Checks for APK sharedUserIds that cross partition group boundaries.
This check is used when merging target files to ensure that a merged
build does not contain any APKs that share UID across builds.
Bug: 171431774
Test: test_common
Test: Use merge_target_files.py to merge two partial builds,
observe no failures for inputs without colliding APKs.
Test: Use merge_target_files.py to merge two partial builds,
observe failure for inputs that have an APK that shares a
UID across input partition groups.
Change-Id: I9dc57216882741ae46a99cfd7847f34702c75582
diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py
index 5e70af1..0683678 100644
--- a/tools/releasetools/common.py
+++ b/tools/releasetools/common.py
@@ -1085,6 +1085,38 @@
return merged_dict
+def SharedUidPartitionViolations(uid_dict, partition_groups):
+ """Checks for APK sharedUserIds that cross partition group boundaries.
+
+ This uses a single or merged build's shareduid_violation_modules.json
+ output file, as generated by find_shareduid_violation.py or
+ core/tasks/find-shareduid-violation.mk.
+
+ An error is defined as a sharedUserId that is found in a set of partitions
+ that span more than one partition group.
+
+ Args:
+ uid_dict: A dictionary created by using the standard json module to read a
+ complete shareduid_violation_modules.json file.
+ partition_groups: A list of groups, where each group is a list of
+ partitions.
+
+ Returns:
+ A list of error messages.
+ """
+ errors = []
+ for uid, partitions in uid_dict.items():
+ found_in_groups = [
+ group for group in partition_groups
+ if set(partitions.keys()) & set(group)
+ ]
+ if len(found_in_groups) > 1:
+ errors.append(
+ "APK sharedUserId \"%s\" found across partition groups in partitions \"%s\""
+ % (uid, ",".join(sorted(partitions.keys()))))
+ return errors
+
+
def AppendAVBSigningArgs(cmd, partition):
"""Append signing arguments for avbtool."""
# e.g., "--key path/to/signing_key --algorithm SHA256_RSA4096"
diff --git a/tools/releasetools/merge_target_files.py b/tools/releasetools/merge_target_files.py
index 0d135d6..ba9e740 100755
--- a/tools/releasetools/merge_target_files.py
+++ b/tools/releasetools/merge_target_files.py
@@ -85,6 +85,7 @@
from __future__ import print_function
import fnmatch
+import json
import logging
import os
import re
@@ -944,20 +945,32 @@
if not check_target_files_vintf.CheckVintf(output_target_files_temp_dir):
raise RuntimeError('Incompatible VINTF metadata')
+ # Generate and check for cross-partition violations of sharedUserId
+ # values in APKs. This requires the input target-files packages to contain
+ # *.apk files.
shareduid_violation_modules = os.path.join(
output_target_files_temp_dir, 'META', 'shareduid_violation_modules.json')
with open(shareduid_violation_modules, 'w') as f:
- partition_map = {
- 'system': 'SYSTEM',
- 'vendor': 'VENDOR',
- 'product': 'PRODUCT',
- 'system_ext': 'SYSTEM_EXT',
- }
+ framework_partitions = item_list_to_partition_set(framework_item_list)
+ vendor_partitions = item_list_to_partition_set(vendor_item_list)
+
+ partition_map = {}
+ for partition in (framework_partitions.union(vendor_partitions)):
+ partition_map[partition.lower()] = partition.upper()
violation = find_shareduid_violation.FindShareduidViolation(
output_target_files_temp_dir, partition_map)
+
+ # Write the output to a file to enable debugging.
f.write(violation)
- # TODO(b/171431774): Add a check to common.py to check if the
- # shared UIDs cross the input build partition boundary.
+
+ # Check for violations across the input builds' partition groups.
+ shareduid_errors = common.SharedUidPartitionViolations(
+ json.loads(violation), [framework_partitions, vendor_partitions])
+ if shareduid_errors:
+ for error in shareduid_errors:
+ logger.error(error)
+ raise ValueError('sharedUserId APK error. See %s' %
+ shareduid_violation_modules)
generate_images(output_target_files_temp_dir, rebuild_recovery)
diff --git a/tools/releasetools/test_common.py b/tools/releasetools/test_common.py
index ee28571..0b368f9 100644
--- a/tools/releasetools/test_common.py
+++ b/tools/releasetools/test_common.py
@@ -15,6 +15,7 @@
#
import copy
+import json
import os
import subprocess
import tempfile
@@ -995,6 +996,34 @@
},
sparse_image.file_map)
+ def test_SharedUidPartitionViolations(self):
+ uid_dict = {
+ 'android.uid.phone': {
+ 'system': ['system_phone.apk'],
+ 'system_ext': ['system_ext_phone.apk'],
+ },
+ 'android.uid.wifi': {
+ 'vendor': ['vendor_wifi.apk'],
+ 'odm': ['odm_wifi.apk'],
+ },
+ }
+ errors = common.SharedUidPartitionViolations(
+ uid_dict, [('system', 'system_ext'), ('vendor', 'odm')])
+ self.assertEqual(errors, [])
+
+ def test_SharedUidPartitionViolations_Violation(self):
+ uid_dict = {
+ 'android.uid.phone': {
+ 'system': ['system_phone.apk'],
+ 'vendor': ['vendor_phone.apk'],
+ },
+ }
+ errors = common.SharedUidPartitionViolations(
+ uid_dict, [('system', 'system_ext'), ('vendor', 'odm')])
+ self.assertIn(
+ ('APK sharedUserId "android.uid.phone" found across partition groups '
+ 'in partitions "system,vendor"'), errors)
+
def test_GetSparseImage_missingImageFile(self):
self.assertRaises(
AssertionError, common.GetSparseImage, 'system2', self.testdata_dir,