BUILD_BROKEN_DUP_SYSPROP as escape hatch for the new sysprop restriction

As the final step for the refactoring of sysprop configuration, this
change adds BUILD_BROKEN_DUP_SYSPROP which is the escape hatch for
the new restriction. When it is turned on, the new syntax `a ?= b`
collapses to the old syntax `a = b`, duplicated assignments are allowed,
and the dups are resolved following the legacy rule of preferring the
first.

This change also summarizes all the user-facing changes to the Change.md
file.

Lastly, post_process_prop.py is refactored to accept new argument
'--allow-dup' which when turned on allowes duplicated sysprops.

Bug: 117892318
Bug: 158735147
Test: atest --host post_process_prop_unittest

Exempt-From-Owner-Approval: cherry-pick from master

Merged-In: I7bdfffd47d50aad66a78e28a30c3dad7ebac080c
(cherry picked from commit b302cdf6a417b9c8eaedee713187735a74707d6a)
Change-Id: I7bdfffd47d50aad66a78e28a30c3dad7ebac080c
diff --git a/tools/post_process_props.py b/tools/post_process_props.py
index 397526f..78a23fb 100755
--- a/tools/post_process_props.py
+++ b/tools/post_process_props.py
@@ -14,6 +14,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import argparse
 import sys
 
 # Usage: post_process_props.py file.prop [disallowed_key, ...]
@@ -69,7 +70,7 @@
 
   return check_pass
 
-def override_optional_props(prop_list):
+def override_optional_props(prop_list, allow_dup=False):
   """Override a?=b with a=c, if the latter exists
 
   Overriding is done by deleting a?=b
@@ -88,6 +89,15 @@
       # duplicated props are allowed when the all have the same value
       if all(overriding_props[0].value == p.value for p in overriding_props):
         continue
+      # or if dup is explicitly allowed for compat reason
+      if allow_dup:
+        # this could left one or more optional props unresolved.
+        # Convert them into non-optional because init doesn't understand ?=
+        # syntax
+        for p in optional_props:
+          p.optional = False
+        continue
+
       success = False
       sys.stderr.write("error: found duplicate sysprop assignments:\n")
       for p in overriding_props:
@@ -198,25 +208,30 @@
         f.write(str(p) + "\n")
 
 def main(argv):
-  filename = argv[1]
+  parser = argparse.ArgumentParser(description="Post-process build.prop file")
+  parser.add_argument("--allow-dup", dest="allow_dup", action="store_true",
+                      default=False)
+  parser.add_argument("filename")
+  parser.add_argument("disallowed_keys", metavar="KEY", type=str, nargs="*")
+  args = parser.parse_args()
 
-  if not filename.endswith("/build.prop"):
+  if not args.filename.endswith("/build.prop"):
     sys.stderr.write("bad command line: " + str(argv) + "\n")
     sys.exit(1)
 
-  props = PropList(filename)
+  props = PropList(args.filename)
   mangle_build_prop(props)
-  if not override_optional_props(props):
+  if not override_optional_props(props, args.allow_dup):
     sys.exit(1)
   if not validate(props):
     sys.exit(1)
 
   # Drop any disallowed keys
-  for key in argv[2:]:
+  for key in args.disallowed_keys:
     for p in props.get_props(key):
       p.delete("%s is a disallowed key" % key)
 
-  props.write(filename)
+  props.write(args.filename)
 
 if __name__ == "__main__":
   main(sys.argv)