Peel tag and restore flags off settings rows

A dumpsys settings row can end in `tag:` and, on some vendor builds, in
`isValuePreservedInRestore:` or a bare `notPreservedInRestore` token.
The parser only peeled `default:` and `defaultSystemSet:` off the end
of a record, so on a row without a default those tokens stayed inside
the value, and on a row with one they landed in `defaultSystemSet`. A
value of `0 tag:null` is not the safe value `0`, so a setting at its
safe value was reported as dangerous; these are the false positives
measured in #912.

The metadata keys are ordered fields like the rest of the record, so
`_split_fields` reads them now, which also replaces the separate
handling of the default. The bare token has no `key:` shape and is
printed last, so it is stripped first and recorded as
`isValuePreservedInRestore: false`.

The bugreport fixture gains the three row shapes from #912: a restore
flag after `defaultSystemSet:`, and a `tag:` or a bare token directly
after the value. Two of them sit on dangerous settings at their safe
value, so the unchanged alert count of one is the false-positive check.
This commit is contained in:
Donncha Ó Cearbhaill
2026-09-05 15:56:55 +02:00
parent fe505c63a6
commit e5fced2a08
4 changed files with 46 additions and 27 deletions
+19 -1
View File
@@ -25,7 +25,7 @@ class TestSettingsArtifact:
def test_parsing(self):
settings = parse_bugreport_settings()
assert len(settings.results) == 11
assert len(settings.results) == 12
assert {result["namespace"] for result in settings.results} == {
"config",
"global",
@@ -69,6 +69,24 @@ class TestSettingsArtifact:
assert record["value"] == "com.example.dialer,com.example.camera"
assert record["default"] == "com.android.settings,\n com.android.vending"
def test_trailing_metadata_is_not_part_of_the_value(self):
settings = parse_bugreport_settings()
record = find(settings, "lock_screen_show_notifications")[0]
assert record["value"] == "1"
assert record["defaultSystemSet"] == "true"
assert record["isValuePreservedInRestore"] == "true"
# Without a default, the tag or the restore token follows the value.
record = find(settings, "accessibility_enabled")[1]
assert record["value"] == "0"
assert record["tag"] == "null"
assert "default" not in record
record = find(settings, "send_action_app_error")[0]
assert record["value"] == "1"
assert record["isValuePreservedInRestore"] == "false"
def test_repeated_names_are_kept_as_separate_records(self):
settings = parse_bugreport_settings()