def-tool: Add app-specific search path
This commit adds app-specific search paths for the native libraries in
APK files.
Bug: 120520550
Test: ./tests/run.py
Change-Id: Id547c963c4fb2cf2f29f9eb07a958f1d43e86b65
diff --git a/vndk/tools/definition-tool/tests/test_elf_resolver.py b/vndk/tools/definition-tool/tests/test_elf_resolver.py
index 020ba5c..29973e3 100755
--- a/vndk/tools/definition-tool/tests/test_elf_resolver.py
+++ b/vndk/tools/definition-tool/tests/test_elf_resolver.py
@@ -29,43 +29,69 @@
self.assertEqual(
['/system/lib/libx.so', '/vendor/lib/libx.so'],
- list(r.get_candidates('libx.so')))
+ list(r.get_candidates('/system/lib/libreq.so', 'libx.so')))
self.assertEqual(
['/C/libx.so', '/system/lib/libx.so', '/vendor/lib/libx.so'],
- list(r.get_candidates('libx.so', ['/C'])))
+ list(r.get_candidates('/system/lib/libreq.so', 'libx.so',
+ ['/C'])))
self.assertEqual(
['/C/libx.so', '/D/libx.so', '/system/lib/libx.so',
'/vendor/lib/libx.so'],
- list(r.get_candidates('libx.so', ['/C', '/D'])))
+ list(r.get_candidates('/system/lib/libreq.so', 'libx.so',
+ ['/C', '/D'])))
self.assertEqual(
['/E/libx.so', '/system/lib/libx.so', '/vendor/lib/libx.so'],
- list(r.get_candidates('libx.so', None, ['/E'])))
+ list(r.get_candidates('/system/lib/libreq.so', 'libx.so', None,
+ ['/E'])))
self.assertEqual(
['/E/libx.so', '/F/libx.so', '/system/lib/libx.so',
'/vendor/lib/libx.so'],
- list(r.get_candidates('libx.so', None, ['/E', '/F'])))
+ list(r.get_candidates('/system/lib/libreq.so', 'libx.so', None,
+ ['/E', '/F'])))
self.assertEqual(
['/C/libx.so', '/D/libx.so', '/E/libx.so', '/F/libx.so',
'/system/lib/libx.so', '/vendor/lib/libx.so'],
- list(r.get_candidates('libx.so', ['/C', '/D'], ['/E', '/F'])))
+ list(r.get_candidates('/system/lib/libreq.so', 'libx.so',
+ ['/C', '/D'], ['/E', '/F'])))
+
+ # Test app-specific search paths.
+ self.assertEqual(
+ ['/system/app/example/lib/armeabi-v7a/libx.so',
+ '/C/libx.so', '/D/libx.so', '/E/libx.so', '/F/libx.so',
+ '/system/lib/libx.so', '/vendor/lib/libx.so'],
+ list(r.get_candidates(
+ '/system/app/example/lib/armeabi-v7a/libreq.so',
+ 'libx.so',
+ ['/C', '/D'], ['/E', '/F'])))
def test_resolve(self):
r = self.resolver
- self.assertEqual('a', r.resolve('liba.so'))
- self.assertEqual('c', r.resolve('libc.so'))
+ self.assertEqual('a', r.resolve('/system/lib/libreq.so', 'liba.so'))
+ self.assertEqual('c', r.resolve('/system/lib/libreq.so', 'libc.so'))
- self.assertEqual(None, r.resolve('libe.so'))
- self.assertEqual('e', r.resolve('libe.so', dt_rpath=['/system/lib/hw']))
+ self.assertEqual(None, r.resolve('/system/lib/libreq.so', 'libe.so'))
self.assertEqual(
- 'e', r.resolve('libe.so', dt_runpath=['/system/lib/hw']))
+ 'e',
+ r.resolve('/system/lib/libreq.so', 'libe.so',
+ dt_rpath=['/system/lib/hw']))
+ self.assertEqual(
+ 'e',
+ r.resolve('/system/lib/libreq.so', 'libe.so',
+ dt_runpath=['/system/lib/hw']))
- self.assertEqual('a2', r.resolve('liba.so', dt_rpath=['/vendor/lib']))
- self.assertEqual('a2', r.resolve('liba.so', dt_runpath=['/vendor/lib']))
+ self.assertEqual(
+ 'a2',
+ r.resolve('/system/lib/libreq.so', 'liba.so',
+ dt_rpath=['/vendor/lib']))
+ self.assertEqual(
+ 'a2',
+ r.resolve('/system/lib/libreq.so', 'liba.so',
+ dt_runpath=['/vendor/lib']))
if __name__ == '__main__':
diff --git a/vndk/tools/definition-tool/vndk_definition_tool.py b/vndk/tools/definition-tool/vndk_definition_tool.py
index 13a2310..cd505a1 100755
--- a/vndk/tools/definition-tool/vndk_definition_tool.py
+++ b/vndk/tools/definition-tool/vndk_definition_tool.py
@@ -1646,12 +1646,21 @@
return self.sorted_version(self)[0]
+# File path patterns for Android apps
+_APP_DIR_PATTERNS = re.compile('^(?:/[^/]+){1,2}/(?:priv-)?app/')
+
+
class ELFResolver(object):
def __init__(self, lib_set, default_search_path):
self.lib_set = lib_set
self.default_search_path = default_search_path
- def get_candidates(self, name, dt_rpath=None, dt_runpath=None):
+ def get_candidates(self, requester, name, dt_rpath=None, dt_runpath=None):
+ # Search app-specific search paths.
+ if _APP_DIR_PATTERNS.match(requester):
+ yield os.path.join(os.path.dirname(requester), name)
+
+ # Search default search paths.
if dt_rpath:
for d in dt_rpath:
yield os.path.join(d, name)
@@ -1661,8 +1670,8 @@
for d in self.default_search_path:
yield os.path.join(d, name)
- def resolve(self, name, dt_rpath=None, dt_runpath=None):
- for path in self.get_candidates(name, dt_rpath, dt_runpath):
+ def resolve(self, requester, name, dt_rpath=None, dt_runpath=None):
+ for path in self.get_candidates(requester, name, dt_rpath, dt_runpath):
try:
return self.lib_set[path]
except KeyError:
@@ -2019,11 +2028,11 @@
def _resolve_lib_dt_needed(self, lib, resolver):
imported_libs = []
for dt_needed in lib.elf.dt_needed:
- dep = resolver.resolve(dt_needed, lib.elf.dt_rpath,
+ dep = resolver.resolve(lib.path, dt_needed, lib.elf.dt_rpath,
lib.elf.dt_runpath)
if not dep:
candidates = list(resolver.get_candidates(
- dt_needed, lib.elf.dt_rpath, lib.elf.dt_runpath))
+ lib.path, dt_needed, lib.elf.dt_rpath, lib.elf.dt_runpath))
print('warning: {}: Missing needed library: {} Tried: {}'
.format(lib.path, dt_needed, candidates), file=sys.stderr)
lib.unresolved_dt_needed.append(dt_needed)
@@ -2728,7 +2737,19 @@
libs = set()
for string in strings:
try:
- libs.update(libnames[string])
+ for dep_file in libnames[string]:
+ match = _APP_DIR_PATTERNS.match(dep_file.path)
+
+ # List the lib if it is not embedded in the app.
+ if not match:
+ libs.add(dep_file)
+ continue
+
+ # Only list the embedded lib if it is in the same app.
+ common = os.path.commonprefix([ap, dep_file.path])
+ if len(common) > len(match.group(0)):
+ libs.add(dep_file)
+ continue
except KeyError:
pass