vndk-def: check-dep: Print symbols and module_path

This commit add the functionality to print depended symbols from
ineligible libs and violating module source path to check-dep
subcommand.

Test: ./tests/run.py

Test: Run `vndk_definition_tool.py deps --symbols` on various tree and
the output should remain identical.

Test: Run `vndk_definition_tool.py check-dep --module-info ...`

Bug: 32811412

Change-Id: Ie9fa31da4ac18425604e27e0377c7da2b88bd4eb
This commit is contained in:
Logan Chien
2017-04-14 17:55:49 +08:00
parent 59ac433af9
commit 68121b4f37
4 changed files with 122 additions and 21 deletions

View File

@@ -83,6 +83,22 @@ class ELFLinkDataTest(unittest.TestCase):
self.assertTrue(self.x.is_system_lib())
self.assertFalse(self.v.is_system_lib())
def test_get_dep_linked_symbols(self):
self.x.linked_symbols['c'] = self.y
self.x.linked_symbols['b'] = self.y
self.x.linked_symbols['a'] = self.y
self.x.linked_symbols['w'] = self.z
self.x.linked_symbols['z'] = self.z
self.x.linked_symbols['y'] = self.z
self.x.linked_symbols['x'] = self.z
self.assertEqual(['a', 'b', 'c'],
self.x.get_dep_linked_symbols(self.y))
self.assertEqual(['w', 'x', 'y', 'z'],
self.x.get_dep_linked_symbols(self.z))
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1,39 @@
#!/usr/bin/env python3
from __future__ import print_function
import os
import sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import unittest
from vndk_definition_tool import ModuleInfo
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
class ModuleInfoTest(unittest.TestCase):
def test_default(self):
m = ModuleInfo()
self.assertEqual([], m.get_module_path('/system/lib64/libA.so'))
def test_get_module_path(self):
m = ModuleInfo(os.path.join(SCRIPT_DIR, 'testdata', 'test_module_info',
'module-info.json'))
self.assertEqual(['system/core/libA'],
m.get_module_path('/system/lib64/libA.so'))
self.assertEqual(['frameworks/base/libB'],
m.get_module_path('/system/lib64/libB.so'))
self.assertEqual(['frameworks/base/libC'],
m.get_module_path('/system/lib64/libC.so'))
self.assertEqual(['frameworks/base/libC'],
m.get_module_path('/system/lib64/hw/libC.so'))
self.assertEqual(
[], m.get_module_path('/system/lib64/libdoes_not_exist.so'))
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1,5 @@
{
"libA": { "path": ["system/core/libA"], "installed": ["out/target/product/generic_arm64/system/lib64/libA.so"] },
"libB": { "path": ["frameworks/base/libB"], "installed": ["out/target/product/generic_arm64/system/lib64/libB.so"] },
"libC": { "path": ["frameworks/base/libC"], "installed": ["out/target/product/generic_arm64/system/lib64/libC.so", "out/target/product/generic_arm64/system/lib64/hw/libC.so"] }
}

View File

