1#!/usr/bin/env python 2# 3# Copyright (C) 2016 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16# 17 18"""utils.py: export utility functions. 19""" 20 21from __future__ import print_function 22import logging 23import os 24import os.path 25import subprocess 26import sys 27 28def get_script_dir(): 29 return os.path.dirname(os.path.realpath(__file__)) 30 31 32def is_windows(): 33 return sys.platform == 'win32' or sys.platform == 'cygwin' 34 35def is_darwin(): 36 return sys.platform == 'darwin' 37 38def is_python3(): 39 return sys.version_info >= (3, 0) 40 41 42def log_debug(msg): 43 logging.debug(msg) 44 45 46def log_info(msg): 47 logging.info(msg) 48 49 50def log_warning(msg): 51 logging.warning(msg) 52 53 54def log_fatal(msg): 55 raise Exception(msg) 56 57def log_exit(msg): 58 sys.exit(msg) 59 60def str_to_bytes(str): 61 if not is_python3(): 62 return str 63 # In python 3, str are wide strings whereas the C api expects 8 bit strings, hence we have to convert 64 # For now using utf-8 as the encoding. 65 return str.encode('utf-8') 66 67def bytes_to_str(bytes): 68 if not is_python3(): 69 return bytes 70 return bytes.decode('utf-8') 71 72def get_target_binary_path(arch, binary_name): 73 if arch == 'aarch64': 74 arch = 'arm64' 75 arch_dir = os.path.join(get_script_dir(), "bin", "android", arch) 76 if not os.path.isdir(arch_dir): 77 log_fatal("can't find arch directory: %s" % arch_dir) 78 binary_path = os.path.join(arch_dir, binary_name) 79 if not os.path.isfile(binary_path): 80 log_fatal("can't find binary: %s" % binary_path) 81 return binary_path 82 83 84def get_host_binary_path(binary_name): 85 dir = os.path.join(get_script_dir(), 'bin') 86 if is_windows(): 87 if binary_name.endswith('.so'): 88 binary_name = binary_name[0:-3] + '.dll' 89 elif binary_name.find('.') == -1: 90 binary_name += '.exe' 91 dir = os.path.join(dir, 'windows') 92 elif sys.platform == 'darwin': # OSX 93 if binary_name.endswith('.so'): 94 binary_name = binary_name[0:-3] + '.dylib' 95 dir = os.path.join(dir, 'darwin') 96 else: 97 dir = os.path.join(dir, 'linux') 98 dir = os.path.join(dir, 'x86_64' if sys.maxsize > 2 ** 32 else 'x86') 99 binary_path = os.path.join(dir, binary_name) 100 if not os.path.isfile(binary_path): 101 log_fatal("can't find binary: %s" % binary_path) 102 return binary_path 103 104 105def is_executable_available(executable, option='--help'): 106 """ Run an executable to see if it exists. """ 107 try: 108 subproc = subprocess.Popen([executable, option], stdout=subprocess.PIPE, 109 stderr=subprocess.PIPE) 110 subproc.communicate() 111 return subproc.returncode == 0 112 except: 113 return False 114 115expected_tool_paths = { 116 'adb': { 117 'test_option': 'version', 118 'darwin': [(True, 'Library/Android/sdk/platform-tools/adb'), 119 (False, '../../platform-tools/adb')], 120 'linux': [(True, 'Android/Sdk/platform-tools/adb'), 121 (False, '../../platform-tools/adb')], 122 'windows': [(True, 'AppData/Local/Android/sdk/platform-tools/adb'), 123 (False, '../../platform-tools/adb')], 124 }, 125 'readelf': { 126 'test_option': '--help', 127 'darwin': [(True, 'Library/Android/sdk/ndk-bundle/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/bin/aarch64-linux-android-readelf'), 128 (False, '../toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/bin/aarch64-linux-android-readelf')], 129 'linux': [(True, 'Android/Sdk/ndk-bundle/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-readelf'), 130 (False, '../toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-readelf')], 131 'windows': [(True, 'AppData/Local/Android/sdk/ndk-bundle/toolchains/aarch64-linux-android-4.9/prebuilt/windows-x86_64/bin/aarch64-linux-android-readelf'), 132 (False, '../toolchains/aarch64-linux-android-4.9/prebuilt/windows-x86_64/bin/aarch64-linux-android-readelf')], 133 }, 134 'addr2line': { 135 'test_option': '--help', 136 'darwin': [(True, 'Library/Android/sdk/ndk-bundle/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/bin/aarch64-linux-android-addr2line'), 137 (False, '../toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/bin/aarch64-linux-android-addr2line')], 138 'linux': [(True, 'Android/Sdk/ndk-bundle/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-addr2line'), 139 (False, '../toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-addr2line')], 140 'windows': [(True, 'AppData/Local/Android/sdk/ndk-bundle/toolchains/aarch64-linux-android-4.9/prebuilt/windows-x86_64/bin/aarch64-linux-android-addr2line'), 141 (False, '../toolchains/aarch64-linux-android-4.9/prebuilt/windows-x86_64/bin/aarch64-linux-android-addr2line')], 142 }, 143} 144 145def find_tool_path(toolname): 146 if toolname not in expected_tool_paths: 147 return None 148 test_option = expected_tool_paths[toolname]['test_option'] 149 if is_executable_available(toolname, test_option): 150 return toolname 151 platform = 'linux' 152 if is_windows(): 153 platform = 'windows' 154 elif is_darwin(): 155 platform = 'darwin' 156 paths = expected_tool_paths[toolname][platform] 157 home = os.environ.get('HOMEPATH') if is_windows() else os.environ.get('HOME') 158 for (relative_to_home, path) in paths: 159 path = path.replace('/', os.sep) 160 if relative_to_home: 161 path = os.path.join(home, path) 162 else: 163 path = os.path.join(get_script_dir(), path) 164 if is_executable_available(path, test_option): 165 return path 166 return None 167 168 169class AdbHelper(object): 170 def __init__(self): 171 adb_path = find_tool_path('adb') 172 if not adb_path: 173 log_exit("Can't find adb in PATH environment.") 174 self.adb_path = adb_path 175 176 177 def run(self, adb_args): 178 return self.run_and_return_output(adb_args)[0] 179 180 181 def run_and_return_output(self, adb_args, stdout_file=None): 182 adb_args = [self.adb_path] + adb_args 183 log_debug('run adb cmd: %s' % adb_args) 184 if stdout_file: 185 with open(stdout_file, 'wb') as stdout_fh: 186 returncode = subprocess.call(adb_args, stdout=stdout_fh) 187 stdoutdata = '' 188 else: 189 subproc = subprocess.Popen(adb_args, stdout=subprocess.PIPE) 190 (stdoutdata, _) = subproc.communicate() 191 returncode = subproc.returncode 192 result = (returncode == 0) 193 if stdoutdata and adb_args[1] != 'push' and adb_args[1] != 'pull': 194 stdoutdata = bytes_to_str(stdoutdata) 195 log_debug(stdoutdata) 196 log_debug('run adb cmd: %s [result %s]' % (adb_args, result)) 197 return (result, stdoutdata) 198 199 def check_run(self, adb_args): 200 self.check_run_and_return_output(adb_args) 201 202 203 def check_run_and_return_output(self, adb_args, stdout_file=None): 204 result, stdoutdata = self.run_and_return_output(adb_args, stdout_file) 205 if not result: 206 log_exit('run "adb %s" failed' % adb_args) 207 return stdoutdata 208 209 210 def switch_to_root(self): 211 result, stdoutdata = self.run_and_return_output(['shell', 'whoami']) 212 if not result: 213 return False 214 if stdoutdata.find('root') != -1: 215 return True 216 build_type = self.get_property('ro.build.type') 217 if build_type == 'user': 218 return False 219 self.run(['root']) 220 result, stdoutdata = self.run_and_return_output(['shell', 'whoami']) 221 if result and stdoutdata.find('root') != -1: 222 return True 223 return False 224 225 def get_property(self, name): 226 result, stdoutdata = self.run_and_return_output(['shell', 'getprop', name]) 227 if not result: 228 return None 229 return stdoutdata 230 231 232 def set_property(self, name, value): 233 return self.run(['shell', 'setprop', name, value]) 234 235 236def load_config(config_file): 237 if not os.path.exists(config_file): 238 log_exit("can't find config_file: %s" % config_file) 239 config = {} 240 if is_python3(): 241 with open(config_file, 'r') as fh: 242 source = fh.read() 243 exec(source, config) 244 else: 245 execfile(config_file, config) 246 return config 247 248 249def flatten_arg_list(arg_list): 250 res = [] 251 if arg_list: 252 for items in arg_list: 253 res += items 254 return res 255 256 257logging.getLogger().setLevel(logging.DEBUG) 258