1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/media/webrtc/trunk/build/android/pylib/apk_info.py Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,142 @@ 1.4 +# Copyright (c) 2012 The Chromium Authors. All rights reserved. 1.5 +# Use of this source code is governed by a BSD-style license that can be 1.6 +# found in the LICENSE file. 1.7 + 1.8 +"""Gathers information about APKs.""" 1.9 + 1.10 +import collections 1.11 +import os 1.12 +import re 1.13 + 1.14 +import cmd_helper 1.15 + 1.16 + 1.17 +class ApkInfo(object): 1.18 + """Helper class for inspecting APKs.""" 1.19 + _PROGUARD_PATH = os.path.join(os.environ['ANDROID_SDK_ROOT'], 1.20 + 'tools/proguard/bin/proguard.sh') 1.21 + if not os.path.exists(_PROGUARD_PATH): 1.22 + _PROGUARD_PATH = os.path.join(os.environ['ANDROID_BUILD_TOP'], 1.23 + 'external/proguard/bin/proguard.sh') 1.24 + _PROGUARD_CLASS_RE = re.compile(r'\s*?- Program class:\s*([\S]+)$') 1.25 + _PROGUARD_METHOD_RE = re.compile(r'\s*?- Method:\s*(\S*)[(].*$') 1.26 + _PROGUARD_ANNOTATION_RE = re.compile(r'\s*?- Annotation \[L(\S*);\]:$') 1.27 + _PROGUARD_ANNOTATION_CONST_RE = re.compile(r'\s*?- Constant element value.*$') 1.28 + _PROGUARD_ANNOTATION_VALUE_RE = re.compile(r'\s*?- \S+? \[(.*)\]$') 1.29 + _AAPT_PACKAGE_NAME_RE = re.compile(r'package: .*name=\'(\S*)\'') 1.30 + 1.31 + def __init__(self, apk_path, jar_path): 1.32 + if not os.path.exists(apk_path): 1.33 + raise Exception('%s not found, please build it' % apk_path) 1.34 + self._apk_path = apk_path 1.35 + if not os.path.exists(jar_path): 1.36 + raise Exception('%s not found, please build it' % jar_path) 1.37 + self._jar_path = jar_path 1.38 + self._annotation_map = collections.defaultdict(list) 1.39 + self._test_methods = [] 1.40 + self._Initialize() 1.41 + 1.42 + def _Initialize(self): 1.43 + proguard_output = cmd_helper.GetCmdOutput([self._PROGUARD_PATH, 1.44 + '-injars', self._jar_path, 1.45 + '-dontshrink', 1.46 + '-dontoptimize', 1.47 + '-dontobfuscate', 1.48 + '-dontpreverify', 1.49 + '-dump', 1.50 + ]).split('\n') 1.51 + clazz = None 1.52 + method = None 1.53 + annotation = None 1.54 + has_value = False 1.55 + qualified_method = None 1.56 + for line in proguard_output: 1.57 + m = self._PROGUARD_CLASS_RE.match(line) 1.58 + if m: 1.59 + clazz = m.group(1).replace('/', '.') # Change package delim. 1.60 + annotation = None 1.61 + continue 1.62 + m = self._PROGUARD_METHOD_RE.match(line) 1.63 + if m: 1.64 + method = m.group(1) 1.65 + annotation = None 1.66 + qualified_method = clazz + '#' + method 1.67 + if method.startswith('test') and clazz.endswith('Test'): 1.68 + self._test_methods += [qualified_method] 1.69 + continue 1.70 + m = self._PROGUARD_ANNOTATION_RE.match(line) 1.71 + if m: 1.72 + assert qualified_method 1.73 + annotation = m.group(1).split('/')[-1] # Ignore the annotation package. 1.74 + self._annotation_map[qualified_method].append(annotation) 1.75 + has_value = False 1.76 + continue 1.77 + if annotation: 1.78 + assert qualified_method 1.79 + if not has_value: 1.80 + m = self._PROGUARD_ANNOTATION_CONST_RE.match(line) 1.81 + if m: 1.82 + has_value = True 1.83 + else: 1.84 + m = self._PROGUARD_ANNOTATION_VALUE_RE.match(line) 1.85 + if m: 1.86 + value = m.group(1) 1.87 + self._annotation_map[qualified_method].append( 1.88 + annotation + ':' + value) 1.89 + has_value = False 1.90 + 1.91 + def _GetAnnotationMap(self): 1.92 + return self._annotation_map 1.93 + 1.94 + def _IsTestMethod(self, test): 1.95 + class_name, method = test.split('#') 1.96 + return class_name.endswith('Test') and method.startswith('test') 1.97 + 1.98 + def GetApkPath(self): 1.99 + return self._apk_path 1.100 + 1.101 + def GetPackageName(self): 1.102 + """Returns the package name of this APK.""" 1.103 + aapt_output = cmd_helper.GetCmdOutput( 1.104 + ['aapt', 'dump', 'badging', self._apk_path]).split('\n') 1.105 + for line in aapt_output: 1.106 + m = self._AAPT_PACKAGE_NAME_RE.match(line) 1.107 + if m: 1.108 + return m.group(1) 1.109 + raise Exception('Failed to determine package name of %s' % self._apk_path) 1.110 + 1.111 + def GetTestAnnotations(self, test): 1.112 + """Returns a list of all annotations for the given |test|. May be empty.""" 1.113 + if not self._IsTestMethod(test): 1.114 + return [] 1.115 + return self._GetAnnotationMap()[test] 1.116 + 1.117 + def _AnnotationsMatchFilters(self, annotation_filter_list, annotations): 1.118 + """Checks if annotations match any of the filters.""" 1.119 + if not annotation_filter_list: 1.120 + return True 1.121 + for annotation_filter in annotation_filter_list: 1.122 + filters = annotation_filter.split('=') 1.123 + if len(filters) == 2: 1.124 + key = filters[0] 1.125 + value_list = filters[1].split(',') 1.126 + for value in value_list: 1.127 + if key + ':' + value in annotations: 1.128 + return True 1.129 + elif annotation_filter in annotations: 1.130 + return True 1.131 + return False 1.132 + 1.133 + def GetAnnotatedTests(self, annotation_filter_list): 1.134 + """Returns a list of all tests that match the given annotation filters.""" 1.135 + return [test for test, annotations in self._GetAnnotationMap().iteritems() 1.136 + if self._IsTestMethod(test) and self._AnnotationsMatchFilters( 1.137 + annotation_filter_list, annotations)] 1.138 + 1.139 + def GetTestMethods(self): 1.140 + """Returns a list of all test methods in this apk as Class#testMethod.""" 1.141 + return self._test_methods 1.142 + 1.143 + @staticmethod 1.144 + def IsPythonDrivenTest(test): 1.145 + return 'pythonDrivenTests' in test