@@ -792,6 +792,13 @@ class ELFLinkData(object):
def is_system_lib(self):
return self.partition == PT_SYSTEM
def get_dep_linked_symbols(self, dep):
symbols = set()
for symbol, exp_lib in self.linked_symbols.items():
if exp_lib == dep:
symbols.add(symbol)
return sorted(symbols)
def sorted_lib_path_list(libs):
libs = [lib.path for lib in libs]
@@ -2102,16 +2109,12 @@ class DepsCommand(ELFGraphCommand):
results = []
for partition in range(NUM_PARTITIONS):
for name, lib in graph.lib_pt[partition].items():
if not args.symbols:
if args.symbols:
def collect_symbols(user, definer):
return ()
return user.get_dep_linked_symbols(definer)
else:
def collect_symbols(user, definer):
symbols = set()
for symbol, exp_lib in user.linked_symbols.items():
if exp_lib == definer:
symbols.add(symbol)
return sorted(symbols)
return ()
data = []
if args.revert:
@@ -2186,6 +2189,21 @@ TAGGED_LIB_DICT_FIELDS = ('ll_ndk', 'sp_ndk', 'sp_ndk_indirect', 'hl_ndk',
TaggedLibDict = collections.namedtuple('TaggedLibDict', TAGGED_LIB_DICT_FIELDS)
class ModuleInfo(object):
def __init__(self, module_info_path=None):
if not module_info_path:
self.json = dict()
else:
with open(module_info_path, 'r') as f:
self.json = json.load(f)
def get_module_path(self, installed_path):
for name, module in self.json.items():
if any(path.endswith(installed_path)
for path in module['installed']):
return module['path']
return []
class CheckDepCommand(ELFGraphCommand):
def __init__(self):
super(CheckDepCommand, self).__init__(
@@ -2196,6 +2214,8 @@ class CheckDepCommand(ELFGraphCommand):
parser.add_argument('--tag-file', required=True)
parser.add_argument('--module-info')
def _load_tag_file(self, tag_file_path):
res = TaggedLibDict(set(), set(), set(), set(), set(), set(), set(),
set())
@@ -2230,7 +2250,17 @@ class CheckDepCommand(ELFGraphCommand):
res[i].add(lib)
return res
def _check_eligible_vndk_dep(self, graph, tagged_libs):
@staticmethod
def _dump_dep(lib, bad_deps, module_info):
print(lib.path)
for module_path in module_info.get_module_path(lib.path):
print('\tMODULE_PATH:', module_path)
for dep in bad_deps:
print('\t' + dep.path)
for symbol in lib.get_dep_linked_symbols(dep):
print('\t\t' + symbol)
def _check_eligible_vndk_dep(self, graph, tagged_libs, module_info):
"""Check whether eligible sets are self-contained."""
num_errors = 0
@@ -2242,27 +2272,32 @@ class CheckDepCommand(ELFGraphCommand):
# Check eligible vndk is self-contained.
for lib in eligible_libs:
bad_deps = []
for dep in lib.deps:
if dep not in eligible_libs and dep not in indirect_libs:
print('error: eligible-lib: {}: eligible lib "{}" should '
'not depend on non-eligible lib "{}".'
.format(lib.path, lib.path, dep.path),
print('error: eligible lib "{}" should not depend on '
'non-eligible lib "{}".'.format(lib.path, dep.path),
file=sys.stderr)
bad_deps.append(dep)
num_errors += 1
if bad_deps:
self._dump_dep(lib, bad_deps, module_info)
# Check the libbinder dependencies.
for lib in eligible_libs:
bad_deps = []
for dep in lib.deps:
if os.path.basename(dep.path) == 'libbinder.so':
print('error: eligible-lib: {}: eligible lib "{}" should '
'not depend on libbinder.so.'
.format(lib.path, lib.path),
file=sys.stderr)
print('error: eligible lib "{}" should not depend on '
'libbinder.so.'.format(lib.path), file=sys.stderr)
bad_deps.append(dep)
num_errors += 1
if bad_deps:
self._dump_dep(lib, bad_deps, module_info)
return num_errors
def _check_vendor_dep(self, graph, tagged_libs):
def _check_vendor_dep(self, graph, tagged_libs, module_info):
"""Check whether vendor libs are depending on non-eligible libs."""
num_errors = 0
@@ -2273,13 +2308,16 @@ class CheckDepCommand(ELFGraphCommand):
tagged_libs.vndk | tagged_libs.vndk_indirect)
for lib in vendor_libs:
bad_deps = []
for dep in lib.deps:
if dep not in vendor_libs and dep not in eligible_libs:
print('error: vendor-lib: {}: vendor lib "{}" depends on '
'non-eligible lib "{}".'
.format(lib.path, lib.path, dep.path),
print('error: vendor lib "{}" depends on non-eligible '
'lib "{}".'.format(lib.path, dep.path),
file=sys.stderr)
bad_deps.append(dep)
num_errors += 1
if bad_deps:
self._dump_dep(lib, bad_deps, module_info)
return num_errors
@@ -2291,8 +2329,11 @@ class CheckDepCommand(ELFGraphCommand):
tags = self._load_tag_file(args.tag_file)
tagged_libs = self._get_tagged_libs(graph, tags)
num_errors = self._check_eligible_vndk_dep(graph, tagged_libs)
num_errors += self._check_vendor_dep(graph, tagged_libs)
module_info = ModuleInfo(args.module_info)
num_errors = self._check_eligible_vndk_dep(graph, tagged_libs,
module_info)
num_errors += self._check_vendor_dep(graph, tagged_libs, module_info)
return 0 if num_errors == 0 else 1