diff --git a/vndk/tools/definition-tool/tests/test_tagged_dict.py b/vndk/tools/definition-tool/tests/test_tagged_dict.py index 73df725ae..3b8f5e1fe 100644 --- a/vndk/tools/definition-tool/tests/test_tagged_dict.py +++ b/vndk/tools/definition-tool/tests/test_tagged_dict.py @@ -22,6 +22,8 @@ _TEST_DATA = '''Path,Tag /vendor/lib/lib_sp_hal.so,sp-hal /vendor/lib/lib_sp_hal_dep.so,sp-hal-dep /vendor/lib/lib_vendor_only.so,vendor-only +/product/lib/lib_product_only.so,product-only +/product_services/lib/lib_product_services_only.so,product_services-only /system/lib/lib_remove.so,remove /system/lib/lib_hl_ndk.so,hl-ndk /system/lib/lib_vndk_private.so,vndk-private @@ -58,6 +60,8 @@ class TaggedDictTest(unittest.TestCase): def _check_tag_visibility(self, d, from_tag, visible_tags): + for to_tag in visible_tags: + self.assertTrue(d.is_tag_visible(from_tag, to_tag)) for to_tag in TaggedDict.TAGS: self.assertEqual(d.is_tag_visible(from_tag, to_tag), to_tag in visible_tags) @@ -72,24 +76,30 @@ class TaggedDictTest(unittest.TestCase): self._check_tag_visibility(d, 'll_ndk_private', visible_tags) # VNDK-SP - visible_tags = {'ll_ndk', 'vndk_sp', 'vndk_sp_private', - 'system_only_rs'} + visible_tags = { + 'll_ndk', 'vndk_sp', 'vndk_sp_private', 'system_only_rs', + } self._check_tag_visibility(d, 'vndk_sp', visible_tags) self._check_tag_visibility(d, 'vndk_sp_private', visible_tags) # VNDK - visible_tags = {'ll_ndk', 'vndk_sp', 'vndk_sp_private', - 'vndk', 'vndk_private'} + visible_tags = { + 'll_ndk', 'vndk_sp', 'vndk_sp_private', 'vndk', 'vndk_private', + } self._check_tag_visibility(d, 'vndk', visible_tags) - # SYSTEM-ONLY - visible_tags = {'ll_ndk', 'll_ndk_private', - 'vndk_sp', 'vndk_sp_private', - 'vndk', 'vndk_private', - 'system_only', 'system_only_rs', - 'sp_hal'} + # SYSTEM-ONLY and PRODUCT_SERVICES-ONLY + visible_tags = { + 'll_ndk', 'll_ndk_private', + 'vndk_sp', 'vndk_sp_private', + 'vndk', 'vndk_private', + 'system_only', 'system_only_rs', + 'product_services_only', + 'sp_hal' + } self._check_tag_visibility(d, 'system_only', visible_tags) self._check_tag_visibility(d, 'system_only_rs', visible_tags) + self._check_tag_visibility(d, 'product_services_only', visible_tags) # SP-HAL visible_tags = {'ll_ndk', 'vndk_sp', 'sp_hal', 'sp_hal_dep'} @@ -97,8 +107,17 @@ class TaggedDictTest(unittest.TestCase): self._check_tag_visibility(d, 'sp_hal_dep', visible_tags) # VENDOR-ONLY - visible_tags = {'ll_ndk', 'vndk_sp', 'vndk', 'sp_hal', 'sp_hal_dep', - 'vendor_only'} + visible_tags = { + 'll_ndk', 'vndk_sp', 'vndk', 'sp_hal', 'sp_hal_dep', 'vendor_only', + } + self._check_tag_visibility(d, 'vendor_only', visible_tags) + + # PRODUCT-ONLY + visible_tags = { + 'll_ndk', 'vndk_sp', 'vndk', 'sp_hal', + # Remove the following after VNDK-ext can be checked separately. + 'sp_hal_dep', 'vendor_only', + } self._check_tag_visibility(d, 'vendor_only', visible_tags) # Remove @@ -182,6 +201,9 @@ class TaggedPathDictTest(unittest.TestCase): self.assertIn('/vendor/lib/lib_sp_hal.so', d.sp_hal) self.assertIn('/vendor/lib/lib_sp_hal_dep.so', d.sp_hal_dep) self.assertIn('/vendor/lib/lib_vendor_only.so', d.vendor_only) + self.assertIn('/product_services/lib/lib_product_services_only.so', + d.product_services_only) + self.assertIn('/product/lib/lib_product_only.so', d.product_only) self.assertIn('/system/lib/lib_remove.so', d.remove) # Aliases @@ -339,6 +361,7 @@ class TaggedPathDictTest(unittest.TestCase): '/system/lib/lib_system_only.so', '/system/lib/lib_system_only_rs.so', '/vendor/lib/lib_sp_hal.so', + '/product_services/lib/lib_product_services_only.so', } self._check_path_visibility(d, all_paths, from_paths, visible_paths) diff --git a/vndk/tools/definition-tool/tests/test_vndk_lib_dir.py b/vndk/tools/definition-tool/tests/test_vndk_lib_dir.py index a1a2a8c29..1d73eccbc 100644 --- a/vndk/tools/definition-tool/tests/test_vndk_lib_dir.py +++ b/vndk/tools/definition-tool/tests/test_vndk_lib_dir.py @@ -108,7 +108,7 @@ class VNDKLibDirTest(unittest.TestCase): VNDKLibDir.is_in_vndk_dir('/system/lib/vndk-sp-28/liba.so')) - def test_create_vndk_search_paths(self): + def test_get_vndk_lib_dirs(self): for version in ('current', '28'): for lib_dir in ('lib', 'lib64'): vndk_sp_name = VNDKLibDir.create_vndk_sp_dir_name(version) @@ -124,7 +124,7 @@ class VNDKLibDirTest(unittest.TestCase): ] vndk_sp_dirs, vndk_dirs = \ - VNDKLibDir.create_vndk_search_paths(lib_dir, version) + VNDKLibDir.get_vndk_lib_dirs(lib_dir, version) self.assertEqual(expected_vndk_sp, vndk_sp_dirs) self.assertEqual(expected_vndk, vndk_dirs) diff --git a/vndk/tools/definition-tool/vndk_definition_tool.py b/vndk/tools/definition-tool/vndk_definition_tool.py index 8c11f0d4a..5d1e2ae4c 100755 --- a/vndk/tools/definition-tool/vndk_definition_tool.py +++ b/vndk/tools/definition-tool/vndk_definition_tool.py @@ -1190,6 +1190,16 @@ class DexFileReader(object): return None +#------------------------------------------------------------------------------ +# Path Functions +#------------------------------------------------------------------------------ + +def _is_under_dir(dir_path, path): + dir_path = os.path.abspath(dir_path) + path = os.path.abspath(path) + return path == dir_path or path.startswith(dir_path + os.path.sep) + + #------------------------------------------------------------------------------ # TaggedDict #------------------------------------------------------------------------------ @@ -1203,6 +1213,8 @@ class TaggedDict(object): 'system_only', 'system_only_rs', 'sp_hal', 'sp_hal_dep', 'vendor_only', + 'product_services_only', + 'product_only', 'remove', ] assert len(tag_list) < 32 @@ -1243,17 +1255,38 @@ class TaggedDict(object): return tag - _LL_NDK_VIS = {'ll_ndk', 'll_ndk_private'} + _LL_NDK_VIS = { + 'll_ndk', 'll_ndk_private', + } - _VNDK_SP_VIS = {'ll_ndk', 'vndk_sp', 'vndk_sp_private', 'system_only_rs'} + _VNDK_SP_VIS = { + 'll_ndk', 'vndk_sp', 'vndk_sp_private', 'system_only_rs', + } - _VNDK_VIS = {'ll_ndk', 'vndk_sp', 'vndk_sp_private', 'vndk', 'vndk_private'} + _VNDK_VIS = { + 'll_ndk', 'vndk_sp', 'vndk_sp_private', 'vndk', 'vndk_private', + } - _SYSTEM_ONLY_VIS = {'ll_ndk', 'll_ndk_private', - 'vndk_sp', 'vndk_sp_private', - 'vndk', 'vndk_private', - 'system_only', 'system_only_rs', - 'sp_hal'} + _SYSTEM_ONLY_VIS = { + 'll_ndk', 'll_ndk_private', + 'vndk_sp', 'vndk_sp_private', + 'vndk', 'vndk_private', + 'system_only', 'system_only_rs', + 'product_services_only', + 'sp_hal', + } + + _PRODUCT_ONLY_VIS = { + 'll_ndk', 'vndk_sp', 'vndk', 'sp_hal', + + # Remove the following after VNDK-ext can be checked separately. + 'sp_hal_dep', 'vendor_only', + } + + _VENDOR_ONLY_VIS = { + 'll_ndk', 'vndk_sp', 'vndk', 'sp_hal', 'sp_hal_dep', + 'vendor_only', + } _SP_HAL_VIS = {'ll_ndk', 'vndk_sp', 'sp_hal', 'sp_hal_dep'} @@ -1269,17 +1302,19 @@ class TaggedDict(object): 'system_only': _SYSTEM_ONLY_VIS, 'system_only_rs': _SYSTEM_ONLY_VIS, + 'product_services_only': _SYSTEM_ONLY_VIS, 'sp_hal': _SP_HAL_VIS, 'sp_hal_dep': _SP_HAL_VIS, - 'vendor_only': {'ll_ndk', 'vndk_sp', 'vndk', 'sp_hal', 'sp_hal_dep', - 'vendor_only'}, + 'vendor_only': _VENDOR_ONLY_VIS, + 'product_only': _PRODUCT_ONLY_VIS, 'remove': set(), } - del _LL_NDK_VIS, _VNDK_SP_VIS, _VNDK_VIS, _SYSTEM_ONLY_VIS, _SP_HAL_VIS + del _LL_NDK_VIS, _VNDK_SP_VIS, _VNDK_VIS, _SYSTEM_ONLY_VIS, \ + _PRODUCT_ONLY_VIS, _VENDOR_ONLY_VIS, _SP_HAL_VIS @classmethod @@ -1426,8 +1461,12 @@ class TaggedPathDict(TaggedDict): @staticmethod def get_path_tag_default(path): - if path.startswith('/vendor/'): + if _is_under_dir('/vendor', path): return 'vendor_only' + if _is_under_dir('/product', path): + return 'product_only' + if _is_under_dir('/product_services', path): + return 'product_services_only' return 'system_only' @@ -1459,6 +1498,13 @@ class TaggedLibDict(object): d.add('sp_hal_dep', lib) else: d.add('vendor_only', lib) + + for lib in graph.lib_pt[PT_PRODUCT].values(): + d.add('vendor_only', lib) + + for lib in graph.lib_pt[PT_PRODUCT_SERVICES].values(): + d.add('vendor_only', lib) + return d @@ -1520,6 +1566,28 @@ class LibProperties(object): return root + '-properties' + ext +#------------------------------------------------------------------------------ +# Public Libraries +#------------------------------------------------------------------------------ + +class PublicLibSet(object): + def __init__(self): + self._lib_names = set() + + + def load_from_public_libraries_txt(self, config_path): + with open(config_path, 'r') as config_file: + for line in config_file: + line = line.strip() + if line and not line.startswith('#'): + self._lib_names.add(line) + + + def is_public_lib(self, path): + lib_name = os.path.basename(path) + return lib_name in self._lib_names + + #------------------------------------------------------------------------------ # ELF Linker #------------------------------------------------------------------------------ @@ -1679,7 +1747,9 @@ def scan_elf_files(root, mount_point=None, unzip_files=True): PT_SYSTEM = 0 PT_VENDOR = 1 -NUM_PARTITIONS = 2 +PT_PRODUCT = 2 +PT_PRODUCT_SERVICES = 3 +NUM_PARTITIONS = 4 SPLibResult = collections.namedtuple( @@ -1771,7 +1841,7 @@ class VNDKLibDir(list): @classmethod - def create_vndk_search_paths(cls, lib_dir, version): + def get_vndk_lib_dirs(cls, lib_dir, version): """Create VNDK/VNDK-SP search paths from lib_dir and version.""" vndk_sp_name = cls.create_vndk_sp_dir_name(version) vndk_name = cls.create_vndk_dir_name(version) @@ -2305,7 +2375,7 @@ class ELFLinker(object): def add_executables_in_dir(self, partition_name, partition, root, alter_partition, alter_subdirs, ignored_subdirs, - scan_elf_files, unzip_files): + unzip_files): root = os.path.abspath(root) prefix_len = len(root) + 1 @@ -2407,35 +2477,88 @@ class ELFLinker(object): self._resolve_lib_deps(lib, resolver, generic_refs) - def _get_apex_bionic_search_paths(self, lib_dir): + def _get_apex_bionic_lib_dirs(self, lib_dir): return ['/apex/com.android.runtime/' + lib_dir + '/bionic'] - def _get_apex_search_paths(self, lib_dir): + def _get_apex_lib_dirs(self, lib_dir): return ['/apex/' + name + '/' + lib_dir for name in sorted(self.apex_module_names)] - def _get_system_search_paths(self, lib_dir): - apex_lib_dirs = (self._get_apex_search_paths(lib_dir) + - self._get_apex_bionic_search_paths(lib_dir)) - system_lib_dirs = ['/system/' + lib_dir, '/system/product/' + lib_dir] - vendor_lib_dirs = ['/vendor/' + lib_dir] - return apex_lib_dirs + system_lib_dirs + vendor_lib_dirs + def _get_system_lib_dirs(self, lib_dir): + return ['/system/' + lib_dir] - def _get_vendor_search_paths(self, lib_dir, vndk_sp_dirs, vndk_dirs): - vendor_lib_dirs = [ + def _get_product_services_lib_dirs(self, lib_dir): + return [ + '/product_services/' + lib_dir, + '/system/product_services/' + lib_dir, + ] + + + def _get_vendor_lib_dirs(self, lib_dir): + return [ '/vendor/' + lib_dir + '/hw', '/vendor/' + lib_dir + '/egl', '/vendor/' + lib_dir, ] - # For degenerated VNDK libs. - apex_lib_dirs = (self._get_apex_search_paths(lib_dir) + - self._get_apex_bionic_search_paths(lib_dir)) - system_lib_dirs = ['/system/' + lib_dir] - return (vendor_lib_dirs + vndk_sp_dirs + vndk_dirs + apex_lib_dirs + - system_lib_dirs) + + + def _get_product_lib_dirs(self, lib_dir): + return [ + '/product/' + lib_dir, + '/system/product/' + lib_dir, + ] + + + def _get_system_search_paths(self, lib_dir): + return ( + self._get_apex_bionic_lib_dirs(lib_dir) + + self._get_apex_lib_dirs(lib_dir) + + self._get_product_services_lib_dirs(lib_dir) + + self._get_system_lib_dirs(lib_dir) + + + # Search '/vendor/${LIB}' and '/product/${LIB}' to detect + # violations. + self._get_product_lib_dirs(lib_dir) + + self._get_vendor_lib_dirs(lib_dir) + ) + + + def _get_vendor_search_paths(self, lib_dir, vndk_sp_dirs, vndk_dirs): + return ( + self._get_vendor_lib_dirs(lib_dir) + + vndk_sp_dirs + + vndk_dirs + + + # Search '/apex/*/${LIB}' and '/system/${LIB}' for degenerated VNDK + # and LL-NDK or to detect violations. + self._get_apex_bionic_lib_dirs(lib_dir) + + self._get_apex_lib_dirs(lib_dir) + + self._get_system_lib_dirs(lib_dir) + ) + + + def _get_product_search_paths(self, lib_dir, vndk_sp_dirs, vndk_dirs): + return ( + self._get_product_lib_dirs(lib_dir) + + vndk_sp_dirs + + vndk_dirs + + + # Search '/vendor/${LIB}', '/system/${LIB}', and '/apex/*/${LIB}' + # for degenerated VNDK and LL-NDK or to detect violations. + self._get_vendor_lib_dirs(lib_dir) + + self._get_apex_bionic_lib_dirs(lib_dir) + + self._get_apex_lib_dirs(lib_dir) + + self._get_system_lib_dirs(lib_dir) + ) + + + def _get_product_services_search_paths(self, lib_dir): + # Delegate to _get_system_search_paths() because there is no ABI + # boundary between system and product_services partition. + return self._get_system_search_paths(lib_dir) def _get_vndk_sp_search_paths(self, lib_dir, vndk_sp_dirs): @@ -2444,16 +2567,21 @@ class ELFLinker(object): '/vendor/' + lib_dir, '/system/' + lib_dir, ] - fallback_lib_dirs += self._get_apex_search_paths(lib_dir) - fallback_lib_dirs += self._get_apex_bionic_search_paths(lib_dir) + fallback_lib_dirs += self._get_apex_bionic_lib_dirs(lib_dir) + fallback_lib_dirs += self._get_apex_lib_dirs(lib_dir) + return vndk_sp_dirs + fallback_lib_dirs def _get_vndk_search_paths(self, lib_dir, vndk_sp_dirs, vndk_dirs): # To find missing dependencies or LL-NDK. - fallback_lib_dirs = ['/system/' + lib_dir] - fallback_lib_dirs += self._get_apex_search_paths(lib_dir) - fallback_lib_dirs += self._get_apex_bionic_search_paths(lib_dir) + fallback_lib_dirs = [ + '/vendor/' + lib_dir, + '/system/' + lib_dir, + ] + fallback_lib_dirs += self._get_apex_bionic_lib_dirs(lib_dir) + fallback_lib_dirs += self._get_apex_lib_dirs(lib_dir) + return vndk_sp_dirs + vndk_dirs + fallback_lib_dirs @@ -2478,7 +2606,7 @@ class ELFLinker(object): # Resolve vndk-sp libs for version in vndk_lib_dirs: vndk_sp_dirs, vndk_dirs = \ - vndk_lib_dirs.create_vndk_search_paths(lib_dir, version) + vndk_lib_dirs.get_vndk_lib_dirs(lib_dir, version) vndk_sp_libs = \ system_vndk_sp_libs[version] | vendor_vndk_sp_libs[version] search_paths = self._get_vndk_sp_search_paths( @@ -2489,7 +2617,7 @@ class ELFLinker(object): # Resolve vndk libs for version in vndk_lib_dirs: vndk_sp_dirs, vndk_dirs = \ - vndk_lib_dirs.create_vndk_search_paths(lib_dir, version) + vndk_lib_dirs.get_vndk_lib_dirs(lib_dir, version) vndk_libs = system_vndk_libs[version] | vendor_vndk_libs[version] search_paths = self._get_vndk_search_paths( lib_dir, vndk_sp_dirs, vndk_dirs) @@ -2497,13 +2625,30 @@ class ELFLinker(object): self._resolve_lib_set_deps(vndk_libs, resolver, generic_refs) # Resolve vendor libs. - vndk_sp_dirs, vndk_dirs = vndk_lib_dirs.create_vndk_search_paths( + vndk_sp_dirs, vndk_dirs = vndk_lib_dirs.get_vndk_lib_dirs( lib_dir, self.ro_vndk_version) search_paths = self._get_vendor_search_paths( lib_dir, vndk_sp_dirs, vndk_dirs) resolver = ELFResolver(lib_dict, search_paths) self._resolve_lib_set_deps(vendor_libs, resolver, generic_refs) + # Resolve product libs + product_lib_dict = self.lib_pt[PT_PRODUCT].get_lib_dict(elf_class) + product_libs = set(product_lib_dict.values()) + search_paths = self._get_product_search_paths( + lib_dir, vndk_sp_dirs, vndk_dirs) + resolver = ELFResolver(lib_dict, search_paths) + self._resolve_lib_set_deps(product_libs, resolver, generic_refs) + + # Resolve product_services libs + product_services_lib_dict = \ + self.lib_pt[PT_PRODUCT_SERVICES].get_lib_dict(elf_class) + product_services_libs = set(product_services_lib_dict.values()) + search_paths = self._get_product_services_search_paths(lib_dir) + resolver = ELFResolver(lib_dict, search_paths) + self._resolve_lib_set_deps( + product_services_libs, resolver, generic_refs) + def resolve_deps(self, generic_refs=None): self._resolve_elf_class_deps('lib', ELF.ELFCLASS32, generic_refs) @@ -2911,11 +3056,12 @@ class ELFLinker(object): @staticmethod - def _create_internal(system_dirs, system_dirs_as_vendor, - system_dirs_ignored, vendor_dirs, - vendor_dirs_as_system, vendor_dirs_ignored, - extra_deps, generic_refs, tagged_paths, - vndk_lib_dirs, unzip_files): + def create(system_dirs=None, system_dirs_as_vendor=None, + system_dirs_ignored=None, vendor_dirs=None, + vendor_dirs_as_system=None, vendor_dirs_ignored=None, + product_dirs=None, product_services_dirs=None, + extra_deps=None, generic_refs=None, tagged_paths=None, + vndk_lib_dirs=None, unzip_files=True): if vndk_lib_dirs is None: vndk_lib_dirs = VNDKLibDir.create_from_dirs( system_dirs, vendor_dirs) @@ -2936,6 +3082,18 @@ class ELFLinker(object): vendor_dirs_as_system, vendor_dirs_ignored, unzip_files) + if product_dirs: + for path in product_dirs: + graph.add_executables_in_dir( + 'product', PT_PRODUCT, path, None, None, None, + unzip_files) + + if product_services_dirs: + for path in product_services_dirs: + graph.add_executables_in_dir( + 'product_services', PT_PRODUCT_SERVICES, path, None, + None, None, unzip_files) + if extra_deps: for path in extra_deps: graph.add_dlopen_deps(path) @@ -2946,19 +3104,6 @@ class ELFLinker(object): return graph - @staticmethod - def create(system_dirs=None, system_dirs_as_vendor=None, - system_dirs_ignored=None, vendor_dirs=None, - vendor_dirs_as_system=None, vendor_dirs_ignored=None, - extra_deps=None, generic_refs=None, tagged_paths=None, - vndk_lib_dirs=None, unzip_files=True): - return ELFLinker._create_internal( - system_dirs, system_dirs_as_vendor, - system_dirs_ignored, vendor_dirs, vendor_dirs_as_system, - vendor_dirs_ignored, extra_deps, generic_refs, tagged_paths, - vndk_lib_dirs, unzip_files) - - #------------------------------------------------------------------------------ # Generic Reference #------------------------------------------------------------------------------ @@ -3074,16 +3219,24 @@ def _enumerate_partition_paths(partition, root): yield (android_path, path) -def _enumerate_paths(system_dirs, vendor_dirs): +def _enumerate_paths(system_dirs, vendor_dirs, product_dirs, + product_services_dirs): for root in system_dirs: for ap, path in _enumerate_partition_paths('system', root): yield (ap, path) for root in vendor_dirs: for ap, path in _enumerate_partition_paths('vendor', root): yield (ap, path) + for root in product_dirs: + for ap, path in _enumerate_partition_paths('product', root): + yield (ap, path) + for root in product_services_dirs: + for ap, path in _enumerate_partition_paths('product_services', root): + yield (ap, path) -def scan_apk_dep(graph, system_dirs, vendor_dirs): +def scan_apk_dep(graph, system_dirs, vendor_dirs, product_dirs, + product_services_dirs): libnames = _build_lib_names_dict(graph) results = [] @@ -3094,7 +3247,8 @@ def scan_apk_dep(graph, system_dirs, vendor_dirs): def decode(string): # PY3 return string.decode('mutf-8') - for ap, path in _enumerate_paths(system_dirs, vendor_dirs): + for ap, path in _enumerate_paths(system_dirs, vendor_dirs, + product_dirs, product_services_dirs): # Read the dex file from various file formats try: dex_string_iter = DexFileReader.enumerate_dex_strings(path) @@ -3254,13 +3408,22 @@ class ELFGraphCommand(Command): help='load extra module dependencies') parser.add_argument( - '--system', action='append', + '--system', action='append', default=[], help='path to system partition contents') parser.add_argument( - '--vendor', action='append', + '--vendor', action='append', default=[], help='path to vendor partition contents') + parser.add_argument( + '--product', action='append', default=[], + help='path to product partition contents') + + parser.add_argument( + '--product-services', action='append', default=[], + help='path to product_services partition contents') + + # XXX: BEGIN: Remove these options parser.add_argument( '--system-dir-as-vendor', action='append', help='sub directory of system partition that has vendor files') @@ -3276,6 +3439,7 @@ class ELFGraphCommand(Command): parser.add_argument( '--vendor-dir-ignored', action='append', help='sub directory of vendor partition that must be ignored') + # XXX: END: Remove these options parser.add_argument( '--load-generic-refs', @@ -3322,6 +3486,8 @@ class ELFGraphCommand(Command): def check_dirs_from_args(self, args): self._check_arg_dir_exists('--system', args.system) self._check_arg_dir_exists('--vendor', args.vendor) + self._check_arg_dir_exists('--product', args.product) + self._check_arg_dir_exists('--product-services', args.product_services) def create_from_args(self, args): @@ -3341,6 +3507,8 @@ class ELFGraphCommand(Command): args.system_dir_ignored, args.vendor, args.vendor_dir_as_system, args.vendor_dir_ignored, + args.product, + args.product_services, args.load_extra_deps, generic_refs=generic_refs, tagged_paths=tagged_paths, @@ -3899,7 +4067,8 @@ class ApkDepsCommand(ELFGraphCommand): def main(self, args): _, graph, _, _ = self.create_from_args(args) - apk_deps = scan_apk_dep(graph, args.system, args.vendor) + apk_deps = scan_apk_dep(graph, args.system, args.vendor, args.product, + args.product_services) for apk_path, dep_paths in apk_deps: print(apk_path) @@ -3979,16 +4148,39 @@ class CheckDepCommand(CheckDepCommandBase): help='Do not check ordering of DT_NEEDED entries') + def _load_public_lib_names(self, system_dirs, vendor_dirs): + names = PublicLibSet() + for base in itertools.chain(system_dirs, vendor_dirs): + config_path = os.path.join(base, 'etc', 'public.libraries.txt') + try: + names.load_from_public_libraries_txt(config_path) + except FileNotFoundError: + pass + return names + + def _check_vendor_dep(self, graph, tagged_libs, lib_properties, - module_info): + module_info, public_libs): """Check whether vendor libs are depending on non-eligible libs.""" num_errors = 0 vendor_libs = set(graph.lib_pt[PT_VENDOR].values()) + vendor_libs.update(graph.lib_pt[PT_PRODUCT].values()) eligible_libs = (tagged_libs.ll_ndk | tagged_libs.vndk_sp | tagged_libs.vndk_sp_private | tagged_libs.vndk) + def _is_app_lib(lib): + app_dirs = [ + '/product/app', + '/product/priv-app', + '/product_services/app', + '/product_services/priv-app', + '/vendor/app', + '/vendor/priv-app', + ] + return any(_is_under_dir(d, lib.path) for d in app_dirs) + for lib in sorted(vendor_libs): bad_deps = set() @@ -4006,6 +4198,12 @@ class CheckDepCommand(CheckDepCommandBase): # Check whether vendor modules depend on ineligible libs. for dep in lib.deps_all: if dep not in vendor_libs and dep not in eligible_libs: + if _is_app_lib(lib) and public_libs.is_public_lib(dep.path): + # It is fine for APK files to depend on public + # libraries (including NDK or other explicitly exposed + # libs). + continue + num_errors += 1 bad_deps.add(dep) @@ -4064,7 +4262,8 @@ class CheckDepCommand(CheckDepCommandBase): return num_errors - def _check_apk_dep(self, graph, system_dirs, vendor_dirs, module_info): + def _check_apk_dep(self, graph, system_dirs, vendor_dirs, product_dirs, + product_services_dirs, module_info): num_errors = 0 def is_in_system_partition(path): @@ -4072,7 +4271,8 @@ class CheckDepCommand(CheckDepCommandBase): path.startswith('/product/') or \ path.startswith('/oem/') - apk_deps = scan_apk_dep(graph, system_dirs, vendor_dirs) + apk_deps = scan_apk_dep(graph, system_dirs, vendor_dirs, product_dirs, + product_services_dirs) for apk_path, dep_paths in apk_deps: apk_in_system = is_in_system_partition(apk_path) @@ -4106,15 +4306,18 @@ class CheckDepCommand(CheckDepCommandBase): lib_properties = \ LibProperties.load_from_path_or_default(lib_properties_path) + public_libs = self._load_public_lib_names(args.system, args.vendor) + num_errors = self._check_vendor_dep(graph, tagged_libs, lib_properties, - module_info) + module_info, public_libs) if args.check_dt_needed_ordering: num_errors += self._check_dt_needed_ordering(graph) if args.check_apk: - num_errors += self._check_apk_dep(graph, args.system, args.vendor, - module_info) + num_errors += self._check_apk_dep( + graph, args.system, args.vendor, args.product, + args.product_services, module_info) return 0 if num_errors == 0 else 1