Jiyong Park | ae55638 | 2020-05-20 18:33:43 +0900 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
Joe Onorato | 9197a48 | 2011-06-08 16:04:14 -0700 | [diff] [blame] | 2 | # |
| 3 | # Copyright (C) 2009 The Android Open Source Project |
| 4 | # |
| 5 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | # you may not use this file except in compliance with the License. |
| 7 | # You may obtain a copy of the License at |
| 8 | # |
| 9 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | # |
| 11 | # Unless required by applicable law or agreed to in writing, software |
| 12 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | # See the License for the specific language governing permissions and |
| 15 | # limitations under the License. |
| 16 | |
Jiyong Park | 0b4fccb | 2020-06-26 17:38:00 +0900 | [diff] [blame] | 17 | import argparse |
Joe Onorato | 9197a48 | 2011-06-08 16:04:14 -0700 | [diff] [blame] | 18 | import sys |
| 19 | |
Jiakai Zhang | 53dd895 | 2024-01-18 17:22:13 +0000 | [diff] [blame] | 20 | from uffd_gc_utils import should_enable_uffd_gc |
| 21 | |
Jiyong Park | d721e87 | 2020-06-22 17:30:57 +0900 | [diff] [blame] | 22 | # Usage: post_process_props.py file.prop [disallowed_key, ...] |
| 23 | # Disallowed keys are removed from the property file, if present |
Jeff Sharkey | 26d22f7 | 2014-03-18 17:20:10 -0700 | [diff] [blame] | 24 | |
Elliott Hughes | 05c1a2a | 2017-02-28 10:04:23 -0800 | [diff] [blame] | 25 | # See PROP_VALUE_MAX in system_properties.h. |
| 26 | # The constant in system_properties.h includes the terminating NUL, |
| 27 | # so we decrease the value by 1 here. |
Ying Wang | 3512321 | 2014-02-11 20:44:09 -0800 | [diff] [blame] | 28 | PROP_VALUE_MAX = 91 |
| 29 | |
Jiyong Park | ae55638 | 2020-05-20 18:33:43 +0900 | [diff] [blame] | 30 | # Put the modifications that you need to make into the */build.prop into this |
| 31 | # function. |
Jiakai Zhang | 53dd895 | 2024-01-18 17:22:13 +0000 | [diff] [blame] | 32 | def mangle_build_prop(prop_list, kernel_version_file_for_uffd_gc): |
Michael Bestas | 95cbd16 | 2015-02-19 14:29:21 +0200 | [diff] [blame] | 33 | # If ro.adb.secure is 0, then enable adb on USB by default |
| 34 | # (this is for eng builds) |
| 35 | if prop_list.get_value("ro.adb.secure") == "0": |
Jiyong Park | d721e87 | 2020-06-22 17:30:57 +0900 | [diff] [blame] | 36 | val = prop_list.get_value("persist.sys.usb.config") |
Jerry Zhang | 1695653 | 2016-10-18 00:01:27 +0000 | [diff] [blame] | 37 | if "adb" not in val: |
| 38 | if val == "": |
| 39 | val = "adb" |
| 40 | else: |
| 41 | val = val + ",adb" |
Jiyong Park | ae55638 | 2020-05-20 18:33:43 +0900 | [diff] [blame] | 42 | prop_list.put("persist.sys.usb.config", val) |
Jiakai Zhang | 53dd895 | 2024-01-18 17:22:13 +0000 | [diff] [blame] | 43 | if prop_list.get_value("ro.dalvik.vm.enable_uffd_gc") == "default": |
| 44 | assert kernel_version_file_for_uffd_gc != "" |
| 45 | enable_uffd_gc = should_enable_uffd_gc(kernel_version_file_for_uffd_gc) |
| 46 | prop_list.put("ro.dalvik.vm.enable_uffd_gc", |
| 47 | "true" if enable_uffd_gc else "false") |
Justin Yun | 07ceaa7 | 2021-04-02 16:29:06 +0900 | [diff] [blame] | 48 | |
Justin Yun | 23d5243 | 2023-11-10 16:31:04 +0900 | [diff] [blame] | 49 | def validate_grf_props(prop_list): |
Justin Yun | 07ceaa7 | 2021-04-02 16:29:06 +0900 | [diff] [blame] | 50 | """Validate GRF properties if exist. |
| 51 | |
Justin Yun | 23d5243 | 2023-11-10 16:31:04 +0900 | [diff] [blame] | 52 | If ro.board.first_api_level is defined, check if its value is valid. |
Justin Yun | 07ceaa7 | 2021-04-02 16:29:06 +0900 | [diff] [blame] | 53 | |
| 54 | Returns: |
| 55 | True if the GRF properties are valid. |
| 56 | """ |
| 57 | grf_api_level = prop_list.get_value("ro.board.first_api_level") |
| 58 | board_api_level = prop_list.get_value("ro.board.api_level") |
| 59 | |
Justin Yun | 23d5243 | 2023-11-10 16:31:04 +0900 | [diff] [blame] | 60 | if grf_api_level and board_api_level: |
| 61 | grf_api_level = int(grf_api_level) |
Justin Yun | 870ea2e | 2023-04-06 16:28:12 +0900 | [diff] [blame] | 62 | board_api_level = int(board_api_level) |
| 63 | if board_api_level < grf_api_level: |
Justin Yun | 23d5243 | 2023-11-10 16:31:04 +0900 | [diff] [blame] | 64 | sys.stderr.write("error: ro.board.api_level(%d) must not be less than " |
Justin Yun | 870ea2e | 2023-04-06 16:28:12 +0900 | [diff] [blame] | 65 | "ro.board.first_api_level(%d)\n" |
| 66 | % (board_api_level, grf_api_level)) |
| 67 | return False |
| 68 | |
Justin Yun | 07ceaa7 | 2021-04-02 16:29:06 +0900 | [diff] [blame] | 69 | return True |
Joe Onorato | 9197a48 | 2011-06-08 16:04:14 -0700 | [diff] [blame] | 70 | |
Jiyong Park | ae55638 | 2020-05-20 18:33:43 +0900 | [diff] [blame] | 71 | def validate(prop_list): |
Ying Wang | 3512321 | 2014-02-11 20:44:09 -0800 | [diff] [blame] | 72 | """Validate the properties. |
| 73 | |
Jiyong Park | d721e87 | 2020-06-22 17:30:57 +0900 | [diff] [blame] | 74 | If the value of a sysprop exceeds the max limit (91), it's an error, unless |
| 75 | the sysprop is a read-only one. |
| 76 | |
| 77 | Checks if there is no optional prop assignments. |
| 78 | |
Ying Wang | 3512321 | 2014-02-11 20:44:09 -0800 | [diff] [blame] | 79 | Returns: |
| 80 | True if nothing is wrong. |
| 81 | """ |
| 82 | check_pass = True |
Jiyong Park | d721e87 | 2020-06-22 17:30:57 +0900 | [diff] [blame] | 83 | for p in prop_list.get_all_props(): |
Jiyong Park | ae55638 | 2020-05-20 18:33:43 +0900 | [diff] [blame] | 84 | if len(p.value) > PROP_VALUE_MAX and not p.name.startswith("ro."): |
Ying Wang | 38df101 | 2015-02-04 15:10:59 -0800 | [diff] [blame] | 85 | check_pass = False |
| 86 | sys.stderr.write("error: %s cannot exceed %d bytes: " % |
Jiyong Park | ae55638 | 2020-05-20 18:33:43 +0900 | [diff] [blame] | 87 | (p.name, PROP_VALUE_MAX)) |
| 88 | sys.stderr.write("%s (%d)\n" % (p.value, len(p.value))) |
Jiyong Park | d721e87 | 2020-06-22 17:30:57 +0900 | [diff] [blame] | 89 | |
| 90 | if p.is_optional(): |
| 91 | check_pass = False |
| 92 | sys.stderr.write("error: found unresolved optional prop assignment:\n") |
| 93 | sys.stderr.write(str(p) + "\n") |
| 94 | |
Ying Wang | 3512321 | 2014-02-11 20:44:09 -0800 | [diff] [blame] | 95 | return check_pass |
| 96 | |
Jiyong Park | 0b4fccb | 2020-06-26 17:38:00 +0900 | [diff] [blame] | 97 | def override_optional_props(prop_list, allow_dup=False): |
Jiyong Park | d721e87 | 2020-06-22 17:30:57 +0900 | [diff] [blame] | 98 | """Override a?=b with a=c, if the latter exists |
| 99 | |
| 100 | Overriding is done by deleting a?=b |
| 101 | When there are a?=b and a?=c, then only the last one survives |
| 102 | When there are a=b and a=c, then it's an error. |
| 103 | |
| 104 | Returns: |
| 105 | True if the override was successful |
| 106 | """ |
| 107 | success = True |
| 108 | for name in prop_list.get_all_names(): |
| 109 | props = prop_list.get_props(name) |
| 110 | optional_props = [p for p in props if p.is_optional()] |
| 111 | overriding_props = [p for p in props if not p.is_optional()] |
| 112 | if len(overriding_props) > 1: |
| 113 | # duplicated props are allowed when the all have the same value |
| 114 | if all(overriding_props[0].value == p.value for p in overriding_props): |
Jiyong Park | 24d9cad | 2020-06-30 11:41:23 +0900 | [diff] [blame] | 115 | for p in optional_props: |
| 116 | p.delete("overridden by %s" % str(overriding_props[0])) |
Jiyong Park | d721e87 | 2020-06-22 17:30:57 +0900 | [diff] [blame] | 117 | continue |
Jiyong Park | 0b4fccb | 2020-06-26 17:38:00 +0900 | [diff] [blame] | 118 | # or if dup is explicitly allowed for compat reason |
| 119 | if allow_dup: |
| 120 | # this could left one or more optional props unresolved. |
| 121 | # Convert them into non-optional because init doesn't understand ?= |
| 122 | # syntax |
| 123 | for p in optional_props: |
| 124 | p.optional = False |
| 125 | continue |
| 126 | |
Jiyong Park | d721e87 | 2020-06-22 17:30:57 +0900 | [diff] [blame] | 127 | success = False |
| 128 | sys.stderr.write("error: found duplicate sysprop assignments:\n") |
| 129 | for p in overriding_props: |
| 130 | sys.stderr.write("%s\n" % str(p)) |
| 131 | elif len(overriding_props) == 1: |
| 132 | for p in optional_props: |
| 133 | p.delete("overridden by %s" % str(overriding_props[0])) |
| 134 | else: |
| 135 | if len(optional_props) > 1: |
| 136 | for p in optional_props[:-1]: |
| 137 | p.delete("overridden by %s" % str(optional_props[-1])) |
| 138 | # Make the last optional one as non-optional |
| 139 | optional_props[-1].optional = False |
| 140 | |
| 141 | return success |
| 142 | |
Jiyong Park | ae55638 | 2020-05-20 18:33:43 +0900 | [diff] [blame] | 143 | class Prop: |
Yu Liu | 115c66b | 2014-02-10 19:20:36 -0800 | [diff] [blame] | 144 | |
Jiyong Park | d721e87 | 2020-06-22 17:30:57 +0900 | [diff] [blame] | 145 | def __init__(self, name, value, optional=False, comment=None): |
Jiyong Park | ae55638 | 2020-05-20 18:33:43 +0900 | [diff] [blame] | 146 | self.name = name.strip() |
| 147 | self.value = value.strip() |
Jiyong Park | d721e87 | 2020-06-22 17:30:57 +0900 | [diff] [blame] | 148 | if comment != None: |
| 149 | self.comments = [comment] |
| 150 | else: |
| 151 | self.comments = [] |
| 152 | self.optional = optional |
Ying Wang | 3512321 | 2014-02-11 20:44:09 -0800 | [diff] [blame] | 153 | |
Jiyong Park | ae55638 | 2020-05-20 18:33:43 +0900 | [diff] [blame] | 154 | @staticmethod |
| 155 | def from_line(line): |
| 156 | line = line.rstrip('\n') |
| 157 | if line.startswith("#"): |
Jiyong Park | d721e87 | 2020-06-22 17:30:57 +0900 | [diff] [blame] | 158 | return Prop("", "", comment=line) |
| 159 | elif "?=" in line: |
| 160 | name, value = line.split("?=", 1) |
| 161 | return Prop(name, value, optional=True) |
Jiyong Park | ae55638 | 2020-05-20 18:33:43 +0900 | [diff] [blame] | 162 | elif "=" in line: |
| 163 | name, value = line.split("=", 1) |
Jiyong Park | d721e87 | 2020-06-22 17:30:57 +0900 | [diff] [blame] | 164 | return Prop(name, value, optional=False) |
Jiyong Park | ae55638 | 2020-05-20 18:33:43 +0900 | [diff] [blame] | 165 | else: |
| 166 | # don't fail on invalid line |
| 167 | # TODO(jiyong) make this a hard error |
Jiyong Park | d721e87 | 2020-06-22 17:30:57 +0900 | [diff] [blame] | 168 | return Prop("", "", comment=line) |
Jiyong Park | ae55638 | 2020-05-20 18:33:43 +0900 | [diff] [blame] | 169 | |
| 170 | def is_comment(self): |
Jiyong Park | d721e87 | 2020-06-22 17:30:57 +0900 | [diff] [blame] | 171 | return bool(self.comments and not self.name) |
| 172 | |
| 173 | def is_optional(self): |
| 174 | return (not self.is_comment()) and self.optional |
| 175 | |
| 176 | def make_as_comment(self): |
| 177 | # Prepend "#" to the last line which is the prop assignment |
| 178 | if not self.is_comment(): |
| 179 | assignment = str(self).rsplit("\n", 1)[-1] |
| 180 | self.comments.append("#" + assignment) |
| 181 | self.name = "" |
| 182 | self.value = "" |
| 183 | |
| 184 | def delete(self, reason): |
| 185 | self.comments.append("# Removed by post_process_props.py because " + reason) |
| 186 | self.make_as_comment() |
Jiyong Park | ae55638 | 2020-05-20 18:33:43 +0900 | [diff] [blame] | 187 | |
| 188 | def __str__(self): |
Jiyong Park | d721e87 | 2020-06-22 17:30:57 +0900 | [diff] [blame] | 189 | assignment = [] |
| 190 | if not self.is_comment(): |
| 191 | operator = "?=" if self.is_optional() else "=" |
| 192 | assignment.append(self.name + operator + self.value) |
| 193 | return "\n".join(self.comments + assignment) |
Jiyong Park | ae55638 | 2020-05-20 18:33:43 +0900 | [diff] [blame] | 194 | |
| 195 | class PropList: |
| 196 | |
| 197 | def __init__(self, filename): |
| 198 | with open(filename) as f: |
| 199 | self.props = [Prop.from_line(l) |
| 200 | for l in f.readlines() if l.strip() != ""] |
| 201 | |
Jiyong Park | d721e87 | 2020-06-22 17:30:57 +0900 | [diff] [blame] | 202 | def get_all_props(self): |
Jiyong Park | ae55638 | 2020-05-20 18:33:43 +0900 | [diff] [blame] | 203 | return [p for p in self.props if not p.is_comment()] |
Joe Onorato | 9197a48 | 2011-06-08 16:04:14 -0700 | [diff] [blame] | 204 | |
Jiyong Park | d721e87 | 2020-06-22 17:30:57 +0900 | [diff] [blame] | 205 | def get_all_names(self): |
| 206 | return set([p.name for p in self.get_all_props()]) |
| 207 | |
| 208 | def get_props(self, name): |
| 209 | return [p for p in self.get_all_props() if p.name == name] |
| 210 | |
| 211 | def get_value(self, name): |
| 212 | # Caution: only the value of the first sysprop having the name is returned. |
Jiyong Park | ae55638 | 2020-05-20 18:33:43 +0900 | [diff] [blame] | 213 | return next((p.value for p in self.props if p.name == name), "") |
Joe Onorato | 9197a48 | 2011-06-08 16:04:14 -0700 | [diff] [blame] | 214 | |
| 215 | def put(self, name, value): |
Jiyong Park | d721e87 | 2020-06-22 17:30:57 +0900 | [diff] [blame] | 216 | # Note: when there is an optional prop for the name, its value isn't changed. |
| 217 | # Instead a new non-optional prop is appended, which will override the |
| 218 | # optional prop. Otherwise, the new value might be overridden by an existing |
| 219 | # non-optional prop of the same name. |
| 220 | index = next((i for i,p in enumerate(self.props) |
| 221 | if p.name == name and not p.is_optional()), -1) |
Jiyong Park | ae55638 | 2020-05-20 18:33:43 +0900 | [diff] [blame] | 222 | if index == -1: |
Jiyong Park | d721e87 | 2020-06-22 17:30:57 +0900 | [diff] [blame] | 223 | self.props.append(Prop(name, value, |
| 224 | comment="# Auto-added by post_process_props.py")) |
Jiyong Park | ae55638 | 2020-05-20 18:33:43 +0900 | [diff] [blame] | 225 | else: |
Jiyong Park | d721e87 | 2020-06-22 17:30:57 +0900 | [diff] [blame] | 226 | self.props[index].comments.append( |
| 227 | "# Value overridden by post_process_props.py. Original value: %s" % |
| 228 | self.props[index].value) |
Jiyong Park | ae55638 | 2020-05-20 18:33:43 +0900 | [diff] [blame] | 229 | self.props[index].value = value |
Joe Onorato | 9197a48 | 2011-06-08 16:04:14 -0700 | [diff] [blame] | 230 | |
Jiyong Park | ae55638 | 2020-05-20 18:33:43 +0900 | [diff] [blame] | 231 | def write(self, filename): |
| 232 | with open(filename, 'w+') as f: |
| 233 | for p in self.props: |
| 234 | f.write(str(p) + "\n") |
Joe Onorato | 9197a48 | 2011-06-08 16:04:14 -0700 | [diff] [blame] | 235 | |
| 236 | def main(argv): |
Jiyong Park | 0b4fccb | 2020-06-26 17:38:00 +0900 | [diff] [blame] | 237 | parser = argparse.ArgumentParser(description="Post-process build.prop file") |
| 238 | parser.add_argument("--allow-dup", dest="allow_dup", action="store_true", |
| 239 | default=False) |
| 240 | parser.add_argument("filename") |
| 241 | parser.add_argument("disallowed_keys", metavar="KEY", type=str, nargs="*") |
Justin Yun | 07ceaa7 | 2021-04-02 16:29:06 +0900 | [diff] [blame] | 242 | parser.add_argument("--sdk-version", type=int, required=True) |
Jiakai Zhang | 53dd895 | 2024-01-18 17:22:13 +0000 | [diff] [blame] | 243 | parser.add_argument("--kernel-version-file-for-uffd-gc", required=True) |
Jiyong Park | 0b4fccb | 2020-06-26 17:38:00 +0900 | [diff] [blame] | 244 | args = parser.parse_args() |
Joe Onorato | 9197a48 | 2011-06-08 16:04:14 -0700 | [diff] [blame] | 245 | |
Jiyong Park | 0b4fccb | 2020-06-26 17:38:00 +0900 | [diff] [blame] | 246 | if not args.filename.endswith("/build.prop"): |
Joe Onorato | 9197a48 | 2011-06-08 16:04:14 -0700 | [diff] [blame] | 247 | sys.stderr.write("bad command line: " + str(argv) + "\n") |
| 248 | sys.exit(1) |
| 249 | |
Jiyong Park | 0b4fccb | 2020-06-26 17:38:00 +0900 | [diff] [blame] | 250 | props = PropList(args.filename) |
Jiakai Zhang | 53dd895 | 2024-01-18 17:22:13 +0000 | [diff] [blame] | 251 | mangle_build_prop(props, args.kernel_version_file_for_uffd_gc) |
Jiyong Park | 0b4fccb | 2020-06-26 17:38:00 +0900 | [diff] [blame] | 252 | if not override_optional_props(props, args.allow_dup): |
Jiyong Park | d721e87 | 2020-06-22 17:30:57 +0900 | [diff] [blame] | 253 | sys.exit(1) |
Justin Yun | 23d5243 | 2023-11-10 16:31:04 +0900 | [diff] [blame] | 254 | if not validate_grf_props(props): |
Justin Yun | 07ceaa7 | 2021-04-02 16:29:06 +0900 | [diff] [blame] | 255 | sys.exit(1) |
Jiyong Park | ae55638 | 2020-05-20 18:33:43 +0900 | [diff] [blame] | 256 | if not validate(props): |
Ying Wang | 3512321 | 2014-02-11 20:44:09 -0800 | [diff] [blame] | 257 | sys.exit(1) |
| 258 | |
Jiyong Park | d721e87 | 2020-06-22 17:30:57 +0900 | [diff] [blame] | 259 | # Drop any disallowed keys |
Jiyong Park | 0b4fccb | 2020-06-26 17:38:00 +0900 | [diff] [blame] | 260 | for key in args.disallowed_keys: |
Jiyong Park | d721e87 | 2020-06-22 17:30:57 +0900 | [diff] [blame] | 261 | for p in props.get_props(key): |
| 262 | p.delete("%s is a disallowed key" % key) |
Jeff Sharkey | 26d22f7 | 2014-03-18 17:20:10 -0700 | [diff] [blame] | 263 | |
Jiyong Park | 0b4fccb | 2020-06-26 17:38:00 +0900 | [diff] [blame] | 264 | props.write(args.filename) |
Joe Onorato | 9197a48 | 2011-06-08 16:04:14 -0700 | [diff] [blame] | 265 | |
| 266 | if __name__ == "__main__": |
| 267 | main(sys.argv) |