Merge "vndk-def: Support same-process HAL discovery."
diff --git a/vndk/tools/definition-tool/README.md b/vndk/tools/definition-tool/README.md
index df6317a..4c6afa8 100644
--- a/vndk/tools/definition-tool/README.md
+++ b/vndk/tools/definition-tool/README.md
@@ -148,6 +148,23 @@
--vendor ${ANDROID_PRODUCT_OUT}/vendor
+## Same-Process HAL
+
+VNDK Definition Tool supports the same-process HAL definition as well. To find
+same-process HALs, run `sp-hal` subcommand:
+
+ $ python3 vndk_definition_tool.py sp-hal \
+ --system ${ANDROID_PRODUCT_OUT}/system \
+ --vendor ${ANDROID_PRODUCT_OUT}/vendor
+
+To find the dependencies of same-process HALs, add `--closure` option:
+
+ $ python3 vndk_definition_tool.py sp-hal \
+ --system ${ANDROID_PRODUCT_OUT}/system \
+ --vendor ${ANDROID_PRODUCT_OUT}/vendor
+ --closure
+
+
## Python 2 Support
Since `vndk_definition_tool.py` runs 3x faster with Python 3, the shebang is
diff --git a/vndk/tools/definition-tool/vndk_definition_tool.py b/vndk/tools/definition-tool/vndk_definition_tool.py
index cde3895..9e8e851 100755
--- a/vndk/tools/definition-tool/vndk_definition_tool.py
+++ b/vndk/tools/definition-tool/vndk_definition_tool.py
@@ -460,6 +460,23 @@
if src and dst:
src.add_dep(dst)
+ def map_path_to_lib(self, path):
+ for lib_set in (self.lib32, self.lib64):
+ lib = lib_set.get(path)
+ if lib:
+ return lib
+ return None
+
+ def map_paths_to_libs(self, paths, report_error):
+ result = set()
+ for path in paths:
+ lib = self.map_path_to_lib(path)
+ if not lib:
+ report_error(path)
+ continue
+ result.add(lib)
+ return result
+
@staticmethod
def _compile_path_matcher(root, subdirs):
dirs = [os.path.normpath(os.path.join(root, i)) for i in subdirs]
@@ -538,31 +555,25 @@
vndk_ext, self.lib_pt[PT_VENDOR], PT_SYSTEM)
# Remove NDK libraries and banned libraries.
- def must_not_be_vndk(lib):
+ def is_not_vndk(lib):
return lib.is_ndk or banned_libs.get(os.path.basename(lib.path))
def remove_ndk_libs(libs):
- return set(lib for lib in libs if not must_not_be_vndk(lib))
+ return set(lib for lib in libs if not is_not_vndk(lib))
vndk_core = remove_ndk_libs(vndk_core)
vndk_ext = remove_ndk_libs(vndk_ext)
# Compute transitive closure.
- def get_transitive_closure(root, boundary):
- closure = set(root)
- stack = list(root)
- while stack:
- lib = stack.pop()
- for dep in lib.deps:
- if must_not_be_vndk(dep):
- continue
- if dep not in closure and dep not in boundary:
- closure.add(dep)
- stack.append(dep)
- return closure
+ def is_not_vndk_indirect(lib):
+ return is_not_vndk(lib) or lib in vndk_ext
- vndk_indirect = get_transitive_closure(vndk_core, vndk_ext) - vndk_core
- vndk_ext = get_transitive_closure(vndk_ext, vndk_core)
+ def is_not_vndk_ext(lib):
+ return is_not_vndk(lib) or lib in vndk_core
+
+ vndk_indirect = self.compute_closure(vndk_core, is_not_vndk_indirect)
+ vndk_indirect -= vndk_core
+ vndk_ext = self.compute_closure(vndk_ext, is_not_vndk_ext)
# Move extended libraries from vndk_core to vndk_ext.
if generic_refs:
@@ -584,7 +595,7 @@
vndk_ext.add(lib)
for dep in lib.deps:
# Skip NDK or banned libraries.
- if must_not_be_vndk(dep):
+ if is_not_vndk(dep):
continue
# Skip vndk_ext and possibly vndk_core.
if dep in vndk_ext or dep in stacked:
@@ -598,6 +609,20 @@
return (vndk_core, vndk_indirect, vndk_ext)
@staticmethod
+ def compute_closure(root_set, is_excluded):
+ closure = set(root_set)
+ stack = list(root_set)
+ while stack:
+ lib = stack.pop()
+ for dep in lib.deps:
+ if is_excluded(dep):
+ continue
+ if dep not in closure:
+ closure.add(dep)
+ stack.append(dep)
+ return closure
+
+ @staticmethod
def create(system_dirs=None, system_dirs_as_vendor=None, vendor_dirs=None,
vendor_dirs_as_system=None, extra_deps=None):
graph = Graph()
@@ -883,6 +908,97 @@
print('\t' + dep)
return 0
+
+class DepsClosureCommand(ELFGraphCommand):
+ def __init__(self):
+ super(DepsClosureCommand, self).__init__(
+ 'deps-closure', help='Find transitive closure of dependencies')
+
+ def add_argparser_options(self, parser):
+ super(DepsClosureCommand, self).add_argparser_options(parser)
+
+ parser.add_argument('lib', nargs='+',
+ help='root set of the shared libraries')
+
+ parser.add_argument('--exclude-lib', action='append', default=[],
+ help='libraries to be excluded')
+
+ parser.add_argument('--exclude-ndk', action='store_true',
+ help='exclude ndk libraries')
+
+ def main(self, args):
+ graph = Graph.create(args.system, args.system_dir_as_vendor,
+ args.vendor, args.vendor_dir_as_system,
+ args.load_extra_deps)
+
+ # Find root/excluded libraries by their paths.
+ def report_error(path):
+ print('error: no such lib: {}'.format(path), file=sys.stderr)
+ root_libs = graph.map_paths_to_libs(args.lib, report_error)
+ excluded_libs = graph.map_paths_to_libs(args.exclude_lib, report_error)
+
+ # Compute and print the closure.
+ if args.exclude_ndk:
+ def is_excluded_libs(lib):
+ return lib.is_ndk or lib in excluded_libs
+ else:
+ def is_excluded_libs(lib):
+ return lib in excluded_libs
+
+ closure = graph.compute_closure(root_libs, is_excluded_libs)
+ for lib in sorted_lib_path_list(closure):
+ print(lib)
+ return 0
+
+
+class SpHalCommand(ELFGraphCommand):
+ def __init__(self):
+ super(SpHalCommand, self).__init__(
+ 'sp-hal', help='Find transitive closure of same-process HALs')
+
+ def add_argparser_options(self, parser):
+ super(SpHalCommand, self).add_argparser_options(parser)
+
+ parser.add_argument('--closure', action='store_true',
+ help='show the closure')
+
+ def main(self, args):
+ graph = Graph.create(args.system, args.system_dir_as_vendor,
+ args.vendor, args.vendor_dir_as_system,
+ args.load_extra_deps)
+
+ # Find SP HALs.
+ name_patterns = (
+ '^/vendor/.*/libEGL_.*\\.so$',
+ '^/vendor/.*/libGLESv1_CM_.*\\.so$',
+ '^/vendor/.*/libGLESv2_.*\\.so$',
+ '^/vendor/.*/libGLESv3_.*\\.so$',
+ '^/vendor/.*/vulkan.*\\.so$',
+ '^/vendor/.*/libRSDriver.*\\.so$',
+ '^/vendor/.*/libPVRRS\\.so$', # libRSDriver
+ '^/vendor/.*/gralloc-mapper@\\d+.\\d+-impl\\.so$',
+ )
+
+ patt = re.compile('|'.join('(?:' + p + ')' for p in name_patterns))
+
+ # Find root/excluded libraries by their paths.
+ sp_hals = set()
+ for lib in graph.lib_pt[PT_VENDOR].values():
+ if patt.match(lib.path):
+ sp_hals.add(lib)
+
+ # Compute the closure (if specified).
+ if args.closure:
+ def is_excluded_libs(lib):
+ return lib.is_ndk
+ sp_hals = graph.compute_closure(sp_hals, is_excluded_libs)
+
+ # Print the result.
+ for lib in sorted_lib_path_list(sp_hals):
+ print(lib)
+ return 0
+
+
def main():
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='subcmd')
@@ -897,6 +1013,8 @@
register_subcmd(CreateGenericRefCommand())
register_subcmd(VNDKCommand())
register_subcmd(DepsCommand())
+ register_subcmd(DepsClosureCommand())
+ register_subcmd(SpHalCommand())
args = parser.parse_args()
if not args.subcmd: