• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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