1*8975f5c5SAndroid Build Coastguard Worker#!/usr/bin/env vpython3 2*8975f5c5SAndroid Build Coastguard Worker# Copyright 2017 The Chromium Authors 3*8975f5c5SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 4*8975f5c5SAndroid Build Coastguard Worker# found in the LICENSE file. 5*8975f5c5SAndroid Build Coastguard Worker 6*8975f5c5SAndroid Build Coastguard Worker# Using colorama.Fore/Back/Style members 7*8975f5c5SAndroid Build Coastguard Worker# pylint: disable=no-member 8*8975f5c5SAndroid Build Coastguard Worker 9*8975f5c5SAndroid Build Coastguard Worker 10*8975f5c5SAndroid Build Coastguard Workerimport argparse 11*8975f5c5SAndroid Build Coastguard Workerimport collections 12*8975f5c5SAndroid Build Coastguard Workerimport json 13*8975f5c5SAndroid Build Coastguard Workerimport logging 14*8975f5c5SAndroid Build Coastguard Workerimport os 15*8975f5c5SAndroid Build Coastguard Workerimport posixpath 16*8975f5c5SAndroid Build Coastguard Workerimport random 17*8975f5c5SAndroid Build Coastguard Workerimport re 18*8975f5c5SAndroid Build Coastguard Workerimport shlex 19*8975f5c5SAndroid Build Coastguard Workerimport shutil 20*8975f5c5SAndroid Build Coastguard Workerimport subprocess 21*8975f5c5SAndroid Build Coastguard Workerimport sys 22*8975f5c5SAndroid Build Coastguard Workerimport tempfile 23*8975f5c5SAndroid Build Coastguard Workerimport textwrap 24*8975f5c5SAndroid Build Coastguard Workerimport zipfile 25*8975f5c5SAndroid Build Coastguard Worker 26*8975f5c5SAndroid Build Coastguard Workerimport adb_command_line 27*8975f5c5SAndroid Build Coastguard Workerimport devil_chromium 28*8975f5c5SAndroid Build Coastguard Workerfrom devil import devil_env 29*8975f5c5SAndroid Build Coastguard Workerfrom devil.android import apk_helper 30*8975f5c5SAndroid Build Coastguard Workerfrom devil.android import device_errors 31*8975f5c5SAndroid Build Coastguard Workerfrom devil.android import device_utils 32*8975f5c5SAndroid Build Coastguard Workerfrom devil.android.sdk import adb_wrapper 33*8975f5c5SAndroid Build Coastguard Workerfrom devil.android.sdk import build_tools 34*8975f5c5SAndroid Build Coastguard Workerfrom devil.android.sdk import intent 35*8975f5c5SAndroid Build Coastguard Workerfrom devil.android.sdk import version_codes 36*8975f5c5SAndroid Build Coastguard Workerfrom devil.utils import run_tests_helper 37*8975f5c5SAndroid Build Coastguard Worker 38*8975f5c5SAndroid Build Coastguard Worker_DIR_SOURCE_ROOT = os.path.normpath( 39*8975f5c5SAndroid Build Coastguard Worker os.path.join(os.path.dirname(__file__), '..', '..')) 40*8975f5c5SAndroid Build Coastguard Worker_JAVA_HOME = os.path.join(_DIR_SOURCE_ROOT, 'third_party', 'jdk', 'current') 41*8975f5c5SAndroid Build Coastguard Worker 42*8975f5c5SAndroid Build Coastguard Workerwith devil_env.SysPath( 43*8975f5c5SAndroid Build Coastguard Worker os.path.join(_DIR_SOURCE_ROOT, 'third_party', 'colorama', 'src')): 44*8975f5c5SAndroid Build Coastguard Worker import colorama 45*8975f5c5SAndroid Build Coastguard Worker 46*8975f5c5SAndroid Build Coastguard Workerfrom incremental_install import installer 47*8975f5c5SAndroid Build Coastguard Workerfrom pylib import constants 48*8975f5c5SAndroid Build Coastguard Workerfrom pylib.symbols import deobfuscator 49*8975f5c5SAndroid Build Coastguard Workerfrom pylib.utils import simpleperf 50*8975f5c5SAndroid Build Coastguard Workerfrom pylib.utils import app_bundle_utils 51*8975f5c5SAndroid Build Coastguard Worker 52*8975f5c5SAndroid Build Coastguard Workerwith devil_env.SysPath( 53*8975f5c5SAndroid Build Coastguard Worker os.path.join(_DIR_SOURCE_ROOT, 'build', 'android', 'gyp')): 54*8975f5c5SAndroid Build Coastguard Worker import bundletool 55*8975f5c5SAndroid Build Coastguard Worker 56*8975f5c5SAndroid Build Coastguard WorkerBASE_MODULE = 'base' 57*8975f5c5SAndroid Build Coastguard Worker 58*8975f5c5SAndroid Build Coastguard Worker 59*8975f5c5SAndroid Build Coastguard Workerdef _Colorize(text, style=''): 60*8975f5c5SAndroid Build Coastguard Worker return (style 61*8975f5c5SAndroid Build Coastguard Worker + text 62*8975f5c5SAndroid Build Coastguard Worker + colorama.Style.RESET_ALL) 63*8975f5c5SAndroid Build Coastguard Worker 64*8975f5c5SAndroid Build Coastguard Worker 65*8975f5c5SAndroid Build Coastguard Workerdef _InstallApk(devices, apk, install_dict): 66*8975f5c5SAndroid Build Coastguard Worker def install(device): 67*8975f5c5SAndroid Build Coastguard Worker if install_dict: 68*8975f5c5SAndroid Build Coastguard Worker installer.Install(device, install_dict, apk=apk, permissions=[]) 69*8975f5c5SAndroid Build Coastguard Worker else: 70*8975f5c5SAndroid Build Coastguard Worker device.Install(apk, permissions=[], allow_downgrade=True, reinstall=True) 71*8975f5c5SAndroid Build Coastguard Worker 72*8975f5c5SAndroid Build Coastguard Worker logging.info('Installing %sincremental apk.', '' if install_dict else 'non-') 73*8975f5c5SAndroid Build Coastguard Worker device_utils.DeviceUtils.parallel(devices).pMap(install) 74*8975f5c5SAndroid Build Coastguard Worker 75*8975f5c5SAndroid Build Coastguard Worker 76*8975f5c5SAndroid Build Coastguard Worker# A named tuple containing the information needed to convert a bundle into 77*8975f5c5SAndroid Build Coastguard Worker# an installable .apks archive. 78*8975f5c5SAndroid Build Coastguard Worker# Fields: 79*8975f5c5SAndroid Build Coastguard Worker# bundle_path: Path to input bundle file. 80*8975f5c5SAndroid Build Coastguard Worker# bundle_apk_path: Path to output bundle .apks archive file. 81*8975f5c5SAndroid Build Coastguard Worker# aapt2_path: Path to aapt2 tool. 82*8975f5c5SAndroid Build Coastguard Worker# keystore_path: Path to keystore file. 83*8975f5c5SAndroid Build Coastguard Worker# keystore_password: Password for the keystore file. 84*8975f5c5SAndroid Build Coastguard Worker# keystore_alias: Signing key name alias within the keystore file. 85*8975f5c5SAndroid Build Coastguard Worker# system_image_locales: List of Chromium locales to include in system .apks. 86*8975f5c5SAndroid Build Coastguard WorkerBundleGenerationInfo = collections.namedtuple( 87*8975f5c5SAndroid Build Coastguard Worker 'BundleGenerationInfo', 88*8975f5c5SAndroid Build Coastguard Worker 'bundle_path,bundle_apks_path,aapt2_path,keystore_path,keystore_password,' 89*8975f5c5SAndroid Build Coastguard Worker 'keystore_alias,system_image_locales') 90*8975f5c5SAndroid Build Coastguard Worker 91*8975f5c5SAndroid Build Coastguard Worker 92*8975f5c5SAndroid Build Coastguard Workerdef _GenerateBundleApks(info, 93*8975f5c5SAndroid Build Coastguard Worker output_path=None, 94*8975f5c5SAndroid Build Coastguard Worker minimal=False, 95*8975f5c5SAndroid Build Coastguard Worker minimal_sdk_version=None, 96*8975f5c5SAndroid Build Coastguard Worker mode=None, 97*8975f5c5SAndroid Build Coastguard Worker optimize_for=None): 98*8975f5c5SAndroid Build Coastguard Worker """Generate an .apks archive from a bundle on demand. 99*8975f5c5SAndroid Build Coastguard Worker 100*8975f5c5SAndroid Build Coastguard Worker Args: 101*8975f5c5SAndroid Build Coastguard Worker info: A BundleGenerationInfo instance. 102*8975f5c5SAndroid Build Coastguard Worker output_path: Path of output .apks archive. 103*8975f5c5SAndroid Build Coastguard Worker minimal: Create the minimal set of apks possible (english-only). 104*8975f5c5SAndroid Build Coastguard Worker minimal_sdk_version: When minimal=True, use this sdkVersion. 105*8975f5c5SAndroid Build Coastguard Worker mode: Build mode, either None, or one of app_bundle_utils.BUILD_APKS_MODES. 106*8975f5c5SAndroid Build Coastguard Worker optimize_for: Override split config, either None, or one of 107*8975f5c5SAndroid Build Coastguard Worker app_bundle_utils.OPTIMIZE_FOR_OPTIONS. 108*8975f5c5SAndroid Build Coastguard Worker """ 109*8975f5c5SAndroid Build Coastguard Worker logging.info('Generating .apks file') 110*8975f5c5SAndroid Build Coastguard Worker app_bundle_utils.GenerateBundleApks( 111*8975f5c5SAndroid Build Coastguard Worker info.bundle_path, 112*8975f5c5SAndroid Build Coastguard Worker # Store .apks file beside the .aab file by default so that it gets cached. 113*8975f5c5SAndroid Build Coastguard Worker output_path or info.bundle_apks_path, 114*8975f5c5SAndroid Build Coastguard Worker info.aapt2_path, 115*8975f5c5SAndroid Build Coastguard Worker info.keystore_path, 116*8975f5c5SAndroid Build Coastguard Worker info.keystore_password, 117*8975f5c5SAndroid Build Coastguard Worker info.keystore_alias, 118*8975f5c5SAndroid Build Coastguard Worker system_image_locales=info.system_image_locales, 119*8975f5c5SAndroid Build Coastguard Worker mode=mode, 120*8975f5c5SAndroid Build Coastguard Worker minimal=minimal, 121*8975f5c5SAndroid Build Coastguard Worker minimal_sdk_version=minimal_sdk_version, 122*8975f5c5SAndroid Build Coastguard Worker optimize_for=optimize_for) 123*8975f5c5SAndroid Build Coastguard Worker 124*8975f5c5SAndroid Build Coastguard Worker 125*8975f5c5SAndroid Build Coastguard Workerdef _InstallBundle(devices, 126*8975f5c5SAndroid Build Coastguard Worker apk_helper_instance, 127*8975f5c5SAndroid Build Coastguard Worker modules, 128*8975f5c5SAndroid Build Coastguard Worker fake_modules, 129*8975f5c5SAndroid Build Coastguard Worker locales=None): 130*8975f5c5SAndroid Build Coastguard Worker 131*8975f5c5SAndroid Build Coastguard Worker def Install(device): 132*8975f5c5SAndroid Build Coastguard Worker device.Install(apk_helper_instance, 133*8975f5c5SAndroid Build Coastguard Worker permissions=[], 134*8975f5c5SAndroid Build Coastguard Worker modules=modules, 135*8975f5c5SAndroid Build Coastguard Worker fake_modules=fake_modules, 136*8975f5c5SAndroid Build Coastguard Worker additional_locales=locales, 137*8975f5c5SAndroid Build Coastguard Worker allow_downgrade=True, 138*8975f5c5SAndroid Build Coastguard Worker reinstall=True) 139*8975f5c5SAndroid Build Coastguard Worker 140*8975f5c5SAndroid Build Coastguard Worker # Basic checks for |modules| and |fake_modules|. 141*8975f5c5SAndroid Build Coastguard Worker # * |fake_modules| cannot include 'base'. 142*8975f5c5SAndroid Build Coastguard Worker # * If |fake_modules| is given, ensure |modules| includes 'base'. 143*8975f5c5SAndroid Build Coastguard Worker # * They must be disjoint (checked by device.Install). 144*8975f5c5SAndroid Build Coastguard Worker modules_set = set(modules) if modules else set() 145*8975f5c5SAndroid Build Coastguard Worker fake_modules_set = set(fake_modules) if fake_modules else set() 146*8975f5c5SAndroid Build Coastguard Worker if BASE_MODULE in fake_modules_set: 147*8975f5c5SAndroid Build Coastguard Worker raise Exception('\'-f {}\' is disallowed.'.format(BASE_MODULE)) 148*8975f5c5SAndroid Build Coastguard Worker if fake_modules_set and BASE_MODULE not in modules_set: 149*8975f5c5SAndroid Build Coastguard Worker raise Exception( 150*8975f5c5SAndroid Build Coastguard Worker '\'-f FAKE\' must be accompanied by \'-m {}\''.format(BASE_MODULE)) 151*8975f5c5SAndroid Build Coastguard Worker 152*8975f5c5SAndroid Build Coastguard Worker logging.info('Installing bundle.') 153*8975f5c5SAndroid Build Coastguard Worker device_utils.DeviceUtils.parallel(devices).pMap(Install) 154*8975f5c5SAndroid Build Coastguard Worker 155*8975f5c5SAndroid Build Coastguard Worker 156*8975f5c5SAndroid Build Coastguard Workerdef _UninstallApk(devices, install_dict, package_name): 157*8975f5c5SAndroid Build Coastguard Worker def uninstall(device): 158*8975f5c5SAndroid Build Coastguard Worker if install_dict: 159*8975f5c5SAndroid Build Coastguard Worker installer.Uninstall(device, package_name) 160*8975f5c5SAndroid Build Coastguard Worker else: 161*8975f5c5SAndroid Build Coastguard Worker device.Uninstall(package_name) 162*8975f5c5SAndroid Build Coastguard Worker device_utils.DeviceUtils.parallel(devices).pMap(uninstall) 163*8975f5c5SAndroid Build Coastguard Worker 164*8975f5c5SAndroid Build Coastguard Worker 165*8975f5c5SAndroid Build Coastguard Workerdef _IsWebViewProvider(apk_helper_instance): 166*8975f5c5SAndroid Build Coastguard Worker meta_data = apk_helper_instance.GetAllMetadata() 167*8975f5c5SAndroid Build Coastguard Worker meta_data_keys = [pair[0] for pair in meta_data] 168*8975f5c5SAndroid Build Coastguard Worker return 'com.android.webview.WebViewLibrary' in meta_data_keys 169*8975f5c5SAndroid Build Coastguard Worker 170*8975f5c5SAndroid Build Coastguard Worker 171*8975f5c5SAndroid Build Coastguard Workerdef _SetWebViewProvider(devices, package_name): 172*8975f5c5SAndroid Build Coastguard Worker 173*8975f5c5SAndroid Build Coastguard Worker def switch_provider(device): 174*8975f5c5SAndroid Build Coastguard Worker if device.build_version_sdk < version_codes.NOUGAT: 175*8975f5c5SAndroid Build Coastguard Worker logging.error('No need to switch provider on pre-Nougat devices (%s)', 176*8975f5c5SAndroid Build Coastguard Worker device.serial) 177*8975f5c5SAndroid Build Coastguard Worker else: 178*8975f5c5SAndroid Build Coastguard Worker device.SetWebViewImplementation(package_name) 179*8975f5c5SAndroid Build Coastguard Worker 180*8975f5c5SAndroid Build Coastguard Worker device_utils.DeviceUtils.parallel(devices).pMap(switch_provider) 181*8975f5c5SAndroid Build Coastguard Worker 182*8975f5c5SAndroid Build Coastguard Worker 183*8975f5c5SAndroid Build Coastguard Workerdef _NormalizeProcessName(debug_process_name, package_name): 184*8975f5c5SAndroid Build Coastguard Worker if not debug_process_name: 185*8975f5c5SAndroid Build Coastguard Worker debug_process_name = package_name 186*8975f5c5SAndroid Build Coastguard Worker elif debug_process_name.startswith(':'): 187*8975f5c5SAndroid Build Coastguard Worker debug_process_name = package_name + debug_process_name 188*8975f5c5SAndroid Build Coastguard Worker elif '.' not in debug_process_name: 189*8975f5c5SAndroid Build Coastguard Worker debug_process_name = package_name + ':' + debug_process_name 190*8975f5c5SAndroid Build Coastguard Worker return debug_process_name 191*8975f5c5SAndroid Build Coastguard Worker 192*8975f5c5SAndroid Build Coastguard Worker 193*8975f5c5SAndroid Build Coastguard Workerdef _ResolveActivity(device, package_name, category, action): 194*8975f5c5SAndroid Build Coastguard Worker # E.g.: 195*8975f5c5SAndroid Build Coastguard Worker # Activity Resolver Table: 196*8975f5c5SAndroid Build Coastguard Worker # Schemes: 197*8975f5c5SAndroid Build Coastguard Worker # http: 198*8975f5c5SAndroid Build Coastguard Worker # 67e97c0 org.chromium.pkg/.MainActivityfilter c91d43e 199*8975f5c5SAndroid Build Coastguard Worker # Action: "android.intent.action.VIEW" 200*8975f5c5SAndroid Build Coastguard Worker # Category: "android.intent.category.DEFAULT" 201*8975f5c5SAndroid Build Coastguard Worker # Category: "android.intent.category.BROWSABLE" 202*8975f5c5SAndroid Build Coastguard Worker # Scheme: "http" 203*8975f5c5SAndroid Build Coastguard Worker # Scheme: "https" 204*8975f5c5SAndroid Build Coastguard Worker # 205*8975f5c5SAndroid Build Coastguard Worker # Non-Data Actions: 206*8975f5c5SAndroid Build Coastguard Worker # android.intent.action.MAIN: 207*8975f5c5SAndroid Build Coastguard Worker # 67e97c0 org.chromium.pkg/.MainActivity filter 4a34cf9 208*8975f5c5SAndroid Build Coastguard Worker # Action: "android.intent.action.MAIN" 209*8975f5c5SAndroid Build Coastguard Worker # Category: "android.intent.category.LAUNCHER" 210*8975f5c5SAndroid Build Coastguard Worker lines = device.RunShellCommand(['dumpsys', 'package', package_name], 211*8975f5c5SAndroid Build Coastguard Worker check_return=True) 212*8975f5c5SAndroid Build Coastguard Worker 213*8975f5c5SAndroid Build Coastguard Worker # Extract the Activity Resolver Table: section. 214*8975f5c5SAndroid Build Coastguard Worker start_idx = next((i for i, l in enumerate(lines) 215*8975f5c5SAndroid Build Coastguard Worker if l.startswith('Activity Resolver Table:')), None) 216*8975f5c5SAndroid Build Coastguard Worker if start_idx is None: 217*8975f5c5SAndroid Build Coastguard Worker if not device.IsApplicationInstalled(package_name): 218*8975f5c5SAndroid Build Coastguard Worker raise Exception('Package not installed: ' + package_name) 219*8975f5c5SAndroid Build Coastguard Worker raise Exception('No Activity Resolver Table in:\n' + '\n'.join(lines)) 220*8975f5c5SAndroid Build Coastguard Worker line_count = next(i for i, l in enumerate(lines[start_idx + 1:]) 221*8975f5c5SAndroid Build Coastguard Worker if l and not l[0].isspace()) 222*8975f5c5SAndroid Build Coastguard Worker data = '\n'.join(lines[start_idx:start_idx + line_count]) 223*8975f5c5SAndroid Build Coastguard Worker 224*8975f5c5SAndroid Build Coastguard Worker # Split on each Activity entry. 225*8975f5c5SAndroid Build Coastguard Worker entries = re.split(r'^ [0-9a-f]+ ', data, flags=re.MULTILINE) 226*8975f5c5SAndroid Build Coastguard Worker 227*8975f5c5SAndroid Build Coastguard Worker def activity_name_from_entry(entry): 228*8975f5c5SAndroid Build Coastguard Worker assert entry.startswith(package_name), 'Got: ' + entry 229*8975f5c5SAndroid Build Coastguard Worker activity_name = entry[len(package_name) + 1:].split(' ', 1)[0] 230*8975f5c5SAndroid Build Coastguard Worker if activity_name[0] == '.': 231*8975f5c5SAndroid Build Coastguard Worker activity_name = package_name + activity_name 232*8975f5c5SAndroid Build Coastguard Worker return activity_name 233*8975f5c5SAndroid Build Coastguard Worker 234*8975f5c5SAndroid Build Coastguard Worker # Find the one with the text we want. 235*8975f5c5SAndroid Build Coastguard Worker category_text = f'Category: "{category}"' 236*8975f5c5SAndroid Build Coastguard Worker action_text = f'Action: "{action}"' 237*8975f5c5SAndroid Build Coastguard Worker matched_entries = [ 238*8975f5c5SAndroid Build Coastguard Worker e for e in entries[1:] if category_text in e and action_text in e 239*8975f5c5SAndroid Build Coastguard Worker ] 240*8975f5c5SAndroid Build Coastguard Worker 241*8975f5c5SAndroid Build Coastguard Worker if not matched_entries: 242*8975f5c5SAndroid Build Coastguard Worker raise Exception(f'Did not find {category_text}, {action_text} in\n{data}') 243*8975f5c5SAndroid Build Coastguard Worker if len(matched_entries) > 1: 244*8975f5c5SAndroid Build Coastguard Worker # When there are multiple matches, look for the one marked as default. 245*8975f5c5SAndroid Build Coastguard Worker # Necessary for Monochrome, which also has MonochromeLauncherActivity. 246*8975f5c5SAndroid Build Coastguard Worker default_entries = [ 247*8975f5c5SAndroid Build Coastguard Worker e for e in matched_entries if 'android.intent.category.DEFAULT' in e 248*8975f5c5SAndroid Build Coastguard Worker ] 249*8975f5c5SAndroid Build Coastguard Worker matched_entries = default_entries or matched_entries 250*8975f5c5SAndroid Build Coastguard Worker 251*8975f5c5SAndroid Build Coastguard Worker # See if all matches point to the same activity. 252*8975f5c5SAndroid Build Coastguard Worker activity_names = {activity_name_from_entry(e) for e in matched_entries} 253*8975f5c5SAndroid Build Coastguard Worker 254*8975f5c5SAndroid Build Coastguard Worker if len(activity_names) > 1: 255*8975f5c5SAndroid Build Coastguard Worker raise Exception('Found multiple launcher activities:\n * ' + 256*8975f5c5SAndroid Build Coastguard Worker '\n * '.join(sorted(activity_names))) 257*8975f5c5SAndroid Build Coastguard Worker return next(iter(activity_names)) 258*8975f5c5SAndroid Build Coastguard Worker 259*8975f5c5SAndroid Build Coastguard Worker 260*8975f5c5SAndroid Build Coastguard Workerdef _ReadDeviceFlags(device, command_line_flags_file): 261*8975f5c5SAndroid Build Coastguard Worker device_path = f'/data/local/tmp/{command_line_flags_file}' 262*8975f5c5SAndroid Build Coastguard Worker old_flags = device.RunShellCommand(f'cat {device_path} 2>/dev/null', 263*8975f5c5SAndroid Build Coastguard Worker as_root=True, 264*8975f5c5SAndroid Build Coastguard Worker shell=True, 265*8975f5c5SAndroid Build Coastguard Worker check_return=False, 266*8975f5c5SAndroid Build Coastguard Worker raw_output=True) 267*8975f5c5SAndroid Build Coastguard Worker if not old_flags: 268*8975f5c5SAndroid Build Coastguard Worker return None 269*8975f5c5SAndroid Build Coastguard Worker if old_flags.startswith('_ '): 270*8975f5c5SAndroid Build Coastguard Worker old_flags = old_flags[2:] 271*8975f5c5SAndroid Build Coastguard Worker 272*8975f5c5SAndroid Build Coastguard Worker return old_flags 273*8975f5c5SAndroid Build Coastguard Worker 274*8975f5c5SAndroid Build Coastguard Worker 275*8975f5c5SAndroid Build Coastguard Workerdef _UpdateDeviceFlags(device, command_line_flags_file, new_flags): 276*8975f5c5SAndroid Build Coastguard Worker if not command_line_flags_file: 277*8975f5c5SAndroid Build Coastguard Worker if new_flags: 278*8975f5c5SAndroid Build Coastguard Worker logging.warning('Command-line flags are not configured for this target.') 279*8975f5c5SAndroid Build Coastguard Worker return 280*8975f5c5SAndroid Build Coastguard Worker 281*8975f5c5SAndroid Build Coastguard Worker old_flags = _ReadDeviceFlags(device, command_line_flags_file) 282*8975f5c5SAndroid Build Coastguard Worker 283*8975f5c5SAndroid Build Coastguard Worker if new_flags is None: 284*8975f5c5SAndroid Build Coastguard Worker if old_flags: 285*8975f5c5SAndroid Build Coastguard Worker logging.warning('Using pre-existing command-line flags: %s', old_flags) 286*8975f5c5SAndroid Build Coastguard Worker return 287*8975f5c5SAndroid Build Coastguard Worker 288*8975f5c5SAndroid Build Coastguard Worker if new_flags != old_flags: 289*8975f5c5SAndroid Build Coastguard Worker adb_command_line.CheckBuildTypeSupportsFlags(device, 290*8975f5c5SAndroid Build Coastguard Worker command_line_flags_file) 291*8975f5c5SAndroid Build Coastguard Worker # This file does not need to be owned by root, but devil's flag_changer 292*8975f5c5SAndroid Build Coastguard Worker # helper uses as_root, so existing files cannot be updated without it. 293*8975f5c5SAndroid Build Coastguard Worker device_path = f'/data/local/tmp/{command_line_flags_file}' 294*8975f5c5SAndroid Build Coastguard Worker if new_flags: 295*8975f5c5SAndroid Build Coastguard Worker logging.info('Updated flags file: %s with value: %s', device_path, 296*8975f5c5SAndroid Build Coastguard Worker new_flags) 297*8975f5c5SAndroid Build Coastguard Worker device.WriteFile(device_path, '_ ' + new_flags, as_root=True) 298*8975f5c5SAndroid Build Coastguard Worker else: 299*8975f5c5SAndroid Build Coastguard Worker logging.info('Removed flags file: %s', device_path) 300*8975f5c5SAndroid Build Coastguard Worker device.RemovePath(device_path, force=True, as_root=True) 301*8975f5c5SAndroid Build Coastguard Worker 302*8975f5c5SAndroid Build Coastguard Worker 303*8975f5c5SAndroid Build Coastguard Workerdef _LaunchUrl(devices, 304*8975f5c5SAndroid Build Coastguard Worker package_name, 305*8975f5c5SAndroid Build Coastguard Worker argv=None, 306*8975f5c5SAndroid Build Coastguard Worker command_line_flags_file=None, 307*8975f5c5SAndroid Build Coastguard Worker url=None, 308*8975f5c5SAndroid Build Coastguard Worker wait_for_java_debugger=False, 309*8975f5c5SAndroid Build Coastguard Worker debug_process_name=None, 310*8975f5c5SAndroid Build Coastguard Worker nokill=None): 311*8975f5c5SAndroid Build Coastguard Worker if argv and command_line_flags_file is None: 312*8975f5c5SAndroid Build Coastguard Worker raise Exception('This apk does not support any flags.') 313*8975f5c5SAndroid Build Coastguard Worker 314*8975f5c5SAndroid Build Coastguard Worker debug_process_name = _NormalizeProcessName(debug_process_name, package_name) 315*8975f5c5SAndroid Build Coastguard Worker 316*8975f5c5SAndroid Build Coastguard Worker if url is None: 317*8975f5c5SAndroid Build Coastguard Worker category = 'android.intent.category.LAUNCHER' 318*8975f5c5SAndroid Build Coastguard Worker action = 'android.intent.action.MAIN' 319*8975f5c5SAndroid Build Coastguard Worker else: 320*8975f5c5SAndroid Build Coastguard Worker category = 'android.intent.category.BROWSABLE' 321*8975f5c5SAndroid Build Coastguard Worker action = 'android.intent.action.VIEW' 322*8975f5c5SAndroid Build Coastguard Worker 323*8975f5c5SAndroid Build Coastguard Worker def launch(device): 324*8975f5c5SAndroid Build Coastguard Worker activity = _ResolveActivity(device, package_name, category, action) 325*8975f5c5SAndroid Build Coastguard Worker # --persistent is required to have Settings.Global.DEBUG_APP be set, which 326*8975f5c5SAndroid Build Coastguard Worker # we currently use to allow reading of flags. https://crbug.com/784947 327*8975f5c5SAndroid Build Coastguard Worker if not nokill: 328*8975f5c5SAndroid Build Coastguard Worker cmd = ['am', 'set-debug-app', '--persistent', debug_process_name] 329*8975f5c5SAndroid Build Coastguard Worker if wait_for_java_debugger: 330*8975f5c5SAndroid Build Coastguard Worker cmd[-1:-1] = ['-w'] 331*8975f5c5SAndroid Build Coastguard Worker # Ignore error since it will fail if apk is not debuggable. 332*8975f5c5SAndroid Build Coastguard Worker device.RunShellCommand(cmd, check_return=False) 333*8975f5c5SAndroid Build Coastguard Worker 334*8975f5c5SAndroid Build Coastguard Worker # The flags are first updated with input args. 335*8975f5c5SAndroid Build Coastguard Worker _UpdateDeviceFlags(device, command_line_flags_file, argv) 336*8975f5c5SAndroid Build Coastguard Worker 337*8975f5c5SAndroid Build Coastguard Worker launch_intent = intent.Intent(action=action, 338*8975f5c5SAndroid Build Coastguard Worker activity=activity, 339*8975f5c5SAndroid Build Coastguard Worker data=url, 340*8975f5c5SAndroid Build Coastguard Worker package=package_name) 341*8975f5c5SAndroid Build Coastguard Worker logging.info('Sending launch intent for %s', activity) 342*8975f5c5SAndroid Build Coastguard Worker device.StartActivity(launch_intent) 343*8975f5c5SAndroid Build Coastguard Worker 344*8975f5c5SAndroid Build Coastguard Worker device_utils.DeviceUtils.parallel(devices).pMap(launch) 345*8975f5c5SAndroid Build Coastguard Worker if wait_for_java_debugger: 346*8975f5c5SAndroid Build Coastguard Worker print('Waiting for debugger to attach to process: ' + 347*8975f5c5SAndroid Build Coastguard Worker _Colorize(debug_process_name, colorama.Fore.YELLOW)) 348*8975f5c5SAndroid Build Coastguard Worker 349*8975f5c5SAndroid Build Coastguard Worker 350*8975f5c5SAndroid Build Coastguard Workerdef _TargetCpuToTargetArch(target_cpu): 351*8975f5c5SAndroid Build Coastguard Worker if target_cpu == 'x64': 352*8975f5c5SAndroid Build Coastguard Worker return 'x86_64' 353*8975f5c5SAndroid Build Coastguard Worker if target_cpu == 'mipsel': 354*8975f5c5SAndroid Build Coastguard Worker return 'mips' 355*8975f5c5SAndroid Build Coastguard Worker return target_cpu 356*8975f5c5SAndroid Build Coastguard Worker 357*8975f5c5SAndroid Build Coastguard Worker 358*8975f5c5SAndroid Build Coastguard Workerdef _RunGdb(device, package_name, debug_process_name, pid, output_directory, 359*8975f5c5SAndroid Build Coastguard Worker target_cpu, port, ide, verbose): 360*8975f5c5SAndroid Build Coastguard Worker if not pid: 361*8975f5c5SAndroid Build Coastguard Worker debug_process_name = _NormalizeProcessName(debug_process_name, package_name) 362*8975f5c5SAndroid Build Coastguard Worker pid = device.GetApplicationPids(debug_process_name, at_most_one=True) 363*8975f5c5SAndroid Build Coastguard Worker if not pid: 364*8975f5c5SAndroid Build Coastguard Worker # Attaching gdb makes the app run so slow that it takes *minutes* to start 365*8975f5c5SAndroid Build Coastguard Worker # up (as of 2018). Better to just fail than to start & attach. 366*8975f5c5SAndroid Build Coastguard Worker raise Exception('App not running.') 367*8975f5c5SAndroid Build Coastguard Worker 368*8975f5c5SAndroid Build Coastguard Worker gdb_script_path = os.path.dirname(__file__) + '/adb_gdb' 369*8975f5c5SAndroid Build Coastguard Worker cmd = [ 370*8975f5c5SAndroid Build Coastguard Worker gdb_script_path, 371*8975f5c5SAndroid Build Coastguard Worker '--package-name=%s' % package_name, 372*8975f5c5SAndroid Build Coastguard Worker '--output-directory=%s' % output_directory, 373*8975f5c5SAndroid Build Coastguard Worker '--adb=%s' % adb_wrapper.AdbWrapper.GetAdbPath(), 374*8975f5c5SAndroid Build Coastguard Worker '--device=%s' % device.serial, 375*8975f5c5SAndroid Build Coastguard Worker '--pid=%s' % pid, 376*8975f5c5SAndroid Build Coastguard Worker '--port=%d' % port, 377*8975f5c5SAndroid Build Coastguard Worker ] 378*8975f5c5SAndroid Build Coastguard Worker if ide: 379*8975f5c5SAndroid Build Coastguard Worker cmd.append('--ide') 380*8975f5c5SAndroid Build Coastguard Worker # Enable verbose output of adb_gdb if it's set for this script. 381*8975f5c5SAndroid Build Coastguard Worker if verbose: 382*8975f5c5SAndroid Build Coastguard Worker cmd.append('--verbose') 383*8975f5c5SAndroid Build Coastguard Worker if target_cpu: 384*8975f5c5SAndroid Build Coastguard Worker cmd.append('--target-arch=%s' % _TargetCpuToTargetArch(target_cpu)) 385*8975f5c5SAndroid Build Coastguard Worker logging.warning('Running: %s', ' '.join(shlex.quote(x) for x in cmd)) 386*8975f5c5SAndroid Build Coastguard Worker print(_Colorize('All subsequent output is from adb_gdb script.', 387*8975f5c5SAndroid Build Coastguard Worker colorama.Fore.YELLOW)) 388*8975f5c5SAndroid Build Coastguard Worker os.execv(gdb_script_path, cmd) 389*8975f5c5SAndroid Build Coastguard Worker 390*8975f5c5SAndroid Build Coastguard Worker 391*8975f5c5SAndroid Build Coastguard Workerdef _RunLldb(device, 392*8975f5c5SAndroid Build Coastguard Worker package_name, 393*8975f5c5SAndroid Build Coastguard Worker debug_process_name, 394*8975f5c5SAndroid Build Coastguard Worker pid, 395*8975f5c5SAndroid Build Coastguard Worker output_directory, 396*8975f5c5SAndroid Build Coastguard Worker port, 397*8975f5c5SAndroid Build Coastguard Worker target_cpu=None, 398*8975f5c5SAndroid Build Coastguard Worker ndk_dir=None, 399*8975f5c5SAndroid Build Coastguard Worker lldb_server=None, 400*8975f5c5SAndroid Build Coastguard Worker lldb=None, 401*8975f5c5SAndroid Build Coastguard Worker verbose=None): 402*8975f5c5SAndroid Build Coastguard Worker if not pid: 403*8975f5c5SAndroid Build Coastguard Worker debug_process_name = _NormalizeProcessName(debug_process_name, package_name) 404*8975f5c5SAndroid Build Coastguard Worker pid = device.GetApplicationPids(debug_process_name, at_most_one=True) 405*8975f5c5SAndroid Build Coastguard Worker if not pid: 406*8975f5c5SAndroid Build Coastguard Worker # Attaching lldb makes the app run so slow that it takes *minutes* to start 407*8975f5c5SAndroid Build Coastguard Worker # up (as of 2018). Better to just fail than to start & attach. 408*8975f5c5SAndroid Build Coastguard Worker raise Exception('App not running.') 409*8975f5c5SAndroid Build Coastguard Worker 410*8975f5c5SAndroid Build Coastguard Worker lldb_script_path = os.path.dirname(__file__) + '/connect_lldb.sh' 411*8975f5c5SAndroid Build Coastguard Worker cmd = [ 412*8975f5c5SAndroid Build Coastguard Worker lldb_script_path, 413*8975f5c5SAndroid Build Coastguard Worker '--package-name=%s' % package_name, 414*8975f5c5SAndroid Build Coastguard Worker '--output-directory=%s' % output_directory, 415*8975f5c5SAndroid Build Coastguard Worker '--adb=%s' % adb_wrapper.AdbWrapper.GetAdbPath(), 416*8975f5c5SAndroid Build Coastguard Worker '--device=%s' % device.serial, 417*8975f5c5SAndroid Build Coastguard Worker '--pid=%s' % pid, 418*8975f5c5SAndroid Build Coastguard Worker '--port=%d' % port, 419*8975f5c5SAndroid Build Coastguard Worker ] 420*8975f5c5SAndroid Build Coastguard Worker # Enable verbose output of connect_lldb.sh if it's set for this script. 421*8975f5c5SAndroid Build Coastguard Worker if verbose: 422*8975f5c5SAndroid Build Coastguard Worker cmd.append('--verbose') 423*8975f5c5SAndroid Build Coastguard Worker if target_cpu: 424*8975f5c5SAndroid Build Coastguard Worker cmd.append('--target-arch=%s' % _TargetCpuToTargetArch(target_cpu)) 425*8975f5c5SAndroid Build Coastguard Worker if ndk_dir: 426*8975f5c5SAndroid Build Coastguard Worker cmd.append('--ndk-dir=%s' % ndk_dir) 427*8975f5c5SAndroid Build Coastguard Worker if lldb_server: 428*8975f5c5SAndroid Build Coastguard Worker cmd.append('--lldb-server=%s' % lldb_server) 429*8975f5c5SAndroid Build Coastguard Worker if lldb: 430*8975f5c5SAndroid Build Coastguard Worker cmd.append('--lldb=%s' % lldb) 431*8975f5c5SAndroid Build Coastguard Worker logging.warning('Running: %s', ' '.join(shlex.quote(x) for x in cmd)) 432*8975f5c5SAndroid Build Coastguard Worker print( 433*8975f5c5SAndroid Build Coastguard Worker _Colorize('All subsequent output is from connect_lldb.sh script.', 434*8975f5c5SAndroid Build Coastguard Worker colorama.Fore.YELLOW)) 435*8975f5c5SAndroid Build Coastguard Worker os.execv(lldb_script_path, cmd) 436*8975f5c5SAndroid Build Coastguard Worker 437*8975f5c5SAndroid Build Coastguard Worker 438*8975f5c5SAndroid Build Coastguard Workerdef _PrintPerDeviceOutput(devices, results, single_line=False): 439*8975f5c5SAndroid Build Coastguard Worker for d, result in zip(devices, results): 440*8975f5c5SAndroid Build Coastguard Worker if not single_line and d is not devices[0]: 441*8975f5c5SAndroid Build Coastguard Worker sys.stdout.write('\n') 442*8975f5c5SAndroid Build Coastguard Worker sys.stdout.write( 443*8975f5c5SAndroid Build Coastguard Worker _Colorize('{} ({}):'.format(d, d.build_description), 444*8975f5c5SAndroid Build Coastguard Worker colorama.Fore.YELLOW)) 445*8975f5c5SAndroid Build Coastguard Worker sys.stdout.write(' ' if single_line else '\n') 446*8975f5c5SAndroid Build Coastguard Worker yield result 447*8975f5c5SAndroid Build Coastguard Worker 448*8975f5c5SAndroid Build Coastguard Worker 449*8975f5c5SAndroid Build Coastguard Workerdef _RunMemUsage(devices, package_name, query_app=False): 450*8975f5c5SAndroid Build Coastguard Worker cmd_args = ['dumpsys', 'meminfo'] 451*8975f5c5SAndroid Build Coastguard Worker if not query_app: 452*8975f5c5SAndroid Build Coastguard Worker cmd_args.append('--local') 453*8975f5c5SAndroid Build Coastguard Worker 454*8975f5c5SAndroid Build Coastguard Worker def mem_usage_helper(d): 455*8975f5c5SAndroid Build Coastguard Worker ret = [] 456*8975f5c5SAndroid Build Coastguard Worker for process in sorted(_GetPackageProcesses(d, package_name)): 457*8975f5c5SAndroid Build Coastguard Worker meminfo = d.RunShellCommand(cmd_args + [str(process.pid)]) 458*8975f5c5SAndroid Build Coastguard Worker ret.append((process.name, '\n'.join(meminfo))) 459*8975f5c5SAndroid Build Coastguard Worker return ret 460*8975f5c5SAndroid Build Coastguard Worker 461*8975f5c5SAndroid Build Coastguard Worker parallel_devices = device_utils.DeviceUtils.parallel(devices) 462*8975f5c5SAndroid Build Coastguard Worker all_results = parallel_devices.pMap(mem_usage_helper).pGet(None) 463*8975f5c5SAndroid Build Coastguard Worker for result in _PrintPerDeviceOutput(devices, all_results): 464*8975f5c5SAndroid Build Coastguard Worker if not result: 465*8975f5c5SAndroid Build Coastguard Worker print('No processes found.') 466*8975f5c5SAndroid Build Coastguard Worker else: 467*8975f5c5SAndroid Build Coastguard Worker for name, usage in sorted(result): 468*8975f5c5SAndroid Build Coastguard Worker print(_Colorize('==== Output of "dumpsys meminfo %s" ====' % name, 469*8975f5c5SAndroid Build Coastguard Worker colorama.Fore.GREEN)) 470*8975f5c5SAndroid Build Coastguard Worker print(usage) 471*8975f5c5SAndroid Build Coastguard Worker 472*8975f5c5SAndroid Build Coastguard Worker 473*8975f5c5SAndroid Build Coastguard Workerdef _DuHelper(device, path_spec, run_as=None): 474*8975f5c5SAndroid Build Coastguard Worker """Runs "du -s -k |path_spec|" on |device| and returns parsed result. 475*8975f5c5SAndroid Build Coastguard Worker 476*8975f5c5SAndroid Build Coastguard Worker Args: 477*8975f5c5SAndroid Build Coastguard Worker device: A DeviceUtils instance. 478*8975f5c5SAndroid Build Coastguard Worker path_spec: The list of paths to run du on. May contain shell expansions 479*8975f5c5SAndroid Build Coastguard Worker (will not be escaped). 480*8975f5c5SAndroid Build Coastguard Worker run_as: Package name to run as, or None to run as shell user. If not None 481*8975f5c5SAndroid Build Coastguard Worker and app is not android:debuggable (run-as fails), then command will be 482*8975f5c5SAndroid Build Coastguard Worker run as root. 483*8975f5c5SAndroid Build Coastguard Worker 484*8975f5c5SAndroid Build Coastguard Worker Returns: 485*8975f5c5SAndroid Build Coastguard Worker A dict of path->size in KiB containing all paths in |path_spec| that exist 486*8975f5c5SAndroid Build Coastguard Worker on device. Paths that do not exist are silently ignored. 487*8975f5c5SAndroid Build Coastguard Worker """ 488*8975f5c5SAndroid Build Coastguard Worker # Example output for: du -s -k /data/data/org.chromium.chrome/{*,.*} 489*8975f5c5SAndroid Build Coastguard Worker # 144 /data/data/org.chromium.chrome/cache 490*8975f5c5SAndroid Build Coastguard Worker # 8 /data/data/org.chromium.chrome/files 491*8975f5c5SAndroid Build Coastguard Worker # <snip> 492*8975f5c5SAndroid Build Coastguard Worker # du: .*: No such file or directory 493*8975f5c5SAndroid Build Coastguard Worker 494*8975f5c5SAndroid Build Coastguard Worker # The -d flag works differently across android version, so use -s instead. 495*8975f5c5SAndroid Build Coastguard Worker # Without the explicit 2>&1, stderr and stdout get combined at random :(. 496*8975f5c5SAndroid Build Coastguard Worker cmd_str = 'du -s -k ' + path_spec + ' 2>&1' 497*8975f5c5SAndroid Build Coastguard Worker lines = device.RunShellCommand(cmd_str, run_as=run_as, shell=True, 498*8975f5c5SAndroid Build Coastguard Worker check_return=False) 499*8975f5c5SAndroid Build Coastguard Worker output = '\n'.join(lines) 500*8975f5c5SAndroid Build Coastguard Worker # run-as: Package 'com.android.chrome' is not debuggable 501*8975f5c5SAndroid Build Coastguard Worker if output.startswith('run-as:'): 502*8975f5c5SAndroid Build Coastguard Worker # check_return=False needed for when some paths in path_spec do not exist. 503*8975f5c5SAndroid Build Coastguard Worker lines = device.RunShellCommand(cmd_str, as_root=True, shell=True, 504*8975f5c5SAndroid Build Coastguard Worker check_return=False) 505*8975f5c5SAndroid Build Coastguard Worker ret = {} 506*8975f5c5SAndroid Build Coastguard Worker try: 507*8975f5c5SAndroid Build Coastguard Worker for line in lines: 508*8975f5c5SAndroid Build Coastguard Worker # du: .*: No such file or directory 509*8975f5c5SAndroid Build Coastguard Worker if line.startswith('du:'): 510*8975f5c5SAndroid Build Coastguard Worker continue 511*8975f5c5SAndroid Build Coastguard Worker size, subpath = line.split(None, 1) 512*8975f5c5SAndroid Build Coastguard Worker ret[subpath] = int(size) 513*8975f5c5SAndroid Build Coastguard Worker return ret 514*8975f5c5SAndroid Build Coastguard Worker except ValueError: 515*8975f5c5SAndroid Build Coastguard Worker logging.error('du command was: %s', cmd_str) 516*8975f5c5SAndroid Build Coastguard Worker logging.error('Failed to parse du output:\n%s', output) 517*8975f5c5SAndroid Build Coastguard Worker raise 518*8975f5c5SAndroid Build Coastguard Worker 519*8975f5c5SAndroid Build Coastguard Worker 520*8975f5c5SAndroid Build Coastguard Workerdef _RunDiskUsage(devices, package_name): 521*8975f5c5SAndroid Build Coastguard Worker # Measuring dex size is a bit complicated: 522*8975f5c5SAndroid Build Coastguard Worker # https://source.android.com/devices/tech/dalvik/jit-compiler 523*8975f5c5SAndroid Build Coastguard Worker # 524*8975f5c5SAndroid Build Coastguard Worker # For KitKat and below: 525*8975f5c5SAndroid Build Coastguard Worker # dumpsys package contains: 526*8975f5c5SAndroid Build Coastguard Worker # dataDir=/data/data/org.chromium.chrome 527*8975f5c5SAndroid Build Coastguard Worker # codePath=/data/app/org.chromium.chrome-1.apk 528*8975f5c5SAndroid Build Coastguard Worker # resourcePath=/data/app/org.chromium.chrome-1.apk 529*8975f5c5SAndroid Build Coastguard Worker # nativeLibraryPath=/data/app-lib/org.chromium.chrome-1 530*8975f5c5SAndroid Build Coastguard Worker # To measure odex: 531*8975f5c5SAndroid Build Coastguard Worker # ls -l /data/dalvik-cache/data@[email protected]@classes.dex 532*8975f5c5SAndroid Build Coastguard Worker # 533*8975f5c5SAndroid Build Coastguard Worker # For Android L and M (and maybe for N+ system apps): 534*8975f5c5SAndroid Build Coastguard Worker # dumpsys package contains: 535*8975f5c5SAndroid Build Coastguard Worker # codePath=/data/app/org.chromium.chrome-1 536*8975f5c5SAndroid Build Coastguard Worker # resourcePath=/data/app/org.chromium.chrome-1 537*8975f5c5SAndroid Build Coastguard Worker # legacyNativeLibraryDir=/data/app/org.chromium.chrome-1/lib 538*8975f5c5SAndroid Build Coastguard Worker # To measure odex: 539*8975f5c5SAndroid Build Coastguard Worker # # Option 1: 540*8975f5c5SAndroid Build Coastguard Worker # /data/dalvik-cache/arm/data@[email protected]@[email protected] 541*8975f5c5SAndroid Build Coastguard Worker # /data/dalvik-cache/arm/data@[email protected]@[email protected] 542*8975f5c5SAndroid Build Coastguard Worker # ls -l /data/dalvik-cache/profiles/org.chromium.chrome 543*8975f5c5SAndroid Build Coastguard Worker # (these profiles all appear to be 0 bytes) 544*8975f5c5SAndroid Build Coastguard Worker # # Option 2: 545*8975f5c5SAndroid Build Coastguard Worker # ls -l /data/app/org.chromium.chrome-1/oat/arm/base.odex 546*8975f5c5SAndroid Build Coastguard Worker # 547*8975f5c5SAndroid Build Coastguard Worker # For Android N+: 548*8975f5c5SAndroid Build Coastguard Worker # dumpsys package contains: 549*8975f5c5SAndroid Build Coastguard Worker # dataDir=/data/user/0/org.chromium.chrome 550*8975f5c5SAndroid Build Coastguard Worker # codePath=/data/app/org.chromium.chrome-UuCZ71IE-i5sZgHAkU49_w== 551*8975f5c5SAndroid Build Coastguard Worker # resourcePath=/data/app/org.chromium.chrome-UuCZ71IE-i5sZgHAkU49_w== 552*8975f5c5SAndroid Build Coastguard Worker # legacyNativeLibraryDir=/data/app/org.chromium.chrome-GUID/lib 553*8975f5c5SAndroid Build Coastguard Worker # Instruction Set: arm 554*8975f5c5SAndroid Build Coastguard Worker # path: /data/app/org.chromium.chrome-UuCZ71IE-i5sZgHAkU49_w==/base.apk 555*8975f5c5SAndroid Build Coastguard Worker # status: /data/.../oat/arm/base.odex[status=kOatUpToDate, compilation_f 556*8975f5c5SAndroid Build Coastguard Worker # ilter=quicken] 557*8975f5c5SAndroid Build Coastguard Worker # Instruction Set: arm64 558*8975f5c5SAndroid Build Coastguard Worker # path: /data/app/org.chromium.chrome-UuCZ71IE-i5sZgHAkU49_w==/base.apk 559*8975f5c5SAndroid Build Coastguard Worker # status: /data/.../oat/arm64/base.odex[status=..., compilation_filter=q 560*8975f5c5SAndroid Build Coastguard Worker # uicken] 561*8975f5c5SAndroid Build Coastguard Worker # To measure odex: 562*8975f5c5SAndroid Build Coastguard Worker # ls -l /data/app/.../oat/arm/base.odex 563*8975f5c5SAndroid Build Coastguard Worker # ls -l /data/app/.../oat/arm/base.vdex (optional) 564*8975f5c5SAndroid Build Coastguard Worker # To measure the correct odex size: 565*8975f5c5SAndroid Build Coastguard Worker # cmd package compile -m speed org.chromium.chrome # For webview 566*8975f5c5SAndroid Build Coastguard Worker # cmd package compile -m speed-profile org.chromium.chrome # For others 567*8975f5c5SAndroid Build Coastguard Worker def disk_usage_helper(d): 568*8975f5c5SAndroid Build Coastguard Worker package_output = '\n'.join(d.RunShellCommand( 569*8975f5c5SAndroid Build Coastguard Worker ['dumpsys', 'package', package_name], check_return=True)) 570*8975f5c5SAndroid Build Coastguard Worker # Does not return error when apk is not installed. 571*8975f5c5SAndroid Build Coastguard Worker if not package_output or 'Unable to find package:' in package_output: 572*8975f5c5SAndroid Build Coastguard Worker return None 573*8975f5c5SAndroid Build Coastguard Worker 574*8975f5c5SAndroid Build Coastguard Worker # Ignore system apks that have updates installed. 575*8975f5c5SAndroid Build Coastguard Worker package_output = re.sub(r'Hidden system packages:.*?^\b', '', 576*8975f5c5SAndroid Build Coastguard Worker package_output, flags=re.S | re.M) 577*8975f5c5SAndroid Build Coastguard Worker 578*8975f5c5SAndroid Build Coastguard Worker try: 579*8975f5c5SAndroid Build Coastguard Worker data_dir = re.search(r'dataDir=(.*)', package_output).group(1) 580*8975f5c5SAndroid Build Coastguard Worker code_path = re.search(r'codePath=(.*)', package_output).group(1) 581*8975f5c5SAndroid Build Coastguard Worker lib_path = re.search(r'(?:legacyN|n)ativeLibrary(?:Dir|Path)=(.*)', 582*8975f5c5SAndroid Build Coastguard Worker package_output).group(1) 583*8975f5c5SAndroid Build Coastguard Worker except AttributeError as e: 584*8975f5c5SAndroid Build Coastguard Worker raise Exception('Error parsing dumpsys output: ' + package_output) from e 585*8975f5c5SAndroid Build Coastguard Worker 586*8975f5c5SAndroid Build Coastguard Worker if code_path.startswith('/system'): 587*8975f5c5SAndroid Build Coastguard Worker logging.warning('Measurement of system image apks can be innacurate') 588*8975f5c5SAndroid Build Coastguard Worker 589*8975f5c5SAndroid Build Coastguard Worker compilation_filters = set() 590*8975f5c5SAndroid Build Coastguard Worker # Match "compilation_filter=value", where a line break can occur at any spot 591*8975f5c5SAndroid Build Coastguard Worker # (refer to examples above). 592*8975f5c5SAndroid Build Coastguard Worker awful_wrapping = r'\s*'.join('compilation_filter=') 593*8975f5c5SAndroid Build Coastguard Worker for m in re.finditer(awful_wrapping + r'([\s\S]+?)[\],]', package_output): 594*8975f5c5SAndroid Build Coastguard Worker compilation_filters.add(re.sub(r'\s+', '', m.group(1))) 595*8975f5c5SAndroid Build Coastguard Worker # Starting Android Q, output looks like: 596*8975f5c5SAndroid Build Coastguard Worker # arm: [status=speed-profile] [reason=install] 597*8975f5c5SAndroid Build Coastguard Worker for m in re.finditer(r'\[status=(.+?)\]', package_output): 598*8975f5c5SAndroid Build Coastguard Worker compilation_filters.add(m.group(1)) 599*8975f5c5SAndroid Build Coastguard Worker compilation_filter = ','.join(sorted(compilation_filters)) 600*8975f5c5SAndroid Build Coastguard Worker 601*8975f5c5SAndroid Build Coastguard Worker data_dir_sizes = _DuHelper(d, '%s/{*,.*}' % data_dir, run_as=package_name) 602*8975f5c5SAndroid Build Coastguard Worker # Measure code_cache separately since it can be large. 603*8975f5c5SAndroid Build Coastguard Worker code_cache_sizes = {} 604*8975f5c5SAndroid Build Coastguard Worker code_cache_dir = next( 605*8975f5c5SAndroid Build Coastguard Worker (k for k in data_dir_sizes if k.endswith('/code_cache')), None) 606*8975f5c5SAndroid Build Coastguard Worker if code_cache_dir: 607*8975f5c5SAndroid Build Coastguard Worker data_dir_sizes.pop(code_cache_dir) 608*8975f5c5SAndroid Build Coastguard Worker code_cache_sizes = _DuHelper(d, '%s/{*,.*}' % code_cache_dir, 609*8975f5c5SAndroid Build Coastguard Worker run_as=package_name) 610*8975f5c5SAndroid Build Coastguard Worker 611*8975f5c5SAndroid Build Coastguard Worker apk_path_spec = code_path 612*8975f5c5SAndroid Build Coastguard Worker if not apk_path_spec.endswith('.apk'): 613*8975f5c5SAndroid Build Coastguard Worker apk_path_spec += '/*.apk' 614*8975f5c5SAndroid Build Coastguard Worker apk_sizes = _DuHelper(d, apk_path_spec) 615*8975f5c5SAndroid Build Coastguard Worker if lib_path.endswith('/lib'): 616*8975f5c5SAndroid Build Coastguard Worker # Shows architecture subdirectory. 617*8975f5c5SAndroid Build Coastguard Worker lib_sizes = _DuHelper(d, '%s/{*,.*}' % lib_path) 618*8975f5c5SAndroid Build Coastguard Worker else: 619*8975f5c5SAndroid Build Coastguard Worker lib_sizes = _DuHelper(d, lib_path) 620*8975f5c5SAndroid Build Coastguard Worker 621*8975f5c5SAndroid Build Coastguard Worker # Look at all possible locations for odex files. 622*8975f5c5SAndroid Build Coastguard Worker odex_paths = [] 623*8975f5c5SAndroid Build Coastguard Worker for apk_path in apk_sizes: 624*8975f5c5SAndroid Build Coastguard Worker mangled_apk_path = apk_path[1:].replace('/', '@') 625*8975f5c5SAndroid Build Coastguard Worker apk_basename = posixpath.basename(apk_path)[:-4] 626*8975f5c5SAndroid Build Coastguard Worker for ext in ('dex', 'odex', 'vdex', 'art'): 627*8975f5c5SAndroid Build Coastguard Worker # Easier to check all architectures than to determine active ones. 628*8975f5c5SAndroid Build Coastguard Worker for arch in ('arm', 'arm64', 'x86', 'x86_64', 'mips', 'mips64'): 629*8975f5c5SAndroid Build Coastguard Worker odex_paths.append( 630*8975f5c5SAndroid Build Coastguard Worker '%s/oat/%s/%s.%s' % (code_path, arch, apk_basename, ext)) 631*8975f5c5SAndroid Build Coastguard Worker # No app could possibly have more than 6 dex files. 632*8975f5c5SAndroid Build Coastguard Worker for suffix in ('', '2', '3', '4', '5'): 633*8975f5c5SAndroid Build Coastguard Worker odex_paths.append('/data/dalvik-cache/%s/%s@classes%s.%s' % ( 634*8975f5c5SAndroid Build Coastguard Worker arch, mangled_apk_path, suffix, ext)) 635*8975f5c5SAndroid Build Coastguard Worker # This path does not have |arch|, so don't repeat it for every arch. 636*8975f5c5SAndroid Build Coastguard Worker if arch == 'arm': 637*8975f5c5SAndroid Build Coastguard Worker odex_paths.append('/data/dalvik-cache/%s@classes%s.dex' % ( 638*8975f5c5SAndroid Build Coastguard Worker mangled_apk_path, suffix)) 639*8975f5c5SAndroid Build Coastguard Worker 640*8975f5c5SAndroid Build Coastguard Worker odex_sizes = _DuHelper(d, ' '.join(shlex.quote(p) for p in odex_paths)) 641*8975f5c5SAndroid Build Coastguard Worker 642*8975f5c5SAndroid Build Coastguard Worker return (data_dir_sizes, code_cache_sizes, apk_sizes, lib_sizes, odex_sizes, 643*8975f5c5SAndroid Build Coastguard Worker compilation_filter) 644*8975f5c5SAndroid Build Coastguard Worker 645*8975f5c5SAndroid Build Coastguard Worker def print_sizes(desc, sizes): 646*8975f5c5SAndroid Build Coastguard Worker print('%s: %d KiB' % (desc, sum(sizes.values()))) 647*8975f5c5SAndroid Build Coastguard Worker for path, size in sorted(sizes.items()): 648*8975f5c5SAndroid Build Coastguard Worker print(' %s: %s KiB' % (path, size)) 649*8975f5c5SAndroid Build Coastguard Worker 650*8975f5c5SAndroid Build Coastguard Worker parallel_devices = device_utils.DeviceUtils.parallel(devices) 651*8975f5c5SAndroid Build Coastguard Worker all_results = parallel_devices.pMap(disk_usage_helper).pGet(None) 652*8975f5c5SAndroid Build Coastguard Worker for result in _PrintPerDeviceOutput(devices, all_results): 653*8975f5c5SAndroid Build Coastguard Worker if not result: 654*8975f5c5SAndroid Build Coastguard Worker print('APK is not installed.') 655*8975f5c5SAndroid Build Coastguard Worker continue 656*8975f5c5SAndroid Build Coastguard Worker 657*8975f5c5SAndroid Build Coastguard Worker (data_dir_sizes, code_cache_sizes, apk_sizes, lib_sizes, odex_sizes, 658*8975f5c5SAndroid Build Coastguard Worker compilation_filter) = result 659*8975f5c5SAndroid Build Coastguard Worker total = sum(sum(sizes.values()) for sizes in result[:-1]) 660*8975f5c5SAndroid Build Coastguard Worker 661*8975f5c5SAndroid Build Coastguard Worker print_sizes('Apk', apk_sizes) 662*8975f5c5SAndroid Build Coastguard Worker print_sizes('App Data (non-code cache)', data_dir_sizes) 663*8975f5c5SAndroid Build Coastguard Worker print_sizes('App Data (code cache)', code_cache_sizes) 664*8975f5c5SAndroid Build Coastguard Worker print_sizes('Native Libs', lib_sizes) 665*8975f5c5SAndroid Build Coastguard Worker show_warning = compilation_filter and 'speed' not in compilation_filter 666*8975f5c5SAndroid Build Coastguard Worker compilation_filter = compilation_filter or 'n/a' 667*8975f5c5SAndroid Build Coastguard Worker print_sizes('odex (compilation_filter=%s)' % compilation_filter, odex_sizes) 668*8975f5c5SAndroid Build Coastguard Worker if show_warning: 669*8975f5c5SAndroid Build Coastguard Worker logging.warning('For a more realistic odex size, run:') 670*8975f5c5SAndroid Build Coastguard Worker logging.warning(' %s compile-dex [speed|speed-profile]', sys.argv[0]) 671*8975f5c5SAndroid Build Coastguard Worker print('Total: %s KiB (%.1f MiB)' % (total, total / 1024.0)) 672*8975f5c5SAndroid Build Coastguard Worker 673*8975f5c5SAndroid Build Coastguard Worker 674*8975f5c5SAndroid Build Coastguard Workerclass _LogcatProcessor: 675*8975f5c5SAndroid Build Coastguard Worker ParsedLine = collections.namedtuple( 676*8975f5c5SAndroid Build Coastguard Worker 'ParsedLine', 677*8975f5c5SAndroid Build Coastguard Worker ['date', 'invokation_time', 'pid', 'tid', 'priority', 'tag', 'message']) 678*8975f5c5SAndroid Build Coastguard Worker 679*8975f5c5SAndroid Build Coastguard Worker class NativeStackSymbolizer: 680*8975f5c5SAndroid Build Coastguard Worker """Buffers lines from native stacks and symbolizes them when done.""" 681*8975f5c5SAndroid Build Coastguard Worker # E.g.: #06 pc 0x0000d519 /apex/com.android.runtime/lib/libart.so 682*8975f5c5SAndroid Build Coastguard Worker # E.g.: #01 pc 00180c8d /data/data/.../lib/libbase.cr.so 683*8975f5c5SAndroid Build Coastguard Worker _STACK_PATTERN = re.compile(r'\s*#\d+\s+(?:pc )?(0x)?[0-9a-f]{8,16}\s') 684*8975f5c5SAndroid Build Coastguard Worker 685*8975f5c5SAndroid Build Coastguard Worker def __init__(self, stack_script_context, print_func): 686*8975f5c5SAndroid Build Coastguard Worker # To symbolize native stacks, we need to pass all lines at once. 687*8975f5c5SAndroid Build Coastguard Worker self._stack_script_context = stack_script_context 688*8975f5c5SAndroid Build Coastguard Worker self._print_func = print_func 689*8975f5c5SAndroid Build Coastguard Worker self._crash_lines_buffer = None 690*8975f5c5SAndroid Build Coastguard Worker 691*8975f5c5SAndroid Build Coastguard Worker def _FlushLines(self): 692*8975f5c5SAndroid Build Coastguard Worker """Prints queued lines after sending them through stack.py.""" 693*8975f5c5SAndroid Build Coastguard Worker if self._crash_lines_buffer is None: 694*8975f5c5SAndroid Build Coastguard Worker return 695*8975f5c5SAndroid Build Coastguard Worker 696*8975f5c5SAndroid Build Coastguard Worker crash_lines = self._crash_lines_buffer 697*8975f5c5SAndroid Build Coastguard Worker self._crash_lines_buffer = None 698*8975f5c5SAndroid Build Coastguard Worker with tempfile.NamedTemporaryFile(mode='w') as f: 699*8975f5c5SAndroid Build Coastguard Worker f.writelines(x[0].message + '\n' for x in crash_lines) 700*8975f5c5SAndroid Build Coastguard Worker f.flush() 701*8975f5c5SAndroid Build Coastguard Worker proc = self._stack_script_context.Popen( 702*8975f5c5SAndroid Build Coastguard Worker input_file=f.name, stdout=subprocess.PIPE) 703*8975f5c5SAndroid Build Coastguard Worker lines = proc.communicate()[0].splitlines() 704*8975f5c5SAndroid Build Coastguard Worker 705*8975f5c5SAndroid Build Coastguard Worker for i, line in enumerate(lines): 706*8975f5c5SAndroid Build Coastguard Worker parsed_line, dim = crash_lines[min(i, len(crash_lines) - 1)] 707*8975f5c5SAndroid Build Coastguard Worker d = parsed_line._asdict() 708*8975f5c5SAndroid Build Coastguard Worker d['message'] = line 709*8975f5c5SAndroid Build Coastguard Worker parsed_line = _LogcatProcessor.ParsedLine(**d) 710*8975f5c5SAndroid Build Coastguard Worker self._print_func(parsed_line, dim) 711*8975f5c5SAndroid Build Coastguard Worker 712*8975f5c5SAndroid Build Coastguard Worker def AddLine(self, parsed_line, dim): 713*8975f5c5SAndroid Build Coastguard Worker # Assume all lines from DEBUG are stacks. 714*8975f5c5SAndroid Build Coastguard Worker # Also look for "stack-looking" lines to catch manual stack prints. 715*8975f5c5SAndroid Build Coastguard Worker # It's important to not buffer non-stack lines because stack.py does not 716*8975f5c5SAndroid Build Coastguard Worker # pass them through. 717*8975f5c5SAndroid Build Coastguard Worker is_crash_line = parsed_line.tag == 'DEBUG' or (self._STACK_PATTERN.match( 718*8975f5c5SAndroid Build Coastguard Worker parsed_line.message)) 719*8975f5c5SAndroid Build Coastguard Worker 720*8975f5c5SAndroid Build Coastguard Worker if is_crash_line: 721*8975f5c5SAndroid Build Coastguard Worker if self._crash_lines_buffer is None: 722*8975f5c5SAndroid Build Coastguard Worker self._crash_lines_buffer = [] 723*8975f5c5SAndroid Build Coastguard Worker self._crash_lines_buffer.append((parsed_line, dim)) 724*8975f5c5SAndroid Build Coastguard Worker return 725*8975f5c5SAndroid Build Coastguard Worker 726*8975f5c5SAndroid Build Coastguard Worker self._FlushLines() 727*8975f5c5SAndroid Build Coastguard Worker 728*8975f5c5SAndroid Build Coastguard Worker self._print_func(parsed_line, dim) 729*8975f5c5SAndroid Build Coastguard Worker 730*8975f5c5SAndroid Build Coastguard Worker 731*8975f5c5SAndroid Build Coastguard Worker # Logcat tags for messages that are generally relevant but are not from PIDs 732*8975f5c5SAndroid Build Coastguard Worker # associated with the apk. 733*8975f5c5SAndroid Build Coastguard Worker _ALLOWLISTED_TAGS = { 734*8975f5c5SAndroid Build Coastguard Worker 'ActivityManager', # Shows activity lifecycle messages. 735*8975f5c5SAndroid Build Coastguard Worker 'ActivityTaskManager', # More activity lifecycle messages. 736*8975f5c5SAndroid Build Coastguard Worker 'AndroidRuntime', # Java crash dumps 737*8975f5c5SAndroid Build Coastguard Worker 'AppZygoteInit', # Android's native application zygote support. 738*8975f5c5SAndroid Build Coastguard Worker 'DEBUG', # Native crash dump. 739*8975f5c5SAndroid Build Coastguard Worker } 740*8975f5c5SAndroid Build Coastguard Worker 741*8975f5c5SAndroid Build Coastguard Worker # Matches messages only on pre-L (Dalvik) that are spammy and unimportant. 742*8975f5c5SAndroid Build Coastguard Worker _DALVIK_IGNORE_PATTERN = re.compile('|'.join([ 743*8975f5c5SAndroid Build Coastguard Worker r'^Added shared lib', 744*8975f5c5SAndroid Build Coastguard Worker r'^Could not find ', 745*8975f5c5SAndroid Build Coastguard Worker r'^DexOpt:', 746*8975f5c5SAndroid Build Coastguard Worker r'^GC_', 747*8975f5c5SAndroid Build Coastguard Worker r'^Late-enabling CheckJNI', 748*8975f5c5SAndroid Build Coastguard Worker r'^Link of class', 749*8975f5c5SAndroid Build Coastguard Worker r'^No JNI_OnLoad found in', 750*8975f5c5SAndroid Build Coastguard Worker r'^Trying to load lib', 751*8975f5c5SAndroid Build Coastguard Worker r'^Unable to resolve superclass', 752*8975f5c5SAndroid Build Coastguard Worker r'^VFY:', 753*8975f5c5SAndroid Build Coastguard Worker r'^WAIT_', 754*8975f5c5SAndroid Build Coastguard Worker ])) 755*8975f5c5SAndroid Build Coastguard Worker 756*8975f5c5SAndroid Build Coastguard Worker def __init__(self, 757*8975f5c5SAndroid Build Coastguard Worker device, 758*8975f5c5SAndroid Build Coastguard Worker package_name, 759*8975f5c5SAndroid Build Coastguard Worker stack_script_context, 760*8975f5c5SAndroid Build Coastguard Worker deobfuscate=None, 761*8975f5c5SAndroid Build Coastguard Worker verbose=False, 762*8975f5c5SAndroid Build Coastguard Worker exit_on_match=None, 763*8975f5c5SAndroid Build Coastguard Worker extra_package_names=None): 764*8975f5c5SAndroid Build Coastguard Worker self._device = device 765*8975f5c5SAndroid Build Coastguard Worker self._package_name = package_name 766*8975f5c5SAndroid Build Coastguard Worker self._extra_package_names = extra_package_names or [] 767*8975f5c5SAndroid Build Coastguard Worker self._verbose = verbose 768*8975f5c5SAndroid Build Coastguard Worker self._deobfuscator = deobfuscate 769*8975f5c5SAndroid Build Coastguard Worker if exit_on_match is not None: 770*8975f5c5SAndroid Build Coastguard Worker self._exit_on_match = re.compile(exit_on_match) 771*8975f5c5SAndroid Build Coastguard Worker else: 772*8975f5c5SAndroid Build Coastguard Worker self._exit_on_match = None 773*8975f5c5SAndroid Build Coastguard Worker self._found_exit_match = False 774*8975f5c5SAndroid Build Coastguard Worker if stack_script_context: 775*8975f5c5SAndroid Build Coastguard Worker self._print_func = _LogcatProcessor.NativeStackSymbolizer( 776*8975f5c5SAndroid Build Coastguard Worker stack_script_context, self._PrintParsedLine).AddLine 777*8975f5c5SAndroid Build Coastguard Worker else: 778*8975f5c5SAndroid Build Coastguard Worker self._print_func = self._PrintParsedLine 779*8975f5c5SAndroid Build Coastguard Worker # Process ID for the app's main process (with no :name suffix). 780*8975f5c5SAndroid Build Coastguard Worker self._primary_pid = None 781*8975f5c5SAndroid Build Coastguard Worker # Set of all Process IDs that belong to the app. 782*8975f5c5SAndroid Build Coastguard Worker self._my_pids = set() 783*8975f5c5SAndroid Build Coastguard Worker # Set of all Process IDs that we've parsed at some point. 784*8975f5c5SAndroid Build Coastguard Worker self._seen_pids = set() 785*8975f5c5SAndroid Build Coastguard Worker # Start proc 22953:com.google.chromeremotedesktop/ 786*8975f5c5SAndroid Build Coastguard Worker self._pid_pattern = re.compile(r'Start proc (\d+):{}/'.format(package_name)) 787*8975f5c5SAndroid Build Coastguard Worker # START u0 {act=android.intent.action.MAIN \ 788*8975f5c5SAndroid Build Coastguard Worker # cat=[android.intent.category.LAUNCHER] \ 789*8975f5c5SAndroid Build Coastguard Worker # flg=0x10000000 pkg=com.google.chromeremotedesktop} from uid 2000 790*8975f5c5SAndroid Build Coastguard Worker self._start_pattern = re.compile(r'START .*(?:cmp|pkg)=' + package_name) 791*8975f5c5SAndroid Build Coastguard Worker 792*8975f5c5SAndroid Build Coastguard Worker self.nonce = 'Chromium apk_operations.py nonce={}'.format(random.random()) 793*8975f5c5SAndroid Build Coastguard Worker # Holds lines buffered on start-up, before we find our nonce message. 794*8975f5c5SAndroid Build Coastguard Worker self._initial_buffered_lines = [] 795*8975f5c5SAndroid Build Coastguard Worker self._UpdateMyPids() 796*8975f5c5SAndroid Build Coastguard Worker # Give preference to PID reported by "ps" over those found from 797*8975f5c5SAndroid Build Coastguard Worker # _start_pattern. There can be multiple "Start proc" messages from prior 798*8975f5c5SAndroid Build Coastguard Worker # runs of the app. 799*8975f5c5SAndroid Build Coastguard Worker self._found_initial_pid = self._primary_pid is not None 800*8975f5c5SAndroid Build Coastguard Worker # Retrieve any additional patterns that are relevant for the User. 801*8975f5c5SAndroid Build Coastguard Worker self._user_defined_highlight = None 802*8975f5c5SAndroid Build Coastguard Worker user_regex = os.environ.get('CHROMIUM_LOGCAT_HIGHLIGHT') 803*8975f5c5SAndroid Build Coastguard Worker if user_regex: 804*8975f5c5SAndroid Build Coastguard Worker self._user_defined_highlight = re.compile(user_regex) 805*8975f5c5SAndroid Build Coastguard Worker if not self._user_defined_highlight: 806*8975f5c5SAndroid Build Coastguard Worker print(_Colorize( 807*8975f5c5SAndroid Build Coastguard Worker 'Rejecting invalid regular expression: {}'.format(user_regex), 808*8975f5c5SAndroid Build Coastguard Worker colorama.Fore.RED + colorama.Style.BRIGHT)) 809*8975f5c5SAndroid Build Coastguard Worker 810*8975f5c5SAndroid Build Coastguard Worker def _UpdateMyPids(self): 811*8975f5c5SAndroid Build Coastguard Worker # We intentionally do not clear self._my_pids to make sure that the 812*8975f5c5SAndroid Build Coastguard Worker # ProcessLine method below also includes lines from processes which may 813*8975f5c5SAndroid Build Coastguard Worker # have already exited. 814*8975f5c5SAndroid Build Coastguard Worker self._primary_pid = None 815*8975f5c5SAndroid Build Coastguard Worker for package_name in [self._package_name] + self._extra_package_names: 816*8975f5c5SAndroid Build Coastguard Worker for process in _GetPackageProcesses(self._device, package_name): 817*8975f5c5SAndroid Build Coastguard Worker # We take only the first "main" process found in order to account for 818*8975f5c5SAndroid Build Coastguard Worker # possibly forked() processes. 819*8975f5c5SAndroid Build Coastguard Worker if ':' not in process.name and self._primary_pid is None: 820*8975f5c5SAndroid Build Coastguard Worker self._primary_pid = process.pid 821*8975f5c5SAndroid Build Coastguard Worker self._my_pids.add(process.pid) 822*8975f5c5SAndroid Build Coastguard Worker 823*8975f5c5SAndroid Build Coastguard Worker def _GetPidStyle(self, pid, dim=False): 824*8975f5c5SAndroid Build Coastguard Worker if pid == self._primary_pid: 825*8975f5c5SAndroid Build Coastguard Worker return colorama.Fore.WHITE 826*8975f5c5SAndroid Build Coastguard Worker if pid in self._my_pids: 827*8975f5c5SAndroid Build Coastguard Worker # TODO(wnwen): Use one separate persistent color per process, pop LRU 828*8975f5c5SAndroid Build Coastguard Worker return colorama.Fore.YELLOW 829*8975f5c5SAndroid Build Coastguard Worker if dim: 830*8975f5c5SAndroid Build Coastguard Worker return colorama.Style.DIM 831*8975f5c5SAndroid Build Coastguard Worker return '' 832*8975f5c5SAndroid Build Coastguard Worker 833*8975f5c5SAndroid Build Coastguard Worker def _GetPriorityStyle(self, priority, dim=False): 834*8975f5c5SAndroid Build Coastguard Worker # pylint:disable=no-self-use 835*8975f5c5SAndroid Build Coastguard Worker if dim: 836*8975f5c5SAndroid Build Coastguard Worker return '' 837*8975f5c5SAndroid Build Coastguard Worker style = colorama.Fore.BLACK 838*8975f5c5SAndroid Build Coastguard Worker if priority in ('E', 'F'): 839*8975f5c5SAndroid Build Coastguard Worker style += colorama.Back.RED 840*8975f5c5SAndroid Build Coastguard Worker elif priority == 'W': 841*8975f5c5SAndroid Build Coastguard Worker style += colorama.Back.YELLOW 842*8975f5c5SAndroid Build Coastguard Worker elif priority == 'I': 843*8975f5c5SAndroid Build Coastguard Worker style += colorama.Back.GREEN 844*8975f5c5SAndroid Build Coastguard Worker elif priority == 'D': 845*8975f5c5SAndroid Build Coastguard Worker style += colorama.Back.BLUE 846*8975f5c5SAndroid Build Coastguard Worker return style 847*8975f5c5SAndroid Build Coastguard Worker 848*8975f5c5SAndroid Build Coastguard Worker def _ParseLine(self, line): 849*8975f5c5SAndroid Build Coastguard Worker tokens = line.split(None, 6) 850*8975f5c5SAndroid Build Coastguard Worker 851*8975f5c5SAndroid Build Coastguard Worker def consume_token_or_default(default): 852*8975f5c5SAndroid Build Coastguard Worker return tokens.pop(0) if len(tokens) > 0 else default 853*8975f5c5SAndroid Build Coastguard Worker 854*8975f5c5SAndroid Build Coastguard Worker def consume_integer_token_or_default(default): 855*8975f5c5SAndroid Build Coastguard Worker if len(tokens) == 0: 856*8975f5c5SAndroid Build Coastguard Worker return default 857*8975f5c5SAndroid Build Coastguard Worker 858*8975f5c5SAndroid Build Coastguard Worker try: 859*8975f5c5SAndroid Build Coastguard Worker return int(tokens.pop(0)) 860*8975f5c5SAndroid Build Coastguard Worker except ValueError: 861*8975f5c5SAndroid Build Coastguard Worker return default 862*8975f5c5SAndroid Build Coastguard Worker 863*8975f5c5SAndroid Build Coastguard Worker date = consume_token_or_default('') 864*8975f5c5SAndroid Build Coastguard Worker invokation_time = consume_token_or_default('') 865*8975f5c5SAndroid Build Coastguard Worker pid = consume_integer_token_or_default(-1) 866*8975f5c5SAndroid Build Coastguard Worker tid = consume_integer_token_or_default(-1) 867*8975f5c5SAndroid Build Coastguard Worker priority = consume_token_or_default('') 868*8975f5c5SAndroid Build Coastguard Worker tag = consume_token_or_default('') 869*8975f5c5SAndroid Build Coastguard Worker original_message = consume_token_or_default('') 870*8975f5c5SAndroid Build Coastguard Worker 871*8975f5c5SAndroid Build Coastguard Worker # Example: 872*8975f5c5SAndroid Build Coastguard Worker # 09-19 06:35:51.113 9060 9154 W GCoreFlp: No location... 873*8975f5c5SAndroid Build Coastguard Worker # 09-19 06:01:26.174 9060 10617 I Auth : [ReflectiveChannelBinder]... 874*8975f5c5SAndroid Build Coastguard Worker # Parsing "GCoreFlp:" vs "Auth :", we only want tag to contain the word, 875*8975f5c5SAndroid Build Coastguard Worker # and we don't want to keep the colon for the message. 876*8975f5c5SAndroid Build Coastguard Worker if tag and tag[-1] == ':': 877*8975f5c5SAndroid Build Coastguard Worker tag = tag[:-1] 878*8975f5c5SAndroid Build Coastguard Worker elif len(original_message) > 2: 879*8975f5c5SAndroid Build Coastguard Worker original_message = original_message[2:] 880*8975f5c5SAndroid Build Coastguard Worker return self.ParsedLine( 881*8975f5c5SAndroid Build Coastguard Worker date, invokation_time, pid, tid, priority, tag, original_message) 882*8975f5c5SAndroid Build Coastguard Worker 883*8975f5c5SAndroid Build Coastguard Worker def _PrintParsedLine(self, parsed_line, dim=False): 884*8975f5c5SAndroid Build Coastguard Worker if self._exit_on_match and self._exit_on_match.search(parsed_line.message): 885*8975f5c5SAndroid Build Coastguard Worker self._found_exit_match = True 886*8975f5c5SAndroid Build Coastguard Worker 887*8975f5c5SAndroid Build Coastguard Worker tid_style = colorama.Style.NORMAL 888*8975f5c5SAndroid Build Coastguard Worker user_match = self._user_defined_highlight and ( 889*8975f5c5SAndroid Build Coastguard Worker re.search(self._user_defined_highlight, parsed_line.tag) 890*8975f5c5SAndroid Build Coastguard Worker or re.search(self._user_defined_highlight, parsed_line.message)) 891*8975f5c5SAndroid Build Coastguard Worker 892*8975f5c5SAndroid Build Coastguard Worker # Make the main thread bright. 893*8975f5c5SAndroid Build Coastguard Worker if not dim and parsed_line.pid == parsed_line.tid: 894*8975f5c5SAndroid Build Coastguard Worker tid_style = colorama.Style.BRIGHT 895*8975f5c5SAndroid Build Coastguard Worker pid_style = self._GetPidStyle(parsed_line.pid, dim) 896*8975f5c5SAndroid Build Coastguard Worker msg_style = pid_style if not user_match else (colorama.Fore.GREEN + 897*8975f5c5SAndroid Build Coastguard Worker colorama.Style.BRIGHT) 898*8975f5c5SAndroid Build Coastguard Worker # We have to pad before adding color as that changes the width of the tag. 899*8975f5c5SAndroid Build Coastguard Worker pid_str = _Colorize('{:5}'.format(parsed_line.pid), pid_style) 900*8975f5c5SAndroid Build Coastguard Worker tid_str = _Colorize('{:5}'.format(parsed_line.tid), tid_style) 901*8975f5c5SAndroid Build Coastguard Worker tag = _Colorize('{:8}'.format(parsed_line.tag), 902*8975f5c5SAndroid Build Coastguard Worker pid_style + ('' if dim else colorama.Style.BRIGHT)) 903*8975f5c5SAndroid Build Coastguard Worker priority = _Colorize(parsed_line.priority, 904*8975f5c5SAndroid Build Coastguard Worker self._GetPriorityStyle(parsed_line.priority)) 905*8975f5c5SAndroid Build Coastguard Worker messages = [parsed_line.message] 906*8975f5c5SAndroid Build Coastguard Worker if self._deobfuscator: 907*8975f5c5SAndroid Build Coastguard Worker messages = self._deobfuscator.TransformLines(messages) 908*8975f5c5SAndroid Build Coastguard Worker for message in messages: 909*8975f5c5SAndroid Build Coastguard Worker message = _Colorize(message, msg_style) 910*8975f5c5SAndroid Build Coastguard Worker sys.stdout.write('{} {} {} {} {} {}: {}\n'.format( 911*8975f5c5SAndroid Build Coastguard Worker parsed_line.date, parsed_line.invokation_time, pid_str, tid_str, 912*8975f5c5SAndroid Build Coastguard Worker priority, tag, message)) 913*8975f5c5SAndroid Build Coastguard Worker 914*8975f5c5SAndroid Build Coastguard Worker def _TriggerNonceFound(self): 915*8975f5c5SAndroid Build Coastguard Worker # Once the nonce is hit, we have confidence that we know which lines 916*8975f5c5SAndroid Build Coastguard Worker # belong to the current run of the app. Process all of the buffered lines. 917*8975f5c5SAndroid Build Coastguard Worker if self._primary_pid: 918*8975f5c5SAndroid Build Coastguard Worker for args in self._initial_buffered_lines: 919*8975f5c5SAndroid Build Coastguard Worker self._print_func(*args) 920*8975f5c5SAndroid Build Coastguard Worker self._initial_buffered_lines = None 921*8975f5c5SAndroid Build Coastguard Worker self.nonce = None 922*8975f5c5SAndroid Build Coastguard Worker 923*8975f5c5SAndroid Build Coastguard Worker def FoundExitMatch(self): 924*8975f5c5SAndroid Build Coastguard Worker return self._found_exit_match 925*8975f5c5SAndroid Build Coastguard Worker 926*8975f5c5SAndroid Build Coastguard Worker def ProcessLine(self, line): 927*8975f5c5SAndroid Build Coastguard Worker if not line or line.startswith('------'): 928*8975f5c5SAndroid Build Coastguard Worker return 929*8975f5c5SAndroid Build Coastguard Worker 930*8975f5c5SAndroid Build Coastguard Worker if self.nonce and self.nonce in line: 931*8975f5c5SAndroid Build Coastguard Worker self._TriggerNonceFound() 932*8975f5c5SAndroid Build Coastguard Worker 933*8975f5c5SAndroid Build Coastguard Worker nonce_found = self.nonce is None 934*8975f5c5SAndroid Build Coastguard Worker 935*8975f5c5SAndroid Build Coastguard Worker log = self._ParseLine(line) 936*8975f5c5SAndroid Build Coastguard Worker if log.pid not in self._seen_pids: 937*8975f5c5SAndroid Build Coastguard Worker self._seen_pids.add(log.pid) 938*8975f5c5SAndroid Build Coastguard Worker if nonce_found: 939*8975f5c5SAndroid Build Coastguard Worker # Update list of owned PIDs each time a new PID is encountered. 940*8975f5c5SAndroid Build Coastguard Worker self._UpdateMyPids() 941*8975f5c5SAndroid Build Coastguard Worker 942*8975f5c5SAndroid Build Coastguard Worker # Search for "Start proc $pid:$package_name/" message. 943*8975f5c5SAndroid Build Coastguard Worker if not nonce_found: 944*8975f5c5SAndroid Build Coastguard Worker # Capture logs before the nonce. Start with the most recent "am start". 945*8975f5c5SAndroid Build Coastguard Worker if self._start_pattern.match(log.message): 946*8975f5c5SAndroid Build Coastguard Worker self._initial_buffered_lines = [] 947*8975f5c5SAndroid Build Coastguard Worker 948*8975f5c5SAndroid Build Coastguard Worker # If we didn't find the PID via "ps", then extract it from log messages. 949*8975f5c5SAndroid Build Coastguard Worker # This will happen if the app crashes too quickly. 950*8975f5c5SAndroid Build Coastguard Worker if not self._found_initial_pid: 951*8975f5c5SAndroid Build Coastguard Worker m = self._pid_pattern.match(log.message) 952*8975f5c5SAndroid Build Coastguard Worker if m: 953*8975f5c5SAndroid Build Coastguard Worker # Find the most recent "Start proc" line before the nonce. 954*8975f5c5SAndroid Build Coastguard Worker # Track only the primary pid in this mode. 955*8975f5c5SAndroid Build Coastguard Worker # The main use-case is to find app logs when no current PIDs exist. 956*8975f5c5SAndroid Build Coastguard Worker # E.g.: When the app crashes on launch. 957*8975f5c5SAndroid Build Coastguard Worker self._primary_pid = m.group(1) 958*8975f5c5SAndroid Build Coastguard Worker self._my_pids.clear() 959*8975f5c5SAndroid Build Coastguard Worker self._my_pids.add(m.group(1)) 960*8975f5c5SAndroid Build Coastguard Worker 961*8975f5c5SAndroid Build Coastguard Worker owned_pid = log.pid in self._my_pids 962*8975f5c5SAndroid Build Coastguard Worker if owned_pid and not self._verbose and log.tag == 'dalvikvm': 963*8975f5c5SAndroid Build Coastguard Worker if self._DALVIK_IGNORE_PATTERN.match(log.message): 964*8975f5c5SAndroid Build Coastguard Worker return 965*8975f5c5SAndroid Build Coastguard Worker 966*8975f5c5SAndroid Build Coastguard Worker if owned_pid or self._verbose or (log.priority == 'F' or # Java crash dump 967*8975f5c5SAndroid Build Coastguard Worker log.tag in self._ALLOWLISTED_TAGS): 968*8975f5c5SAndroid Build Coastguard Worker if nonce_found: 969*8975f5c5SAndroid Build Coastguard Worker self._print_func(log, not owned_pid) 970*8975f5c5SAndroid Build Coastguard Worker else: 971*8975f5c5SAndroid Build Coastguard Worker self._initial_buffered_lines.append((log, not owned_pid)) 972*8975f5c5SAndroid Build Coastguard Worker 973*8975f5c5SAndroid Build Coastguard Worker 974*8975f5c5SAndroid Build Coastguard Workerdef _RunLogcat(device, 975*8975f5c5SAndroid Build Coastguard Worker package_name, 976*8975f5c5SAndroid Build Coastguard Worker stack_script_context, 977*8975f5c5SAndroid Build Coastguard Worker deobfuscate, 978*8975f5c5SAndroid Build Coastguard Worker verbose, 979*8975f5c5SAndroid Build Coastguard Worker exit_on_match=None, 980*8975f5c5SAndroid Build Coastguard Worker extra_package_names=None): 981*8975f5c5SAndroid Build Coastguard Worker logcat_processor = _LogcatProcessor(device, 982*8975f5c5SAndroid Build Coastguard Worker package_name, 983*8975f5c5SAndroid Build Coastguard Worker stack_script_context, 984*8975f5c5SAndroid Build Coastguard Worker deobfuscate, 985*8975f5c5SAndroid Build Coastguard Worker verbose, 986*8975f5c5SAndroid Build Coastguard Worker exit_on_match=exit_on_match, 987*8975f5c5SAndroid Build Coastguard Worker extra_package_names=extra_package_names) 988*8975f5c5SAndroid Build Coastguard Worker device.RunShellCommand(['log', logcat_processor.nonce]) 989*8975f5c5SAndroid Build Coastguard Worker for line in device.adb.Logcat(logcat_format='threadtime'): 990*8975f5c5SAndroid Build Coastguard Worker try: 991*8975f5c5SAndroid Build Coastguard Worker logcat_processor.ProcessLine(line) 992*8975f5c5SAndroid Build Coastguard Worker if logcat_processor.FoundExitMatch(): 993*8975f5c5SAndroid Build Coastguard Worker return 994*8975f5c5SAndroid Build Coastguard Worker except: 995*8975f5c5SAndroid Build Coastguard Worker sys.stderr.write('Failed to process line: ' + line + '\n') 996*8975f5c5SAndroid Build Coastguard Worker # Skip stack trace for the common case of the adb server being 997*8975f5c5SAndroid Build Coastguard Worker # restarted. 998*8975f5c5SAndroid Build Coastguard Worker if 'unexpected EOF' in line: 999*8975f5c5SAndroid Build Coastguard Worker sys.exit(1) 1000*8975f5c5SAndroid Build Coastguard Worker raise 1001*8975f5c5SAndroid Build Coastguard Worker 1002*8975f5c5SAndroid Build Coastguard Worker 1003*8975f5c5SAndroid Build Coastguard Workerdef _GetPackageProcesses(device, package_name): 1004*8975f5c5SAndroid Build Coastguard Worker my_names = (package_name, package_name + '_zygote') 1005*8975f5c5SAndroid Build Coastguard Worker return [ 1006*8975f5c5SAndroid Build Coastguard Worker p for p in device.ListProcesses(package_name) 1007*8975f5c5SAndroid Build Coastguard Worker if p.name in my_names or p.name.startswith(package_name + ':') 1008*8975f5c5SAndroid Build Coastguard Worker ] 1009*8975f5c5SAndroid Build Coastguard Worker 1010*8975f5c5SAndroid Build Coastguard Worker 1011*8975f5c5SAndroid Build Coastguard Workerdef _RunPs(devices, package_name): 1012*8975f5c5SAndroid Build Coastguard Worker parallel_devices = device_utils.DeviceUtils.parallel(devices) 1013*8975f5c5SAndroid Build Coastguard Worker all_processes = parallel_devices.pMap( 1014*8975f5c5SAndroid Build Coastguard Worker lambda d: _GetPackageProcesses(d, package_name)).pGet(None) 1015*8975f5c5SAndroid Build Coastguard Worker for processes in _PrintPerDeviceOutput(devices, all_processes): 1016*8975f5c5SAndroid Build Coastguard Worker if not processes: 1017*8975f5c5SAndroid Build Coastguard Worker print('No processes found.') 1018*8975f5c5SAndroid Build Coastguard Worker else: 1019*8975f5c5SAndroid Build Coastguard Worker proc_map = collections.defaultdict(list) 1020*8975f5c5SAndroid Build Coastguard Worker for p in processes: 1021*8975f5c5SAndroid Build Coastguard Worker proc_map[p.name].append(str(p.pid)) 1022*8975f5c5SAndroid Build Coastguard Worker for name, pids in sorted(proc_map.items()): 1023*8975f5c5SAndroid Build Coastguard Worker print(name, ','.join(pids)) 1024*8975f5c5SAndroid Build Coastguard Worker 1025*8975f5c5SAndroid Build Coastguard Worker 1026*8975f5c5SAndroid Build Coastguard Workerdef _RunShell(devices, package_name, cmd): 1027*8975f5c5SAndroid Build Coastguard Worker if cmd: 1028*8975f5c5SAndroid Build Coastguard Worker parallel_devices = device_utils.DeviceUtils.parallel(devices) 1029*8975f5c5SAndroid Build Coastguard Worker outputs = parallel_devices.RunShellCommand( 1030*8975f5c5SAndroid Build Coastguard Worker cmd, run_as=package_name).pGet(None) 1031*8975f5c5SAndroid Build Coastguard Worker for output in _PrintPerDeviceOutput(devices, outputs): 1032*8975f5c5SAndroid Build Coastguard Worker for line in output: 1033*8975f5c5SAndroid Build Coastguard Worker print(line) 1034*8975f5c5SAndroid Build Coastguard Worker else: 1035*8975f5c5SAndroid Build Coastguard Worker adb_path = adb_wrapper.AdbWrapper.GetAdbPath() 1036*8975f5c5SAndroid Build Coastguard Worker cmd = [adb_path, '-s', devices[0].serial, 'shell'] 1037*8975f5c5SAndroid Build Coastguard Worker # Pre-N devices do not support -t flag. 1038*8975f5c5SAndroid Build Coastguard Worker if devices[0].build_version_sdk >= version_codes.NOUGAT: 1039*8975f5c5SAndroid Build Coastguard Worker cmd += ['-t', 'run-as', package_name] 1040*8975f5c5SAndroid Build Coastguard Worker else: 1041*8975f5c5SAndroid Build Coastguard Worker print('Upon entering the shell, run:') 1042*8975f5c5SAndroid Build Coastguard Worker print('run-as', package_name) 1043*8975f5c5SAndroid Build Coastguard Worker print() 1044*8975f5c5SAndroid Build Coastguard Worker os.execv(adb_path, cmd) 1045*8975f5c5SAndroid Build Coastguard Worker 1046*8975f5c5SAndroid Build Coastguard Worker 1047*8975f5c5SAndroid Build Coastguard Workerdef _RunCompileDex(devices, package_name, compilation_filter): 1048*8975f5c5SAndroid Build Coastguard Worker cmd = ['cmd', 'package', 'compile', '-f', '-m', compilation_filter, 1049*8975f5c5SAndroid Build Coastguard Worker package_name] 1050*8975f5c5SAndroid Build Coastguard Worker parallel_devices = device_utils.DeviceUtils.parallel(devices) 1051*8975f5c5SAndroid Build Coastguard Worker return parallel_devices.RunShellCommand(cmd, timeout=120).pGet(None) 1052*8975f5c5SAndroid Build Coastguard Worker 1053*8975f5c5SAndroid Build Coastguard Worker 1054*8975f5c5SAndroid Build Coastguard Workerdef _RunProfile(device, package_name, host_build_directory, pprof_out_path, 1055*8975f5c5SAndroid Build Coastguard Worker process_specifier, thread_specifier, events, extra_args): 1056*8975f5c5SAndroid Build Coastguard Worker simpleperf.PrepareDevice(device) 1057*8975f5c5SAndroid Build Coastguard Worker device_simpleperf_path = simpleperf.InstallSimpleperf(device, package_name) 1058*8975f5c5SAndroid Build Coastguard Worker with tempfile.NamedTemporaryFile() as fh: 1059*8975f5c5SAndroid Build Coastguard Worker host_simpleperf_out_path = fh.name 1060*8975f5c5SAndroid Build Coastguard Worker 1061*8975f5c5SAndroid Build Coastguard Worker with simpleperf.RunSimpleperf(device, device_simpleperf_path, package_name, 1062*8975f5c5SAndroid Build Coastguard Worker process_specifier, thread_specifier, 1063*8975f5c5SAndroid Build Coastguard Worker events, extra_args, host_simpleperf_out_path): 1064*8975f5c5SAndroid Build Coastguard Worker sys.stdout.write('Profiler is running; press Enter to stop...\n') 1065*8975f5c5SAndroid Build Coastguard Worker sys.stdin.read(1) 1066*8975f5c5SAndroid Build Coastguard Worker sys.stdout.write('Post-processing data...\n') 1067*8975f5c5SAndroid Build Coastguard Worker 1068*8975f5c5SAndroid Build Coastguard Worker simpleperf.ConvertSimpleperfToPprof(host_simpleperf_out_path, 1069*8975f5c5SAndroid Build Coastguard Worker host_build_directory, pprof_out_path) 1070*8975f5c5SAndroid Build Coastguard Worker print(textwrap.dedent(""" 1071*8975f5c5SAndroid Build Coastguard Worker Profile data written to %(s)s. 1072*8975f5c5SAndroid Build Coastguard Worker 1073*8975f5c5SAndroid Build Coastguard Worker To view profile as a call graph in browser: 1074*8975f5c5SAndroid Build Coastguard Worker pprof -web %(s)s 1075*8975f5c5SAndroid Build Coastguard Worker 1076*8975f5c5SAndroid Build Coastguard Worker To print the hottest methods: 1077*8975f5c5SAndroid Build Coastguard Worker pprof -top %(s)s 1078*8975f5c5SAndroid Build Coastguard Worker 1079*8975f5c5SAndroid Build Coastguard Worker pprof has many useful customization options; `pprof --help` for details. 1080*8975f5c5SAndroid Build Coastguard Worker """ % {'s': pprof_out_path})) 1081*8975f5c5SAndroid Build Coastguard Worker 1082*8975f5c5SAndroid Build Coastguard Worker 1083*8975f5c5SAndroid Build Coastguard Workerclass _StackScriptContext: 1084*8975f5c5SAndroid Build Coastguard Worker """Maintains temporary files needed by stack.py.""" 1085*8975f5c5SAndroid Build Coastguard Worker 1086*8975f5c5SAndroid Build Coastguard Worker def __init__(self, 1087*8975f5c5SAndroid Build Coastguard Worker output_directory, 1088*8975f5c5SAndroid Build Coastguard Worker apk_path, 1089*8975f5c5SAndroid Build Coastguard Worker bundle_generation_info, 1090*8975f5c5SAndroid Build Coastguard Worker quiet=False): 1091*8975f5c5SAndroid Build Coastguard Worker self._output_directory = output_directory 1092*8975f5c5SAndroid Build Coastguard Worker self._apk_path = apk_path 1093*8975f5c5SAndroid Build Coastguard Worker self._bundle_generation_info = bundle_generation_info 1094*8975f5c5SAndroid Build Coastguard Worker self._staging_dir = None 1095*8975f5c5SAndroid Build Coastguard Worker self._quiet = quiet 1096*8975f5c5SAndroid Build Coastguard Worker 1097*8975f5c5SAndroid Build Coastguard Worker def _CreateStaging(self): 1098*8975f5c5SAndroid Build Coastguard Worker # In many cases, stack decoding requires APKs to map trace lines to native 1099*8975f5c5SAndroid Build Coastguard Worker # libraries. Create a temporary directory, and either unpack a bundle's 1100*8975f5c5SAndroid Build Coastguard Worker # APKS into it, or simply symlink the standalone APK into it. This 1101*8975f5c5SAndroid Build Coastguard Worker # provides an unambiguous set of APK files for the stack decoding process 1102*8975f5c5SAndroid Build Coastguard Worker # to inspect. 1103*8975f5c5SAndroid Build Coastguard Worker logging.debug('Creating stack staging directory') 1104*8975f5c5SAndroid Build Coastguard Worker self._staging_dir = tempfile.mkdtemp() 1105*8975f5c5SAndroid Build Coastguard Worker bundle_generation_info = self._bundle_generation_info 1106*8975f5c5SAndroid Build Coastguard Worker 1107*8975f5c5SAndroid Build Coastguard Worker if bundle_generation_info: 1108*8975f5c5SAndroid Build Coastguard Worker # TODO(wnwen): Use apk_helper instead. 1109*8975f5c5SAndroid Build Coastguard Worker _GenerateBundleApks(bundle_generation_info) 1110*8975f5c5SAndroid Build Coastguard Worker logging.debug('Extracting .apks file') 1111*8975f5c5SAndroid Build Coastguard Worker with zipfile.ZipFile(bundle_generation_info.bundle_apks_path, 'r') as z: 1112*8975f5c5SAndroid Build Coastguard Worker files_to_extract = [ 1113*8975f5c5SAndroid Build Coastguard Worker f for f in z.namelist() if f.endswith('-master.apk') 1114*8975f5c5SAndroid Build Coastguard Worker ] 1115*8975f5c5SAndroid Build Coastguard Worker z.extractall(self._staging_dir, files_to_extract) 1116*8975f5c5SAndroid Build Coastguard Worker elif self._apk_path: 1117*8975f5c5SAndroid Build Coastguard Worker # Otherwise an incremental APK and an empty apks directory is correct. 1118*8975f5c5SAndroid Build Coastguard Worker output = os.path.join(self._staging_dir, os.path.basename(self._apk_path)) 1119*8975f5c5SAndroid Build Coastguard Worker os.symlink(self._apk_path, output) 1120*8975f5c5SAndroid Build Coastguard Worker 1121*8975f5c5SAndroid Build Coastguard Worker def Close(self): 1122*8975f5c5SAndroid Build Coastguard Worker if self._staging_dir: 1123*8975f5c5SAndroid Build Coastguard Worker logging.debug('Clearing stack staging directory') 1124*8975f5c5SAndroid Build Coastguard Worker shutil.rmtree(self._staging_dir) 1125*8975f5c5SAndroid Build Coastguard Worker self._staging_dir = None 1126*8975f5c5SAndroid Build Coastguard Worker 1127*8975f5c5SAndroid Build Coastguard Worker def Popen(self, input_file=None, **kwargs): 1128*8975f5c5SAndroid Build Coastguard Worker if self._staging_dir is None: 1129*8975f5c5SAndroid Build Coastguard Worker self._CreateStaging() 1130*8975f5c5SAndroid Build Coastguard Worker stack_script = os.path.join( 1131*8975f5c5SAndroid Build Coastguard Worker constants.host_paths.ANDROID_PLATFORM_DEVELOPMENT_SCRIPTS_PATH, 1132*8975f5c5SAndroid Build Coastguard Worker 'stack.py') 1133*8975f5c5SAndroid Build Coastguard Worker cmd = [ 1134*8975f5c5SAndroid Build Coastguard Worker stack_script, '--output-directory', self._output_directory, 1135*8975f5c5SAndroid Build Coastguard Worker '--apks-directory', self._staging_dir 1136*8975f5c5SAndroid Build Coastguard Worker ] 1137*8975f5c5SAndroid Build Coastguard Worker if self._quiet: 1138*8975f5c5SAndroid Build Coastguard Worker cmd.append('--quiet') 1139*8975f5c5SAndroid Build Coastguard Worker if input_file: 1140*8975f5c5SAndroid Build Coastguard Worker cmd.append(input_file) 1141*8975f5c5SAndroid Build Coastguard Worker logging.info('Running: %s', shlex.join(cmd)) 1142*8975f5c5SAndroid Build Coastguard Worker return subprocess.Popen(cmd, universal_newlines=True, **kwargs) 1143*8975f5c5SAndroid Build Coastguard Worker 1144*8975f5c5SAndroid Build Coastguard Worker 1145*8975f5c5SAndroid Build Coastguard Workerdef _GenerateAvailableDevicesMessage(devices): 1146*8975f5c5SAndroid Build Coastguard Worker devices_obj = device_utils.DeviceUtils.parallel(devices) 1147*8975f5c5SAndroid Build Coastguard Worker descriptions = devices_obj.pMap(lambda d: d.build_description).pGet(None) 1148*8975f5c5SAndroid Build Coastguard Worker msg = 'Available devices:\n' 1149*8975f5c5SAndroid Build Coastguard Worker for d, desc in zip(devices, descriptions): 1150*8975f5c5SAndroid Build Coastguard Worker msg += ' %s (%s)\n' % (d, desc) 1151*8975f5c5SAndroid Build Coastguard Worker return msg 1152*8975f5c5SAndroid Build Coastguard Worker 1153*8975f5c5SAndroid Build Coastguard Worker 1154*8975f5c5SAndroid Build Coastguard Worker# TODO(agrieve):add "--all" in the MultipleDevicesError message and use it here. 1155*8975f5c5SAndroid Build Coastguard Workerdef _GenerateMissingAllFlagMessage(devices): 1156*8975f5c5SAndroid Build Coastguard Worker return ('More than one device available. Use --all to select all devices, ' + 1157*8975f5c5SAndroid Build Coastguard Worker 'or use --device to select a device by serial.\n\n' + 1158*8975f5c5SAndroid Build Coastguard Worker _GenerateAvailableDevicesMessage(devices)) 1159*8975f5c5SAndroid Build Coastguard Worker 1160*8975f5c5SAndroid Build Coastguard Workerdef _SanitizeFilename(filename): 1161*8975f5c5SAndroid Build Coastguard Worker for sep in os.path.sep, os.path.altsep: 1162*8975f5c5SAndroid Build Coastguard Worker if sep is not None: 1163*8975f5c5SAndroid Build Coastguard Worker filename = filename.replace(sep, '_') 1164*8975f5c5SAndroid Build Coastguard Worker return filename 1165*8975f5c5SAndroid Build Coastguard Worker 1166*8975f5c5SAndroid Build Coastguard Worker 1167*8975f5c5SAndroid Build Coastguard Workerdef _DeviceCachePath(device, output_directory): 1168*8975f5c5SAndroid Build Coastguard Worker file_name = 'device_cache_%s.json' % _SanitizeFilename(device.serial) 1169*8975f5c5SAndroid Build Coastguard Worker return os.path.join(output_directory, file_name) 1170*8975f5c5SAndroid Build Coastguard Worker 1171*8975f5c5SAndroid Build Coastguard Worker 1172*8975f5c5SAndroid Build Coastguard Workerdef _LoadDeviceCaches(devices, output_directory): 1173*8975f5c5SAndroid Build Coastguard Worker if not output_directory: 1174*8975f5c5SAndroid Build Coastguard Worker return 1175*8975f5c5SAndroid Build Coastguard Worker for d in devices: 1176*8975f5c5SAndroid Build Coastguard Worker cache_path = _DeviceCachePath(d, output_directory) 1177*8975f5c5SAndroid Build Coastguard Worker if os.path.exists(cache_path): 1178*8975f5c5SAndroid Build Coastguard Worker logging.debug('Using device cache: %s', cache_path) 1179*8975f5c5SAndroid Build Coastguard Worker with open(cache_path) as f: 1180*8975f5c5SAndroid Build Coastguard Worker d.LoadCacheData(f.read()) 1181*8975f5c5SAndroid Build Coastguard Worker # Delete the cached file so that any exceptions cause it to be cleared. 1182*8975f5c5SAndroid Build Coastguard Worker os.unlink(cache_path) 1183*8975f5c5SAndroid Build Coastguard Worker else: 1184*8975f5c5SAndroid Build Coastguard Worker logging.debug('No cache present for device: %s', d) 1185*8975f5c5SAndroid Build Coastguard Worker 1186*8975f5c5SAndroid Build Coastguard Worker 1187*8975f5c5SAndroid Build Coastguard Workerdef _SaveDeviceCaches(devices, output_directory): 1188*8975f5c5SAndroid Build Coastguard Worker if not output_directory: 1189*8975f5c5SAndroid Build Coastguard Worker return 1190*8975f5c5SAndroid Build Coastguard Worker for d in devices: 1191*8975f5c5SAndroid Build Coastguard Worker cache_path = _DeviceCachePath(d, output_directory) 1192*8975f5c5SAndroid Build Coastguard Worker with open(cache_path, 'w') as f: 1193*8975f5c5SAndroid Build Coastguard Worker f.write(d.DumpCacheData()) 1194*8975f5c5SAndroid Build Coastguard Worker logging.info('Wrote device cache: %s', cache_path) 1195*8975f5c5SAndroid Build Coastguard Worker 1196*8975f5c5SAndroid Build Coastguard Worker 1197*8975f5c5SAndroid Build Coastguard Workerclass _Command: 1198*8975f5c5SAndroid Build Coastguard Worker name = None 1199*8975f5c5SAndroid Build Coastguard Worker description = None 1200*8975f5c5SAndroid Build Coastguard Worker long_description = None 1201*8975f5c5SAndroid Build Coastguard Worker needs_package_name = False 1202*8975f5c5SAndroid Build Coastguard Worker needs_output_directory = False 1203*8975f5c5SAndroid Build Coastguard Worker needs_apk_helper = False 1204*8975f5c5SAndroid Build Coastguard Worker supports_incremental = False 1205*8975f5c5SAndroid Build Coastguard Worker accepts_command_line_flags = False 1206*8975f5c5SAndroid Build Coastguard Worker accepts_args = False 1207*8975f5c5SAndroid Build Coastguard Worker need_device_args = True 1208*8975f5c5SAndroid Build Coastguard Worker all_devices_by_default = False 1209*8975f5c5SAndroid Build Coastguard Worker calls_exec = False 1210*8975f5c5SAndroid Build Coastguard Worker supports_multiple_devices = True 1211*8975f5c5SAndroid Build Coastguard Worker 1212*8975f5c5SAndroid Build Coastguard Worker def __init__(self, from_wrapper_script, is_bundle, is_test_apk): 1213*8975f5c5SAndroid Build Coastguard Worker self._parser = None 1214*8975f5c5SAndroid Build Coastguard Worker self._from_wrapper_script = from_wrapper_script 1215*8975f5c5SAndroid Build Coastguard Worker self.args = None 1216*8975f5c5SAndroid Build Coastguard Worker self.incremental_apk_path = None 1217*8975f5c5SAndroid Build Coastguard Worker self.apk_helper = None 1218*8975f5c5SAndroid Build Coastguard Worker self.additional_apk_helpers = None 1219*8975f5c5SAndroid Build Coastguard Worker self.install_dict = None 1220*8975f5c5SAndroid Build Coastguard Worker self.devices = None 1221*8975f5c5SAndroid Build Coastguard Worker self.is_bundle = is_bundle 1222*8975f5c5SAndroid Build Coastguard Worker self.is_test_apk = is_test_apk 1223*8975f5c5SAndroid Build Coastguard Worker self.bundle_generation_info = None 1224*8975f5c5SAndroid Build Coastguard Worker # Only support incremental install from APK wrapper scripts. 1225*8975f5c5SAndroid Build Coastguard Worker if is_bundle or not from_wrapper_script: 1226*8975f5c5SAndroid Build Coastguard Worker self.supports_incremental = False 1227*8975f5c5SAndroid Build Coastguard Worker 1228*8975f5c5SAndroid Build Coastguard Worker def RegisterBundleGenerationInfo(self, bundle_generation_info): 1229*8975f5c5SAndroid Build Coastguard Worker self.bundle_generation_info = bundle_generation_info 1230*8975f5c5SAndroid Build Coastguard Worker 1231*8975f5c5SAndroid Build Coastguard Worker def _RegisterExtraArgs(self, group): 1232*8975f5c5SAndroid Build Coastguard Worker pass 1233*8975f5c5SAndroid Build Coastguard Worker 1234*8975f5c5SAndroid Build Coastguard Worker def RegisterArgs(self, parser): 1235*8975f5c5SAndroid Build Coastguard Worker subp = parser.add_parser( 1236*8975f5c5SAndroid Build Coastguard Worker self.name, help=self.description, 1237*8975f5c5SAndroid Build Coastguard Worker description=self.long_description or self.description, 1238*8975f5c5SAndroid Build Coastguard Worker formatter_class=argparse.RawDescriptionHelpFormatter) 1239*8975f5c5SAndroid Build Coastguard Worker self._parser = subp 1240*8975f5c5SAndroid Build Coastguard Worker subp.set_defaults(command=self) 1241*8975f5c5SAndroid Build Coastguard Worker if self.need_device_args: 1242*8975f5c5SAndroid Build Coastguard Worker subp.add_argument('--all', 1243*8975f5c5SAndroid Build Coastguard Worker action='store_true', 1244*8975f5c5SAndroid Build Coastguard Worker default=self.all_devices_by_default, 1245*8975f5c5SAndroid Build Coastguard Worker help='Operate on all connected devices.',) 1246*8975f5c5SAndroid Build Coastguard Worker subp.add_argument('-d', 1247*8975f5c5SAndroid Build Coastguard Worker '--device', 1248*8975f5c5SAndroid Build Coastguard Worker action='append', 1249*8975f5c5SAndroid Build Coastguard Worker default=[], 1250*8975f5c5SAndroid Build Coastguard Worker dest='devices', 1251*8975f5c5SAndroid Build Coastguard Worker help='Target device for script to work on. Enter ' 1252*8975f5c5SAndroid Build Coastguard Worker 'multiple times for multiple devices.') 1253*8975f5c5SAndroid Build Coastguard Worker subp.add_argument('-v', 1254*8975f5c5SAndroid Build Coastguard Worker '--verbose', 1255*8975f5c5SAndroid Build Coastguard Worker action='count', 1256*8975f5c5SAndroid Build Coastguard Worker default=0, 1257*8975f5c5SAndroid Build Coastguard Worker dest='verbose_count', 1258*8975f5c5SAndroid Build Coastguard Worker help='Verbose level (multiple times for more)') 1259*8975f5c5SAndroid Build Coastguard Worker group = subp.add_argument_group('%s arguments' % self.name) 1260*8975f5c5SAndroid Build Coastguard Worker 1261*8975f5c5SAndroid Build Coastguard Worker if self.needs_package_name: 1262*8975f5c5SAndroid Build Coastguard Worker # Three cases to consider here, since later code assumes 1263*8975f5c5SAndroid Build Coastguard Worker # self.args.package_name always exists, even if None: 1264*8975f5c5SAndroid Build Coastguard Worker # 1265*8975f5c5SAndroid Build Coastguard Worker # - Called from a bundle wrapper script, the package_name is already 1266*8975f5c5SAndroid Build Coastguard Worker # set through parser.set_defaults(), so don't call add_argument() 1267*8975f5c5SAndroid Build Coastguard Worker # to avoid overriding its value. 1268*8975f5c5SAndroid Build Coastguard Worker # 1269*8975f5c5SAndroid Build Coastguard Worker # - Called from an apk wrapper script. The --package-name argument 1270*8975f5c5SAndroid Build Coastguard Worker # should not appear, but self.args.package_name will be gleaned from 1271*8975f5c5SAndroid Build Coastguard Worker # the --apk-path file later. 1272*8975f5c5SAndroid Build Coastguard Worker # 1273*8975f5c5SAndroid Build Coastguard Worker # - Called directly, then --package-name is required on the command-line. 1274*8975f5c5SAndroid Build Coastguard Worker # 1275*8975f5c5SAndroid Build Coastguard Worker # Similarly is_official_build is set directly by the bundle wrapper 1276*8975f5c5SAndroid Build Coastguard Worker # script, so it also needs to be added for non-bundle builds. 1277*8975f5c5SAndroid Build Coastguard Worker if not self.is_bundle: 1278*8975f5c5SAndroid Build Coastguard Worker group.add_argument( 1279*8975f5c5SAndroid Build Coastguard Worker '--package-name', 1280*8975f5c5SAndroid Build Coastguard Worker help=argparse.SUPPRESS if self._from_wrapper_script else ( 1281*8975f5c5SAndroid Build Coastguard Worker "App's package name.")) 1282*8975f5c5SAndroid Build Coastguard Worker 1283*8975f5c5SAndroid Build Coastguard Worker group.add_argument( 1284*8975f5c5SAndroid Build Coastguard Worker '--is-official-build', 1285*8975f5c5SAndroid Build Coastguard Worker action='store_true', 1286*8975f5c5SAndroid Build Coastguard Worker default=False, 1287*8975f5c5SAndroid Build Coastguard Worker help=argparse.SUPPRESS if self._from_wrapper_script else 1288*8975f5c5SAndroid Build Coastguard Worker ('Whether this is an official build or not (affects perf).')) 1289*8975f5c5SAndroid Build Coastguard Worker 1290*8975f5c5SAndroid Build Coastguard Worker if self.needs_apk_helper or self.needs_package_name: 1291*8975f5c5SAndroid Build Coastguard Worker # Adding this argument to the subparser would override the set_defaults() 1292*8975f5c5SAndroid Build Coastguard Worker # value set by on the parent parser (even if None). 1293*8975f5c5SAndroid Build Coastguard Worker if not self._from_wrapper_script and not self.is_bundle: 1294*8975f5c5SAndroid Build Coastguard Worker group.add_argument( 1295*8975f5c5SAndroid Build Coastguard Worker '--apk-path', required=self.needs_apk_helper, help='Path to .apk') 1296*8975f5c5SAndroid Build Coastguard Worker 1297*8975f5c5SAndroid Build Coastguard Worker if self.supports_incremental: 1298*8975f5c5SAndroid Build Coastguard Worker group.add_argument('--incremental', 1299*8975f5c5SAndroid Build Coastguard Worker action='store_true', 1300*8975f5c5SAndroid Build Coastguard Worker default=False, 1301*8975f5c5SAndroid Build Coastguard Worker help='Always install an incremental apk.') 1302*8975f5c5SAndroid Build Coastguard Worker group.add_argument('--non-incremental', 1303*8975f5c5SAndroid Build Coastguard Worker action='store_true', 1304*8975f5c5SAndroid Build Coastguard Worker default=False, 1305*8975f5c5SAndroid Build Coastguard Worker help='Always install a non-incremental apk.') 1306*8975f5c5SAndroid Build Coastguard Worker 1307*8975f5c5SAndroid Build Coastguard Worker # accepts_command_line_flags and accepts_args are mutually exclusive. 1308*8975f5c5SAndroid Build Coastguard Worker # argparse will throw if they are both set. 1309*8975f5c5SAndroid Build Coastguard Worker if self.accepts_command_line_flags: 1310*8975f5c5SAndroid Build Coastguard Worker group.add_argument( 1311*8975f5c5SAndroid Build Coastguard Worker '--args', help='Command-line flags. Use = to assign args.') 1312*8975f5c5SAndroid Build Coastguard Worker 1313*8975f5c5SAndroid Build Coastguard Worker if self.accepts_args: 1314*8975f5c5SAndroid Build Coastguard Worker group.add_argument( 1315*8975f5c5SAndroid Build Coastguard Worker '--args', help='Extra arguments. Use = to assign args') 1316*8975f5c5SAndroid Build Coastguard Worker 1317*8975f5c5SAndroid Build Coastguard Worker if not self._from_wrapper_script and self.accepts_command_line_flags: 1318*8975f5c5SAndroid Build Coastguard Worker # Provided by wrapper scripts. 1319*8975f5c5SAndroid Build Coastguard Worker group.add_argument( 1320*8975f5c5SAndroid Build Coastguard Worker '--command-line-flags-file', 1321*8975f5c5SAndroid Build Coastguard Worker help='Name of the command-line flags file') 1322*8975f5c5SAndroid Build Coastguard Worker 1323*8975f5c5SAndroid Build Coastguard Worker self._RegisterExtraArgs(group) 1324*8975f5c5SAndroid Build Coastguard Worker 1325*8975f5c5SAndroid Build Coastguard Worker def _CreateApkHelpers(self, args, incremental_apk_path, install_dict): 1326*8975f5c5SAndroid Build Coastguard Worker """Returns true iff self.apk_helper was created and assigned.""" 1327*8975f5c5SAndroid Build Coastguard Worker if self.apk_helper is None: 1328*8975f5c5SAndroid Build Coastguard Worker if args.apk_path: 1329*8975f5c5SAndroid Build Coastguard Worker self.apk_helper = apk_helper.ToHelper(args.apk_path) 1330*8975f5c5SAndroid Build Coastguard Worker elif incremental_apk_path: 1331*8975f5c5SAndroid Build Coastguard Worker self.install_dict = install_dict 1332*8975f5c5SAndroid Build Coastguard Worker self.apk_helper = apk_helper.ToHelper(incremental_apk_path) 1333*8975f5c5SAndroid Build Coastguard Worker elif self.is_bundle: 1334*8975f5c5SAndroid Build Coastguard Worker _GenerateBundleApks(self.bundle_generation_info) 1335*8975f5c5SAndroid Build Coastguard Worker self.apk_helper = apk_helper.ToHelper( 1336*8975f5c5SAndroid Build Coastguard Worker self.bundle_generation_info.bundle_apks_path) 1337*8975f5c5SAndroid Build Coastguard Worker if args.additional_apk_paths and self.additional_apk_helpers is None: 1338*8975f5c5SAndroid Build Coastguard Worker self.additional_apk_helpers = [ 1339*8975f5c5SAndroid Build Coastguard Worker apk_helper.ToHelper(apk_path) 1340*8975f5c5SAndroid Build Coastguard Worker for apk_path in args.additional_apk_paths 1341*8975f5c5SAndroid Build Coastguard Worker ] 1342*8975f5c5SAndroid Build Coastguard Worker return self.apk_helper is not None 1343*8975f5c5SAndroid Build Coastguard Worker 1344*8975f5c5SAndroid Build Coastguard Worker def _FindSupportedDevices(self, devices): 1345*8975f5c5SAndroid Build Coastguard Worker """Returns supported devices and reasons for each not supported one.""" 1346*8975f5c5SAndroid Build Coastguard Worker app_abis = self.apk_helper.GetAbis() 1347*8975f5c5SAndroid Build Coastguard Worker calling_script_name = os.path.basename(sys.argv[0]) 1348*8975f5c5SAndroid Build Coastguard Worker is_webview = 'webview' in calling_script_name 1349*8975f5c5SAndroid Build Coastguard Worker requires_32_bit = self.apk_helper.Get32BitAbiOverride() == '0xffffffff' 1350*8975f5c5SAndroid Build Coastguard Worker logging.debug('App supports (requires 32bit: %r, is webview: %r): %r', 1351*8975f5c5SAndroid Build Coastguard Worker requires_32_bit, is_webview, app_abis) 1352*8975f5c5SAndroid Build Coastguard Worker # Webview 32_64 targets can work even on 64-bit only devices since only the 1353*8975f5c5SAndroid Build Coastguard Worker # webview library in the target needs the correct bitness. 1354*8975f5c5SAndroid Build Coastguard Worker if requires_32_bit and not is_webview: 1355*8975f5c5SAndroid Build Coastguard Worker app_abis = [abi for abi in app_abis if '64' not in abi] 1356*8975f5c5SAndroid Build Coastguard Worker logging.debug('App supports (filtered): %r', app_abis) 1357*8975f5c5SAndroid Build Coastguard Worker if not app_abis: 1358*8975f5c5SAndroid Build Coastguard Worker # The app does not have any native libs, so all devices can support it. 1359*8975f5c5SAndroid Build Coastguard Worker return devices, {} 1360*8975f5c5SAndroid Build Coastguard Worker fully_supported = [] 1361*8975f5c5SAndroid Build Coastguard Worker not_supported_reasons = {} 1362*8975f5c5SAndroid Build Coastguard Worker for device in devices: 1363*8975f5c5SAndroid Build Coastguard Worker device_abis = device.GetSupportedABIs() 1364*8975f5c5SAndroid Build Coastguard Worker device_primary_abi = device_abis[0] 1365*8975f5c5SAndroid Build Coastguard Worker logging.debug('Device primary: %s', device_primary_abi) 1366*8975f5c5SAndroid Build Coastguard Worker logging.debug('Device supports: %r', device_abis) 1367*8975f5c5SAndroid Build Coastguard Worker 1368*8975f5c5SAndroid Build Coastguard Worker # x86/x86_64 emulators sometimes advertises arm support but arm builds do 1369*8975f5c5SAndroid Build Coastguard Worker # not work on them. Thus these non-functional ABIs need to be filtered out 1370*8975f5c5SAndroid Build Coastguard Worker # here to avoid resulting in hard to understand runtime failures. 1371*8975f5c5SAndroid Build Coastguard Worker if device_primary_abi in ('x86', 'x86_64'): 1372*8975f5c5SAndroid Build Coastguard Worker device_abis = [abi for abi in device_abis if not abi.startswith('arm')] 1373*8975f5c5SAndroid Build Coastguard Worker logging.debug('Device supports (filtered): %r', device_abis) 1374*8975f5c5SAndroid Build Coastguard Worker 1375*8975f5c5SAndroid Build Coastguard Worker if any(abi in app_abis for abi in device_abis): 1376*8975f5c5SAndroid Build Coastguard Worker fully_supported.append(device) 1377*8975f5c5SAndroid Build Coastguard Worker else: # No common supported ABIs between the device and app. 1378*8975f5c5SAndroid Build Coastguard Worker if device_primary_abi == 'x86': 1379*8975f5c5SAndroid Build Coastguard Worker target_cpu = 'x86' 1380*8975f5c5SAndroid Build Coastguard Worker elif device_primary_abi == 'x86_64': 1381*8975f5c5SAndroid Build Coastguard Worker target_cpu = 'x64' 1382*8975f5c5SAndroid Build Coastguard Worker elif device_primary_abi.startswith('arm64'): 1383*8975f5c5SAndroid Build Coastguard Worker target_cpu = 'arm64' 1384*8975f5c5SAndroid Build Coastguard Worker elif device_primary_abi.startswith('armeabi'): 1385*8975f5c5SAndroid Build Coastguard Worker target_cpu = 'arm' 1386*8975f5c5SAndroid Build Coastguard Worker else: 1387*8975f5c5SAndroid Build Coastguard Worker target_cpu = '<something else>' 1388*8975f5c5SAndroid Build Coastguard Worker # pylint: disable=line-too-long 1389*8975f5c5SAndroid Build Coastguard Worker native_lib_link = 'https://chromium.googlesource.com/chromium/src/+/main/docs/android_native_libraries.md' 1390*8975f5c5SAndroid Build Coastguard Worker not_supported_reasons[device.serial] = ( 1391*8975f5c5SAndroid Build Coastguard Worker f"none of the app's ABIs ({','.join(app_abis)}) match this " 1392*8975f5c5SAndroid Build Coastguard Worker f"device's ABIs ({','.join(device_abis)}), you may need to set " 1393*8975f5c5SAndroid Build Coastguard Worker f'target_cpu="{target_cpu}" in your args.gn. If you already set ' 1394*8975f5c5SAndroid Build Coastguard Worker 'the target_cpu arg, you may need to use one of the _64 or _64_32 ' 1395*8975f5c5SAndroid Build Coastguard Worker f'targets, see {native_lib_link} for more details.') 1396*8975f5c5SAndroid Build Coastguard Worker return fully_supported, not_supported_reasons 1397*8975f5c5SAndroid Build Coastguard Worker 1398*8975f5c5SAndroid Build Coastguard Worker def ProcessArgs(self, args): 1399*8975f5c5SAndroid Build Coastguard Worker self.args = args 1400*8975f5c5SAndroid Build Coastguard Worker # Ensure these keys always exist. They are set by wrapper scripts, but not 1401*8975f5c5SAndroid Build Coastguard Worker # always added when not using wrapper scripts. 1402*8975f5c5SAndroid Build Coastguard Worker args.__dict__.setdefault('apk_path', None) 1403*8975f5c5SAndroid Build Coastguard Worker args.__dict__.setdefault('incremental_json', None) 1404*8975f5c5SAndroid Build Coastguard Worker 1405*8975f5c5SAndroid Build Coastguard Worker self.incremental_apk_path = None 1406*8975f5c5SAndroid Build Coastguard Worker install_dict = None 1407*8975f5c5SAndroid Build Coastguard Worker if args.incremental_json and not (self.supports_incremental and 1408*8975f5c5SAndroid Build Coastguard Worker args.non_incremental): 1409*8975f5c5SAndroid Build Coastguard Worker with open(args.incremental_json) as f: 1410*8975f5c5SAndroid Build Coastguard Worker install_dict = json.load(f) 1411*8975f5c5SAndroid Build Coastguard Worker self.incremental_apk_path = os.path.join(args.output_directory, 1412*8975f5c5SAndroid Build Coastguard Worker install_dict['apk_path']) 1413*8975f5c5SAndroid Build Coastguard Worker if not os.path.exists(self.incremental_apk_path): 1414*8975f5c5SAndroid Build Coastguard Worker self.incremental_apk_path = None 1415*8975f5c5SAndroid Build Coastguard Worker 1416*8975f5c5SAndroid Build Coastguard Worker if self.supports_incremental: 1417*8975f5c5SAndroid Build Coastguard Worker if args.incremental and args.non_incremental: 1418*8975f5c5SAndroid Build Coastguard Worker self._parser.error('Must use only one of --incremental and ' 1419*8975f5c5SAndroid Build Coastguard Worker '--non-incremental') 1420*8975f5c5SAndroid Build Coastguard Worker elif args.non_incremental: 1421*8975f5c5SAndroid Build Coastguard Worker if not args.apk_path: 1422*8975f5c5SAndroid Build Coastguard Worker self._parser.error('Apk has not been built.') 1423*8975f5c5SAndroid Build Coastguard Worker elif args.incremental: 1424*8975f5c5SAndroid Build Coastguard Worker if not self.incremental_apk_path: 1425*8975f5c5SAndroid Build Coastguard Worker self._parser.error('Incremental apk has not been built.') 1426*8975f5c5SAndroid Build Coastguard Worker args.apk_path = None 1427*8975f5c5SAndroid Build Coastguard Worker 1428*8975f5c5SAndroid Build Coastguard Worker if args.apk_path and self.incremental_apk_path: 1429*8975f5c5SAndroid Build Coastguard Worker self._parser.error('Both incremental and non-incremental apks exist. ' 1430*8975f5c5SAndroid Build Coastguard Worker 'Select using --incremental or --non-incremental') 1431*8975f5c5SAndroid Build Coastguard Worker 1432*8975f5c5SAndroid Build Coastguard Worker 1433*8975f5c5SAndroid Build Coastguard Worker # Gate apk_helper creation with _CreateApkHelpers since for bundles it takes 1434*8975f5c5SAndroid Build Coastguard Worker # a while to unpack the apks file from the aab file, so avoid this slowdown 1435*8975f5c5SAndroid Build Coastguard Worker # for simple commands that don't need apk_helper. 1436*8975f5c5SAndroid Build Coastguard Worker if self.needs_apk_helper: 1437*8975f5c5SAndroid Build Coastguard Worker if not self._CreateApkHelpers(args, self.incremental_apk_path, 1438*8975f5c5SAndroid Build Coastguard Worker install_dict): 1439*8975f5c5SAndroid Build Coastguard Worker self._parser.error('App is not built.') 1440*8975f5c5SAndroid Build Coastguard Worker 1441*8975f5c5SAndroid Build Coastguard Worker if self.needs_package_name and not args.package_name: 1442*8975f5c5SAndroid Build Coastguard Worker if self._CreateApkHelpers(args, self.incremental_apk_path, install_dict): 1443*8975f5c5SAndroid Build Coastguard Worker args.package_name = self.apk_helper.GetPackageName() 1444*8975f5c5SAndroid Build Coastguard Worker elif self._from_wrapper_script: 1445*8975f5c5SAndroid Build Coastguard Worker self._parser.error('App is not built.') 1446*8975f5c5SAndroid Build Coastguard Worker else: 1447*8975f5c5SAndroid Build Coastguard Worker self._parser.error('One of --package-name or --apk-path is required.') 1448*8975f5c5SAndroid Build Coastguard Worker 1449*8975f5c5SAndroid Build Coastguard Worker self.devices = [] 1450*8975f5c5SAndroid Build Coastguard Worker if self.need_device_args: 1451*8975f5c5SAndroid Build Coastguard Worker # Avoid filtering by ABIs with catapult since some x86 or x86_64 emulators 1452*8975f5c5SAndroid Build Coastguard Worker # can still work with the right target_cpu GN arg and the right targets. 1453*8975f5c5SAndroid Build Coastguard Worker # Doing this manually allows us to output more informative warnings to 1454*8975f5c5SAndroid Build Coastguard Worker # help devs towards the right course, see: https://crbug.com/1335139 1455*8975f5c5SAndroid Build Coastguard Worker available_devices = device_utils.DeviceUtils.HealthyDevices( 1456*8975f5c5SAndroid Build Coastguard Worker device_arg=args.devices, 1457*8975f5c5SAndroid Build Coastguard Worker enable_device_files_cache=bool(args.output_directory), 1458*8975f5c5SAndroid Build Coastguard Worker default_retries=0) 1459*8975f5c5SAndroid Build Coastguard Worker if not available_devices: 1460*8975f5c5SAndroid Build Coastguard Worker raise Exception('Cannot find any available devices.') 1461*8975f5c5SAndroid Build Coastguard Worker 1462*8975f5c5SAndroid Build Coastguard Worker if not self._CreateApkHelpers(args, self.incremental_apk_path, 1463*8975f5c5SAndroid Build Coastguard Worker install_dict): 1464*8975f5c5SAndroid Build Coastguard Worker self.devices = available_devices 1465*8975f5c5SAndroid Build Coastguard Worker else: 1466*8975f5c5SAndroid Build Coastguard Worker fully_supported, not_supported_reasons = self._FindSupportedDevices( 1467*8975f5c5SAndroid Build Coastguard Worker available_devices) 1468*8975f5c5SAndroid Build Coastguard Worker reason_string = '\n'.join( 1469*8975f5c5SAndroid Build Coastguard Worker 'The device (serial={}) is not supported because {}'.format( 1470*8975f5c5SAndroid Build Coastguard Worker serial, reason) 1471*8975f5c5SAndroid Build Coastguard Worker for serial, reason in not_supported_reasons.items()) 1472*8975f5c5SAndroid Build Coastguard Worker if args.devices: 1473*8975f5c5SAndroid Build Coastguard Worker if reason_string: 1474*8975f5c5SAndroid Build Coastguard Worker logging.warning('Devices not supported: %s', reason_string) 1475*8975f5c5SAndroid Build Coastguard Worker self.devices = available_devices 1476*8975f5c5SAndroid Build Coastguard Worker elif fully_supported: 1477*8975f5c5SAndroid Build Coastguard Worker self.devices = fully_supported 1478*8975f5c5SAndroid Build Coastguard Worker else: 1479*8975f5c5SAndroid Build Coastguard Worker raise Exception('Cannot find any supported devices for this app.\n\n' 1480*8975f5c5SAndroid Build Coastguard Worker f'{reason_string}') 1481*8975f5c5SAndroid Build Coastguard Worker 1482*8975f5c5SAndroid Build Coastguard Worker # TODO(agrieve): Device cache should not depend on output directory. 1483*8975f5c5SAndroid Build Coastguard Worker # Maybe put into /tmp? 1484*8975f5c5SAndroid Build Coastguard Worker _LoadDeviceCaches(self.devices, args.output_directory) 1485*8975f5c5SAndroid Build Coastguard Worker 1486*8975f5c5SAndroid Build Coastguard Worker try: 1487*8975f5c5SAndroid Build Coastguard Worker if len(self.devices) > 1: 1488*8975f5c5SAndroid Build Coastguard Worker if not self.supports_multiple_devices: 1489*8975f5c5SAndroid Build Coastguard Worker self._parser.error(device_errors.MultipleDevicesError(self.devices)) 1490*8975f5c5SAndroid Build Coastguard Worker if not args.all and not args.devices: 1491*8975f5c5SAndroid Build Coastguard Worker self._parser.error(_GenerateMissingAllFlagMessage(self.devices)) 1492*8975f5c5SAndroid Build Coastguard Worker # Save cache now if command will not get a chance to afterwards. 1493*8975f5c5SAndroid Build Coastguard Worker if self.calls_exec: 1494*8975f5c5SAndroid Build Coastguard Worker _SaveDeviceCaches(self.devices, args.output_directory) 1495*8975f5c5SAndroid Build Coastguard Worker except: 1496*8975f5c5SAndroid Build Coastguard Worker _SaveDeviceCaches(self.devices, args.output_directory) 1497*8975f5c5SAndroid Build Coastguard Worker raise 1498*8975f5c5SAndroid Build Coastguard Worker 1499*8975f5c5SAndroid Build Coastguard Worker 1500*8975f5c5SAndroid Build Coastguard Workerclass _DevicesCommand(_Command): 1501*8975f5c5SAndroid Build Coastguard Worker name = 'devices' 1502*8975f5c5SAndroid Build Coastguard Worker description = 'Describe attached devices.' 1503*8975f5c5SAndroid Build Coastguard Worker all_devices_by_default = True 1504*8975f5c5SAndroid Build Coastguard Worker 1505*8975f5c5SAndroid Build Coastguard Worker def Run(self): 1506*8975f5c5SAndroid Build Coastguard Worker print(_GenerateAvailableDevicesMessage(self.devices)) 1507*8975f5c5SAndroid Build Coastguard Worker 1508*8975f5c5SAndroid Build Coastguard Worker 1509*8975f5c5SAndroid Build Coastguard Workerclass _PackageInfoCommand(_Command): 1510*8975f5c5SAndroid Build Coastguard Worker name = 'package-info' 1511*8975f5c5SAndroid Build Coastguard Worker description = 'Show various attributes of this app.' 1512*8975f5c5SAndroid Build Coastguard Worker need_device_args = False 1513*8975f5c5SAndroid Build Coastguard Worker needs_package_name = True 1514*8975f5c5SAndroid Build Coastguard Worker needs_apk_helper = True 1515*8975f5c5SAndroid Build Coastguard Worker 1516*8975f5c5SAndroid Build Coastguard Worker def Run(self): 1517*8975f5c5SAndroid Build Coastguard Worker # Format all (even ints) as strings, to handle cases where APIs return None 1518*8975f5c5SAndroid Build Coastguard Worker print('Package name: "%s"' % self.args.package_name) 1519*8975f5c5SAndroid Build Coastguard Worker print('versionCode: %s' % self.apk_helper.GetVersionCode()) 1520*8975f5c5SAndroid Build Coastguard Worker print('versionName: "%s"' % self.apk_helper.GetVersionName()) 1521*8975f5c5SAndroid Build Coastguard Worker print('minSdkVersion: %s' % self.apk_helper.GetMinSdkVersion()) 1522*8975f5c5SAndroid Build Coastguard Worker print('targetSdkVersion: %s' % self.apk_helper.GetTargetSdkVersion()) 1523*8975f5c5SAndroid Build Coastguard Worker print('Supported ABIs: %r' % self.apk_helper.GetAbis()) 1524*8975f5c5SAndroid Build Coastguard Worker 1525*8975f5c5SAndroid Build Coastguard Worker 1526*8975f5c5SAndroid Build Coastguard Workerclass _InstallCommand(_Command): 1527*8975f5c5SAndroid Build Coastguard Worker name = 'install' 1528*8975f5c5SAndroid Build Coastguard Worker description = 'Installs the APK or bundle to one or more devices.' 1529*8975f5c5SAndroid Build Coastguard Worker needs_package_name = True 1530*8975f5c5SAndroid Build Coastguard Worker needs_apk_helper = True 1531*8975f5c5SAndroid Build Coastguard Worker supports_incremental = True 1532*8975f5c5SAndroid Build Coastguard Worker default_modules = [] 1533*8975f5c5SAndroid Build Coastguard Worker 1534*8975f5c5SAndroid Build Coastguard Worker def _RegisterExtraArgs(self, group): 1535*8975f5c5SAndroid Build Coastguard Worker if self.is_bundle: 1536*8975f5c5SAndroid Build Coastguard Worker group.add_argument( 1537*8975f5c5SAndroid Build Coastguard Worker '--locales', 1538*8975f5c5SAndroid Build Coastguard Worker action='append', 1539*8975f5c5SAndroid Build Coastguard Worker help= 1540*8975f5c5SAndroid Build Coastguard Worker 'Locale splits to install (english is in base, so always installed).') 1541*8975f5c5SAndroid Build Coastguard Worker group.add_argument( 1542*8975f5c5SAndroid Build Coastguard Worker '-m', 1543*8975f5c5SAndroid Build Coastguard Worker '--module', 1544*8975f5c5SAndroid Build Coastguard Worker action='append', 1545*8975f5c5SAndroid Build Coastguard Worker default=self.default_modules, 1546*8975f5c5SAndroid Build Coastguard Worker help='Module to install. Can be specified multiple times.') 1547*8975f5c5SAndroid Build Coastguard Worker group.add_argument( 1548*8975f5c5SAndroid Build Coastguard Worker '-f', 1549*8975f5c5SAndroid Build Coastguard Worker '--fake', 1550*8975f5c5SAndroid Build Coastguard Worker action='append', 1551*8975f5c5SAndroid Build Coastguard Worker default=[], 1552*8975f5c5SAndroid Build Coastguard Worker help='Fake bundle module install. Can be specified multiple times. ' 1553*8975f5c5SAndroid Build Coastguard Worker 'Requires \'-m {0}\' to be given, and \'-f {0}\' is illegal.'.format( 1554*8975f5c5SAndroid Build Coastguard Worker BASE_MODULE)) 1555*8975f5c5SAndroid Build Coastguard Worker # Add even if |self.default_modules| is empty, for consistency. 1556*8975f5c5SAndroid Build Coastguard Worker group.add_argument('--no-module', 1557*8975f5c5SAndroid Build Coastguard Worker action='append', 1558*8975f5c5SAndroid Build Coastguard Worker choices=self.default_modules, 1559*8975f5c5SAndroid Build Coastguard Worker default=[], 1560*8975f5c5SAndroid Build Coastguard Worker help='Module to exclude from default install.') 1561*8975f5c5SAndroid Build Coastguard Worker 1562*8975f5c5SAndroid Build Coastguard Worker def Run(self): 1563*8975f5c5SAndroid Build Coastguard Worker if self.additional_apk_helpers: 1564*8975f5c5SAndroid Build Coastguard Worker for additional_apk_helper in self.additional_apk_helpers: 1565*8975f5c5SAndroid Build Coastguard Worker _InstallApk(self.devices, additional_apk_helper, None) 1566*8975f5c5SAndroid Build Coastguard Worker if self.is_bundle: 1567*8975f5c5SAndroid Build Coastguard Worker modules = list( 1568*8975f5c5SAndroid Build Coastguard Worker set(self.args.module) - set(self.args.no_module) - 1569*8975f5c5SAndroid Build Coastguard Worker set(self.args.fake)) 1570*8975f5c5SAndroid Build Coastguard Worker _InstallBundle(self.devices, self.apk_helper, modules, self.args.fake, 1571*8975f5c5SAndroid Build Coastguard Worker self.args.locales) 1572*8975f5c5SAndroid Build Coastguard Worker else: 1573*8975f5c5SAndroid Build Coastguard Worker _InstallApk(self.devices, self.apk_helper, self.install_dict) 1574*8975f5c5SAndroid Build Coastguard Worker if self.args.is_official_build: 1575*8975f5c5SAndroid Build Coastguard Worker _RunCompileDex(self.devices, self.args.package_name, 'speed') 1576*8975f5c5SAndroid Build Coastguard Worker 1577*8975f5c5SAndroid Build Coastguard Worker 1578*8975f5c5SAndroid Build Coastguard Workerclass _UninstallCommand(_Command): 1579*8975f5c5SAndroid Build Coastguard Worker name = 'uninstall' 1580*8975f5c5SAndroid Build Coastguard Worker description = 'Removes the APK or bundle from one or more devices.' 1581*8975f5c5SAndroid Build Coastguard Worker needs_package_name = True 1582*8975f5c5SAndroid Build Coastguard Worker 1583*8975f5c5SAndroid Build Coastguard Worker def Run(self): 1584*8975f5c5SAndroid Build Coastguard Worker _UninstallApk(self.devices, self.install_dict, self.args.package_name) 1585*8975f5c5SAndroid Build Coastguard Worker 1586*8975f5c5SAndroid Build Coastguard Worker 1587*8975f5c5SAndroid Build Coastguard Workerclass _SetWebViewProviderCommand(_Command): 1588*8975f5c5SAndroid Build Coastguard Worker name = 'set-webview-provider' 1589*8975f5c5SAndroid Build Coastguard Worker description = ("Sets the device's WebView provider to this APK's " 1590*8975f5c5SAndroid Build Coastguard Worker "package name.") 1591*8975f5c5SAndroid Build Coastguard Worker needs_package_name = True 1592*8975f5c5SAndroid Build Coastguard Worker needs_apk_helper = True 1593*8975f5c5SAndroid Build Coastguard Worker 1594*8975f5c5SAndroid Build Coastguard Worker def Run(self): 1595*8975f5c5SAndroid Build Coastguard Worker if not _IsWebViewProvider(self.apk_helper): 1596*8975f5c5SAndroid Build Coastguard Worker raise Exception('This package does not have a WebViewLibrary meta-data ' 1597*8975f5c5SAndroid Build Coastguard Worker 'tag. Are you sure it contains a WebView implementation?') 1598*8975f5c5SAndroid Build Coastguard Worker _SetWebViewProvider(self.devices, self.args.package_name) 1599*8975f5c5SAndroid Build Coastguard Worker 1600*8975f5c5SAndroid Build Coastguard Worker 1601*8975f5c5SAndroid Build Coastguard Workerclass _LaunchCommand(_Command): 1602*8975f5c5SAndroid Build Coastguard Worker name = 'launch' 1603*8975f5c5SAndroid Build Coastguard Worker description = ('Sends a launch intent for the APK or bundle after first ' 1604*8975f5c5SAndroid Build Coastguard Worker 'writing the command-line flags file.') 1605*8975f5c5SAndroid Build Coastguard Worker needs_package_name = True 1606*8975f5c5SAndroid Build Coastguard Worker accepts_command_line_flags = True 1607*8975f5c5SAndroid Build Coastguard Worker all_devices_by_default = True 1608*8975f5c5SAndroid Build Coastguard Worker 1609*8975f5c5SAndroid Build Coastguard Worker def _RegisterExtraArgs(self, group): 1610*8975f5c5SAndroid Build Coastguard Worker group.add_argument('-w', '--wait-for-java-debugger', action='store_true', 1611*8975f5c5SAndroid Build Coastguard Worker help='Pause execution until debugger attaches. Applies ' 1612*8975f5c5SAndroid Build Coastguard Worker 'only to the main process. To have renderers wait, ' 1613*8975f5c5SAndroid Build Coastguard Worker 'use --args="--renderer-wait-for-java-debugger"') 1614*8975f5c5SAndroid Build Coastguard Worker group.add_argument('--debug-process-name', 1615*8975f5c5SAndroid Build Coastguard Worker help='Name of the process to debug. ' 1616*8975f5c5SAndroid Build Coastguard Worker 'E.g. "privileged_process0", or "foo.bar:baz"') 1617*8975f5c5SAndroid Build Coastguard Worker group.add_argument('--nokill', action='store_true', 1618*8975f5c5SAndroid Build Coastguard Worker help='Do not set the debug-app, nor set command-line ' 1619*8975f5c5SAndroid Build Coastguard Worker 'flags. Useful to load a URL without having the ' 1620*8975f5c5SAndroid Build Coastguard Worker 'app restart.') 1621*8975f5c5SAndroid Build Coastguard Worker group.add_argument('url', nargs='?', help='A URL to launch with.') 1622*8975f5c5SAndroid Build Coastguard Worker 1623*8975f5c5SAndroid Build Coastguard Worker def Run(self): 1624*8975f5c5SAndroid Build Coastguard Worker if self.is_test_apk: 1625*8975f5c5SAndroid Build Coastguard Worker raise Exception('Use the bin/run_* scripts to run test apks.') 1626*8975f5c5SAndroid Build Coastguard Worker _LaunchUrl(self.devices, 1627*8975f5c5SAndroid Build Coastguard Worker self.args.package_name, 1628*8975f5c5SAndroid Build Coastguard Worker argv=self.args.args, 1629*8975f5c5SAndroid Build Coastguard Worker command_line_flags_file=self.args.command_line_flags_file, 1630*8975f5c5SAndroid Build Coastguard Worker url=self.args.url, 1631*8975f5c5SAndroid Build Coastguard Worker wait_for_java_debugger=self.args.wait_for_java_debugger, 1632*8975f5c5SAndroid Build Coastguard Worker debug_process_name=self.args.debug_process_name, 1633*8975f5c5SAndroid Build Coastguard Worker nokill=self.args.nokill) 1634*8975f5c5SAndroid Build Coastguard Worker 1635*8975f5c5SAndroid Build Coastguard Worker 1636*8975f5c5SAndroid Build Coastguard Workerclass _StopCommand(_Command): 1637*8975f5c5SAndroid Build Coastguard Worker name = 'stop' 1638*8975f5c5SAndroid Build Coastguard Worker description = 'Force-stops the app.' 1639*8975f5c5SAndroid Build Coastguard Worker needs_package_name = True 1640*8975f5c5SAndroid Build Coastguard Worker all_devices_by_default = True 1641*8975f5c5SAndroid Build Coastguard Worker 1642*8975f5c5SAndroid Build Coastguard Worker def Run(self): 1643*8975f5c5SAndroid Build Coastguard Worker device_utils.DeviceUtils.parallel(self.devices).ForceStop( 1644*8975f5c5SAndroid Build Coastguard Worker self.args.package_name) 1645*8975f5c5SAndroid Build Coastguard Worker 1646*8975f5c5SAndroid Build Coastguard Worker 1647*8975f5c5SAndroid Build Coastguard Workerclass _ClearDataCommand(_Command): 1648*8975f5c5SAndroid Build Coastguard Worker name = 'clear-data' 1649*8975f5c5SAndroid Build Coastguard Worker descriptions = 'Clears all app data.' 1650*8975f5c5SAndroid Build Coastguard Worker needs_package_name = True 1651*8975f5c5SAndroid Build Coastguard Worker all_devices_by_default = True 1652*8975f5c5SAndroid Build Coastguard Worker 1653*8975f5c5SAndroid Build Coastguard Worker def Run(self): 1654*8975f5c5SAndroid Build Coastguard Worker device_utils.DeviceUtils.parallel(self.devices).ClearApplicationState( 1655*8975f5c5SAndroid Build Coastguard Worker self.args.package_name) 1656*8975f5c5SAndroid Build Coastguard Worker 1657*8975f5c5SAndroid Build Coastguard Worker 1658*8975f5c5SAndroid Build Coastguard Workerclass _ArgvCommand(_Command): 1659*8975f5c5SAndroid Build Coastguard Worker name = 'argv' 1660*8975f5c5SAndroid Build Coastguard Worker description = 'Display and optionally update command-line flags file.' 1661*8975f5c5SAndroid Build Coastguard Worker needs_package_name = True 1662*8975f5c5SAndroid Build Coastguard Worker accepts_command_line_flags = True 1663*8975f5c5SAndroid Build Coastguard Worker all_devices_by_default = True 1664*8975f5c5SAndroid Build Coastguard Worker 1665*8975f5c5SAndroid Build Coastguard Worker def Run(self): 1666*8975f5c5SAndroid Build Coastguard Worker command_line_flags_file = self.args.command_line_flags_file 1667*8975f5c5SAndroid Build Coastguard Worker argv = self.args.args 1668*8975f5c5SAndroid Build Coastguard Worker devices = self.devices 1669*8975f5c5SAndroid Build Coastguard Worker parallel_devices = device_utils.DeviceUtils.parallel(devices) 1670*8975f5c5SAndroid Build Coastguard Worker 1671*8975f5c5SAndroid Build Coastguard Worker if argv is not None: 1672*8975f5c5SAndroid Build Coastguard Worker parallel_devices.pMap( 1673*8975f5c5SAndroid Build Coastguard Worker lambda d: _UpdateDeviceFlags(d, command_line_flags_file, argv)) 1674*8975f5c5SAndroid Build Coastguard Worker 1675*8975f5c5SAndroid Build Coastguard Worker outputs = parallel_devices.pMap( 1676*8975f5c5SAndroid Build Coastguard Worker lambda d: _ReadDeviceFlags(d, command_line_flags_file) or '').pGet(None) 1677*8975f5c5SAndroid Build Coastguard Worker 1678*8975f5c5SAndroid Build Coastguard Worker print(f'Showing flags via /data/local/tmp/{command_line_flags_file}:') 1679*8975f5c5SAndroid Build Coastguard Worker for flags in _PrintPerDeviceOutput(devices, outputs, single_line=True): 1680*8975f5c5SAndroid Build Coastguard Worker print(flags or 'No flags set.') 1681*8975f5c5SAndroid Build Coastguard Worker 1682*8975f5c5SAndroid Build Coastguard Worker 1683*8975f5c5SAndroid Build Coastguard Workerclass _GdbCommand(_Command): 1684*8975f5c5SAndroid Build Coastguard Worker name = 'gdb' 1685*8975f5c5SAndroid Build Coastguard Worker description = 'Runs //build/android/adb_gdb with apk-specific args.' 1686*8975f5c5SAndroid Build Coastguard Worker long_description = description + """ 1687*8975f5c5SAndroid Build Coastguard Worker 1688*8975f5c5SAndroid Build Coastguard WorkerTo attach to a process other than the APK's main process, use --pid=1234. 1689*8975f5c5SAndroid Build Coastguard WorkerTo list all PIDs, use the "ps" command. 1690*8975f5c5SAndroid Build Coastguard Worker 1691*8975f5c5SAndroid Build Coastguard WorkerIf no apk process is currently running, sends a launch intent. 1692*8975f5c5SAndroid Build Coastguard Worker""" 1693*8975f5c5SAndroid Build Coastguard Worker needs_package_name = True 1694*8975f5c5SAndroid Build Coastguard Worker needs_output_directory = True 1695*8975f5c5SAndroid Build Coastguard Worker calls_exec = True 1696*8975f5c5SAndroid Build Coastguard Worker supports_multiple_devices = False 1697*8975f5c5SAndroid Build Coastguard Worker 1698*8975f5c5SAndroid Build Coastguard Worker def Run(self): 1699*8975f5c5SAndroid Build Coastguard Worker _RunGdb(self.devices[0], self.args.package_name, 1700*8975f5c5SAndroid Build Coastguard Worker self.args.debug_process_name, self.args.pid, 1701*8975f5c5SAndroid Build Coastguard Worker self.args.output_directory, self.args.target_cpu, self.args.port, 1702*8975f5c5SAndroid Build Coastguard Worker self.args.ide, bool(self.args.verbose_count)) 1703*8975f5c5SAndroid Build Coastguard Worker 1704*8975f5c5SAndroid Build Coastguard Worker def _RegisterExtraArgs(self, group): 1705*8975f5c5SAndroid Build Coastguard Worker pid_group = group.add_mutually_exclusive_group() 1706*8975f5c5SAndroid Build Coastguard Worker pid_group.add_argument('--debug-process-name', 1707*8975f5c5SAndroid Build Coastguard Worker help='Name of the process to attach to. ' 1708*8975f5c5SAndroid Build Coastguard Worker 'E.g. "privileged_process0", or "foo.bar:baz"') 1709*8975f5c5SAndroid Build Coastguard Worker pid_group.add_argument('--pid', 1710*8975f5c5SAndroid Build Coastguard Worker help='The process ID to attach to. Defaults to ' 1711*8975f5c5SAndroid Build Coastguard Worker 'the main process for the package.') 1712*8975f5c5SAndroid Build Coastguard Worker group.add_argument('--ide', action='store_true', 1713*8975f5c5SAndroid Build Coastguard Worker help='Rather than enter a gdb prompt, set up the ' 1714*8975f5c5SAndroid Build Coastguard Worker 'gdb connection and wait for an IDE to ' 1715*8975f5c5SAndroid Build Coastguard Worker 'connect.') 1716*8975f5c5SAndroid Build Coastguard Worker # Same default port that ndk-gdb.py uses. 1717*8975f5c5SAndroid Build Coastguard Worker group.add_argument('--port', type=int, default=5039, 1718*8975f5c5SAndroid Build Coastguard Worker help='Use the given port for the GDB connection') 1719*8975f5c5SAndroid Build Coastguard Worker 1720*8975f5c5SAndroid Build Coastguard Worker 1721*8975f5c5SAndroid Build Coastguard Workerclass _LldbCommand(_Command): 1722*8975f5c5SAndroid Build Coastguard Worker name = 'lldb' 1723*8975f5c5SAndroid Build Coastguard Worker description = 'Runs //build/android/connect_lldb.sh with apk-specific args.' 1724*8975f5c5SAndroid Build Coastguard Worker long_description = description + """ 1725*8975f5c5SAndroid Build Coastguard Worker 1726*8975f5c5SAndroid Build Coastguard WorkerTo attach to a process other than the APK's main process, use --pid=1234. 1727*8975f5c5SAndroid Build Coastguard WorkerTo list all PIDs, use the "ps" command. 1728*8975f5c5SAndroid Build Coastguard Worker 1729*8975f5c5SAndroid Build Coastguard WorkerIf no apk process is currently running, sends a launch intent. 1730*8975f5c5SAndroid Build Coastguard Worker""" 1731*8975f5c5SAndroid Build Coastguard Worker needs_package_name = True 1732*8975f5c5SAndroid Build Coastguard Worker needs_output_directory = True 1733*8975f5c5SAndroid Build Coastguard Worker calls_exec = True 1734*8975f5c5SAndroid Build Coastguard Worker supports_multiple_devices = False 1735*8975f5c5SAndroid Build Coastguard Worker 1736*8975f5c5SAndroid Build Coastguard Worker def Run(self): 1737*8975f5c5SAndroid Build Coastguard Worker _RunLldb(device=self.devices[0], 1738*8975f5c5SAndroid Build Coastguard Worker package_name=self.args.package_name, 1739*8975f5c5SAndroid Build Coastguard Worker debug_process_name=self.args.debug_process_name, 1740*8975f5c5SAndroid Build Coastguard Worker pid=self.args.pid, 1741*8975f5c5SAndroid Build Coastguard Worker output_directory=self.args.output_directory, 1742*8975f5c5SAndroid Build Coastguard Worker port=self.args.port, 1743*8975f5c5SAndroid Build Coastguard Worker target_cpu=self.args.target_cpu, 1744*8975f5c5SAndroid Build Coastguard Worker ndk_dir=self.args.ndk_dir, 1745*8975f5c5SAndroid Build Coastguard Worker lldb_server=self.args.lldb_server, 1746*8975f5c5SAndroid Build Coastguard Worker lldb=self.args.lldb, 1747*8975f5c5SAndroid Build Coastguard Worker verbose=bool(self.args.verbose_count)) 1748*8975f5c5SAndroid Build Coastguard Worker 1749*8975f5c5SAndroid Build Coastguard Worker def _RegisterExtraArgs(self, group): 1750*8975f5c5SAndroid Build Coastguard Worker pid_group = group.add_mutually_exclusive_group() 1751*8975f5c5SAndroid Build Coastguard Worker pid_group.add_argument('--debug-process-name', 1752*8975f5c5SAndroid Build Coastguard Worker help='Name of the process to attach to. ' 1753*8975f5c5SAndroid Build Coastguard Worker 'E.g. "privileged_process0", or "foo.bar:baz"') 1754*8975f5c5SAndroid Build Coastguard Worker pid_group.add_argument('--pid', 1755*8975f5c5SAndroid Build Coastguard Worker help='The process ID to attach to. Defaults to ' 1756*8975f5c5SAndroid Build Coastguard Worker 'the main process for the package.') 1757*8975f5c5SAndroid Build Coastguard Worker group.add_argument('--ndk-dir', 1758*8975f5c5SAndroid Build Coastguard Worker help='Select alternative NDK root directory.') 1759*8975f5c5SAndroid Build Coastguard Worker group.add_argument('--lldb-server', 1760*8975f5c5SAndroid Build Coastguard Worker help='Select alternative on-device lldb-server.') 1761*8975f5c5SAndroid Build Coastguard Worker group.add_argument('--lldb', help='Select alternative client lldb.sh.') 1762*8975f5c5SAndroid Build Coastguard Worker # Same default port that ndk-gdb.py uses. 1763*8975f5c5SAndroid Build Coastguard Worker group.add_argument('--port', 1764*8975f5c5SAndroid Build Coastguard Worker type=int, 1765*8975f5c5SAndroid Build Coastguard Worker default=5039, 1766*8975f5c5SAndroid Build Coastguard Worker help='Use the given port for the LLDB connection') 1767*8975f5c5SAndroid Build Coastguard Worker 1768*8975f5c5SAndroid Build Coastguard Worker 1769*8975f5c5SAndroid Build Coastguard Workerclass _LogcatCommand(_Command): 1770*8975f5c5SAndroid Build Coastguard Worker name = 'logcat' 1771*8975f5c5SAndroid Build Coastguard Worker description = 'Runs "adb logcat" with filters relevant the current APK.' 1772*8975f5c5SAndroid Build Coastguard Worker long_description = description + """ 1773*8975f5c5SAndroid Build Coastguard Worker 1774*8975f5c5SAndroid Build Coastguard Worker"Relevant filters" means: 1775*8975f5c5SAndroid Build Coastguard Worker * Log messages from processes belonging to the apk, 1776*8975f5c5SAndroid Build Coastguard Worker * Plus log messages from log tags: ActivityManager|DEBUG, 1777*8975f5c5SAndroid Build Coastguard Worker * Plus fatal logs from any process, 1778*8975f5c5SAndroid Build Coastguard Worker * Minus spamy dalvikvm logs (for pre-L devices). 1779*8975f5c5SAndroid Build Coastguard Worker 1780*8975f5c5SAndroid Build Coastguard WorkerColors: 1781*8975f5c5SAndroid Build Coastguard Worker * Primary process is white 1782*8975f5c5SAndroid Build Coastguard Worker * Other processes (gpu, renderer) are yellow 1783*8975f5c5SAndroid Build Coastguard Worker * Non-apk processes are grey 1784*8975f5c5SAndroid Build Coastguard Worker * UI thread has a bolded Thread-ID 1785*8975f5c5SAndroid Build Coastguard Worker 1786*8975f5c5SAndroid Build Coastguard WorkerJava stack traces are detected and deobfuscated (for release builds). 1787*8975f5c5SAndroid Build Coastguard Worker 1788*8975f5c5SAndroid Build Coastguard WorkerTo disable filtering, (but keep coloring), use --verbose. 1789*8975f5c5SAndroid Build Coastguard Worker""" 1790*8975f5c5SAndroid Build Coastguard Worker needs_package_name = True 1791*8975f5c5SAndroid Build Coastguard Worker supports_multiple_devices = False 1792*8975f5c5SAndroid Build Coastguard Worker 1793*8975f5c5SAndroid Build Coastguard Worker def Run(self): 1794*8975f5c5SAndroid Build Coastguard Worker deobfuscate = None 1795*8975f5c5SAndroid Build Coastguard Worker if self.args.proguard_mapping_path and not self.args.no_deobfuscate: 1796*8975f5c5SAndroid Build Coastguard Worker deobfuscate = deobfuscator.Deobfuscator(self.args.proguard_mapping_path) 1797*8975f5c5SAndroid Build Coastguard Worker apk_path = self.args.apk_path or self.incremental_apk_path 1798*8975f5c5SAndroid Build Coastguard Worker if apk_path or self.bundle_generation_info: 1799*8975f5c5SAndroid Build Coastguard Worker stack_script_context = _StackScriptContext(self.args.output_directory, 1800*8975f5c5SAndroid Build Coastguard Worker apk_path, 1801*8975f5c5SAndroid Build Coastguard Worker self.bundle_generation_info, 1802*8975f5c5SAndroid Build Coastguard Worker quiet=True) 1803*8975f5c5SAndroid Build Coastguard Worker else: 1804*8975f5c5SAndroid Build Coastguard Worker stack_script_context = None 1805*8975f5c5SAndroid Build Coastguard Worker 1806*8975f5c5SAndroid Build Coastguard Worker extra_package_names = [] 1807*8975f5c5SAndroid Build Coastguard Worker if self.is_test_apk and self.additional_apk_helpers: 1808*8975f5c5SAndroid Build Coastguard Worker for additional_apk_helper in self.additional_apk_helpers: 1809*8975f5c5SAndroid Build Coastguard Worker extra_package_names.append(additional_apk_helper.GetPackageName()) 1810*8975f5c5SAndroid Build Coastguard Worker 1811*8975f5c5SAndroid Build Coastguard Worker try: 1812*8975f5c5SAndroid Build Coastguard Worker _RunLogcat(self.devices[0], 1813*8975f5c5SAndroid Build Coastguard Worker self.args.package_name, 1814*8975f5c5SAndroid Build Coastguard Worker stack_script_context, 1815*8975f5c5SAndroid Build Coastguard Worker deobfuscate, 1816*8975f5c5SAndroid Build Coastguard Worker bool(self.args.verbose_count), 1817*8975f5c5SAndroid Build Coastguard Worker self.args.exit_on_match, 1818*8975f5c5SAndroid Build Coastguard Worker extra_package_names=extra_package_names) 1819*8975f5c5SAndroid Build Coastguard Worker except KeyboardInterrupt: 1820*8975f5c5SAndroid Build Coastguard Worker pass # Don't show stack trace upon Ctrl-C 1821*8975f5c5SAndroid Build Coastguard Worker finally: 1822*8975f5c5SAndroid Build Coastguard Worker if stack_script_context: 1823*8975f5c5SAndroid Build Coastguard Worker stack_script_context.Close() 1824*8975f5c5SAndroid Build Coastguard Worker if deobfuscate: 1825*8975f5c5SAndroid Build Coastguard Worker deobfuscate.Close() 1826*8975f5c5SAndroid Build Coastguard Worker 1827*8975f5c5SAndroid Build Coastguard Worker def _RegisterExtraArgs(self, group): 1828*8975f5c5SAndroid Build Coastguard Worker if self._from_wrapper_script: 1829*8975f5c5SAndroid Build Coastguard Worker group.add_argument('--no-deobfuscate', action='store_true', 1830*8975f5c5SAndroid Build Coastguard Worker help='Disables ProGuard deobfuscation of logcat.') 1831*8975f5c5SAndroid Build Coastguard Worker else: 1832*8975f5c5SAndroid Build Coastguard Worker group.set_defaults(no_deobfuscate=False) 1833*8975f5c5SAndroid Build Coastguard Worker group.add_argument('--proguard-mapping-path', 1834*8975f5c5SAndroid Build Coastguard Worker help='Path to ProGuard map (enables deobfuscation)') 1835*8975f5c5SAndroid Build Coastguard Worker group.add_argument('--exit-on-match', 1836*8975f5c5SAndroid Build Coastguard Worker help='Exits logcat when a message matches this regex.') 1837*8975f5c5SAndroid Build Coastguard Worker 1838*8975f5c5SAndroid Build Coastguard Worker 1839*8975f5c5SAndroid Build Coastguard Workerclass _PsCommand(_Command): 1840*8975f5c5SAndroid Build Coastguard Worker name = 'ps' 1841*8975f5c5SAndroid Build Coastguard Worker description = 'Show PIDs of any APK processes currently running.' 1842*8975f5c5SAndroid Build Coastguard Worker needs_package_name = True 1843*8975f5c5SAndroid Build Coastguard Worker all_devices_by_default = True 1844*8975f5c5SAndroid Build Coastguard Worker 1845*8975f5c5SAndroid Build Coastguard Worker def Run(self): 1846*8975f5c5SAndroid Build Coastguard Worker _RunPs(self.devices, self.args.package_name) 1847*8975f5c5SAndroid Build Coastguard Worker 1848*8975f5c5SAndroid Build Coastguard Worker 1849*8975f5c5SAndroid Build Coastguard Workerclass _DiskUsageCommand(_Command): 1850*8975f5c5SAndroid Build Coastguard Worker name = 'disk-usage' 1851*8975f5c5SAndroid Build Coastguard Worker description = 'Show how much device storage is being consumed by the app.' 1852*8975f5c5SAndroid Build Coastguard Worker needs_package_name = True 1853*8975f5c5SAndroid Build Coastguard Worker all_devices_by_default = True 1854*8975f5c5SAndroid Build Coastguard Worker 1855*8975f5c5SAndroid Build Coastguard Worker def Run(self): 1856*8975f5c5SAndroid Build Coastguard Worker _RunDiskUsage(self.devices, self.args.package_name) 1857*8975f5c5SAndroid Build Coastguard Worker 1858*8975f5c5SAndroid Build Coastguard Worker 1859*8975f5c5SAndroid Build Coastguard Workerclass _MemUsageCommand(_Command): 1860*8975f5c5SAndroid Build Coastguard Worker name = 'mem-usage' 1861*8975f5c5SAndroid Build Coastguard Worker description = 'Show memory usage of currently running APK processes.' 1862*8975f5c5SAndroid Build Coastguard Worker needs_package_name = True 1863*8975f5c5SAndroid Build Coastguard Worker all_devices_by_default = True 1864*8975f5c5SAndroid Build Coastguard Worker 1865*8975f5c5SAndroid Build Coastguard Worker def _RegisterExtraArgs(self, group): 1866*8975f5c5SAndroid Build Coastguard Worker group.add_argument('--query-app', action='store_true', 1867*8975f5c5SAndroid Build Coastguard Worker help='Do not add --local to "dumpsys meminfo". This will output ' 1868*8975f5c5SAndroid Build Coastguard Worker 'additional metrics (e.g. Context count), but also cause memory ' 1869*8975f5c5SAndroid Build Coastguard Worker 'to be used in order to gather the metrics.') 1870*8975f5c5SAndroid Build Coastguard Worker 1871*8975f5c5SAndroid Build Coastguard Worker def Run(self): 1872*8975f5c5SAndroid Build Coastguard Worker _RunMemUsage(self.devices, self.args.package_name, 1873*8975f5c5SAndroid Build Coastguard Worker query_app=self.args.query_app) 1874*8975f5c5SAndroid Build Coastguard Worker 1875*8975f5c5SAndroid Build Coastguard Worker 1876*8975f5c5SAndroid Build Coastguard Workerclass _ShellCommand(_Command): 1877*8975f5c5SAndroid Build Coastguard Worker name = 'shell' 1878*8975f5c5SAndroid Build Coastguard Worker description = ('Same as "adb shell <command>", but runs as the apk\'s uid ' 1879*8975f5c5SAndroid Build Coastguard Worker '(via run-as). Useful for inspecting the app\'s data ' 1880*8975f5c5SAndroid Build Coastguard Worker 'directory.') 1881*8975f5c5SAndroid Build Coastguard Worker needs_package_name = True 1882*8975f5c5SAndroid Build Coastguard Worker 1883*8975f5c5SAndroid Build Coastguard Worker @property 1884*8975f5c5SAndroid Build Coastguard Worker def calls_exec(self): 1885*8975f5c5SAndroid Build Coastguard Worker return not self.args.cmd 1886*8975f5c5SAndroid Build Coastguard Worker 1887*8975f5c5SAndroid Build Coastguard Worker @property 1888*8975f5c5SAndroid Build Coastguard Worker def supports_multiple_devices(self): 1889*8975f5c5SAndroid Build Coastguard Worker return not self.args.cmd 1890*8975f5c5SAndroid Build Coastguard Worker 1891*8975f5c5SAndroid Build Coastguard Worker def _RegisterExtraArgs(self, group): 1892*8975f5c5SAndroid Build Coastguard Worker group.add_argument( 1893*8975f5c5SAndroid Build Coastguard Worker 'cmd', nargs=argparse.REMAINDER, help='Command to run.') 1894*8975f5c5SAndroid Build Coastguard Worker 1895*8975f5c5SAndroid Build Coastguard Worker def Run(self): 1896*8975f5c5SAndroid Build Coastguard Worker _RunShell(self.devices, self.args.package_name, self.args.cmd) 1897*8975f5c5SAndroid Build Coastguard Worker 1898*8975f5c5SAndroid Build Coastguard Worker 1899*8975f5c5SAndroid Build Coastguard Workerclass _CompileDexCommand(_Command): 1900*8975f5c5SAndroid Build Coastguard Worker name = 'compile-dex' 1901*8975f5c5SAndroid Build Coastguard Worker description = ('Applicable only for Android N+. Forces .odex files to be ' 1902*8975f5c5SAndroid Build Coastguard Worker 'compiled with the given compilation filter. To see existing ' 1903*8975f5c5SAndroid Build Coastguard Worker 'filter, use "disk-usage" command.') 1904*8975f5c5SAndroid Build Coastguard Worker needs_package_name = True 1905*8975f5c5SAndroid Build Coastguard Worker all_devices_by_default = True 1906*8975f5c5SAndroid Build Coastguard Worker 1907*8975f5c5SAndroid Build Coastguard Worker def _RegisterExtraArgs(self, group): 1908*8975f5c5SAndroid Build Coastguard Worker group.add_argument( 1909*8975f5c5SAndroid Build Coastguard Worker 'compilation_filter', 1910*8975f5c5SAndroid Build Coastguard Worker choices=['verify', 'quicken', 'space-profile', 'space', 1911*8975f5c5SAndroid Build Coastguard Worker 'speed-profile', 'speed'], 1912*8975f5c5SAndroid Build Coastguard Worker help='For WebView/Monochrome, use "speed". For other apks, use ' 1913*8975f5c5SAndroid Build Coastguard Worker '"speed-profile".') 1914*8975f5c5SAndroid Build Coastguard Worker 1915*8975f5c5SAndroid Build Coastguard Worker def Run(self): 1916*8975f5c5SAndroid Build Coastguard Worker outputs = _RunCompileDex(self.devices, self.args.package_name, 1917*8975f5c5SAndroid Build Coastguard Worker self.args.compilation_filter) 1918*8975f5c5SAndroid Build Coastguard Worker for output in _PrintPerDeviceOutput(self.devices, outputs): 1919*8975f5c5SAndroid Build Coastguard Worker for line in output: 1920*8975f5c5SAndroid Build Coastguard Worker print(line) 1921*8975f5c5SAndroid Build Coastguard Worker 1922*8975f5c5SAndroid Build Coastguard Worker 1923*8975f5c5SAndroid Build Coastguard Workerclass _PrintCertsCommand(_Command): 1924*8975f5c5SAndroid Build Coastguard Worker name = 'print-certs' 1925*8975f5c5SAndroid Build Coastguard Worker description = 'Print info about certificates used to sign this APK.' 1926*8975f5c5SAndroid Build Coastguard Worker need_device_args = False 1927*8975f5c5SAndroid Build Coastguard Worker needs_apk_helper = True 1928*8975f5c5SAndroid Build Coastguard Worker 1929*8975f5c5SAndroid Build Coastguard Worker def _RegisterExtraArgs(self, group): 1930*8975f5c5SAndroid Build Coastguard Worker group.add_argument( 1931*8975f5c5SAndroid Build Coastguard Worker '--full-cert', 1932*8975f5c5SAndroid Build Coastguard Worker action='store_true', 1933*8975f5c5SAndroid Build Coastguard Worker help=("Print the certificate's full signature, Base64-encoded. " 1934*8975f5c5SAndroid Build Coastguard Worker "Useful when configuring an Android image's " 1935*8975f5c5SAndroid Build Coastguard Worker "config_webview_packages.xml.")) 1936*8975f5c5SAndroid Build Coastguard Worker 1937*8975f5c5SAndroid Build Coastguard Worker def Run(self): 1938*8975f5c5SAndroid Build Coastguard Worker keytool = os.path.join(_JAVA_HOME, 'bin', 'keytool') 1939*8975f5c5SAndroid Build Coastguard Worker pem_certificate_pattern = re.compile( 1940*8975f5c5SAndroid Build Coastguard Worker r'-+BEGIN CERTIFICATE-+([\r\n0-9A-Za-z+/=]+)-+END CERTIFICATE-+[\r\n]*') 1941*8975f5c5SAndroid Build Coastguard Worker if self.is_bundle: 1942*8975f5c5SAndroid Build Coastguard Worker # Bundles are not signed until converted to .apks. The wrapper scripts 1943*8975f5c5SAndroid Build Coastguard Worker # record which key will be used to sign though. 1944*8975f5c5SAndroid Build Coastguard Worker with tempfile.NamedTemporaryFile() as f: 1945*8975f5c5SAndroid Build Coastguard Worker logging.warning('Bundles are not signed until turned into .apk files.') 1946*8975f5c5SAndroid Build Coastguard Worker logging.warning('Showing signing info based on associated keystore.') 1947*8975f5c5SAndroid Build Coastguard Worker cmd = [ 1948*8975f5c5SAndroid Build Coastguard Worker keytool, '-exportcert', '-keystore', 1949*8975f5c5SAndroid Build Coastguard Worker self.bundle_generation_info.keystore_path, '-storepass', 1950*8975f5c5SAndroid Build Coastguard Worker self.bundle_generation_info.keystore_password, '-alias', 1951*8975f5c5SAndroid Build Coastguard Worker self.bundle_generation_info.keystore_alias, '-file', f.name 1952*8975f5c5SAndroid Build Coastguard Worker ] 1953*8975f5c5SAndroid Build Coastguard Worker logging.warning('Running: %s', shlex.join(cmd)) 1954*8975f5c5SAndroid Build Coastguard Worker subprocess.check_output(cmd, stderr=subprocess.STDOUT) 1955*8975f5c5SAndroid Build Coastguard Worker cmd = [keytool, '-printcert', '-file', f.name] 1956*8975f5c5SAndroid Build Coastguard Worker logging.warning('Running: %s', shlex.join(cmd)) 1957*8975f5c5SAndroid Build Coastguard Worker subprocess.check_call(cmd) 1958*8975f5c5SAndroid Build Coastguard Worker if self.args.full_cert: 1959*8975f5c5SAndroid Build Coastguard Worker # Redirect stderr to hide a keytool warning about using non-standard 1960*8975f5c5SAndroid Build Coastguard Worker # keystore format. 1961*8975f5c5SAndroid Build Coastguard Worker cmd += ['-rfc'] 1962*8975f5c5SAndroid Build Coastguard Worker logging.warning('Running: %s', shlex.join(cmd)) 1963*8975f5c5SAndroid Build Coastguard Worker pem_encoded_certificate = subprocess.check_output( 1964*8975f5c5SAndroid Build Coastguard Worker cmd, stderr=subprocess.STDOUT).decode() 1965*8975f5c5SAndroid Build Coastguard Worker else: 1966*8975f5c5SAndroid Build Coastguard Worker 1967*8975f5c5SAndroid Build Coastguard Worker def run_apksigner(min_sdk_version): 1968*8975f5c5SAndroid Build Coastguard Worker cmd = [ 1969*8975f5c5SAndroid Build Coastguard Worker build_tools.GetPath('apksigner'), 'verify', '--min-sdk-version', 1970*8975f5c5SAndroid Build Coastguard Worker str(min_sdk_version), '--print-certs-pem', '--verbose', 1971*8975f5c5SAndroid Build Coastguard Worker self.apk_helper.path 1972*8975f5c5SAndroid Build Coastguard Worker ] 1973*8975f5c5SAndroid Build Coastguard Worker logging.warning('Running: %s', shlex.join(cmd)) 1974*8975f5c5SAndroid Build Coastguard Worker env = os.environ.copy() 1975*8975f5c5SAndroid Build Coastguard Worker env['PATH'] = os.path.pathsep.join( 1976*8975f5c5SAndroid Build Coastguard Worker [os.path.join(_JAVA_HOME, 'bin'), 1977*8975f5c5SAndroid Build Coastguard Worker env.get('PATH')]) 1978*8975f5c5SAndroid Build Coastguard Worker # Redirect stderr to hide verification failures (see explanation below). 1979*8975f5c5SAndroid Build Coastguard Worker return subprocess.check_output(cmd, 1980*8975f5c5SAndroid Build Coastguard Worker env=env, 1981*8975f5c5SAndroid Build Coastguard Worker universal_newlines=True, 1982*8975f5c5SAndroid Build Coastguard Worker stderr=subprocess.STDOUT) 1983*8975f5c5SAndroid Build Coastguard Worker 1984*8975f5c5SAndroid Build Coastguard Worker # apksigner's default behavior is nonintuitive: it will print "Verified 1985*8975f5c5SAndroid Build Coastguard Worker # using <scheme number>...: false" for any scheme which is obsolete for 1986*8975f5c5SAndroid Build Coastguard Worker # the APK's minSdkVersion even if it actually was signed with that scheme 1987*8975f5c5SAndroid Build Coastguard Worker # (ex. it prints "Verified using v1 scheme: false" for Monochrome because 1988*8975f5c5SAndroid Build Coastguard Worker # v1 was obsolete by N). To workaround this, we force apksigner to use the 1989*8975f5c5SAndroid Build Coastguard Worker # lowest possible minSdkVersion. We need to fallback to higher 1990*8975f5c5SAndroid Build Coastguard Worker # minSdkVersions in case the APK fails to verify for that minSdkVersion 1991*8975f5c5SAndroid Build Coastguard Worker # (which means the APK is genuinely not signed with that scheme). These 1992*8975f5c5SAndroid Build Coastguard Worker # SDK values are the highest SDK version before the next scheme is 1993*8975f5c5SAndroid Build Coastguard Worker # available: 1994*8975f5c5SAndroid Build Coastguard Worker versions = [ 1995*8975f5c5SAndroid Build Coastguard Worker version_codes.MARSHMALLOW, # before v2 launched in N 1996*8975f5c5SAndroid Build Coastguard Worker version_codes.OREO_MR1, # before v3 launched in P 1997*8975f5c5SAndroid Build Coastguard Worker version_codes.Q, # before v4 launched in R 1998*8975f5c5SAndroid Build Coastguard Worker version_codes.R, 1999*8975f5c5SAndroid Build Coastguard Worker ] 2000*8975f5c5SAndroid Build Coastguard Worker stdout = None 2001*8975f5c5SAndroid Build Coastguard Worker for min_sdk_version in versions: 2002*8975f5c5SAndroid Build Coastguard Worker try: 2003*8975f5c5SAndroid Build Coastguard Worker stdout = run_apksigner(min_sdk_version) 2004*8975f5c5SAndroid Build Coastguard Worker break 2005*8975f5c5SAndroid Build Coastguard Worker except subprocess.CalledProcessError: 2006*8975f5c5SAndroid Build Coastguard Worker # Doesn't verify with this min-sdk-version, so try again with a higher 2007*8975f5c5SAndroid Build Coastguard Worker # one 2008*8975f5c5SAndroid Build Coastguard Worker continue 2009*8975f5c5SAndroid Build Coastguard Worker if not stdout: 2010*8975f5c5SAndroid Build Coastguard Worker raise RuntimeError('apksigner was not able to verify APK') 2011*8975f5c5SAndroid Build Coastguard Worker 2012*8975f5c5SAndroid Build Coastguard Worker # Separate what the '--print-certs' flag would output vs. the additional 2013*8975f5c5SAndroid Build Coastguard Worker # signature output included by '--print-certs-pem'. The additional PEM 2014*8975f5c5SAndroid Build Coastguard Worker # output is only printed when self.args.full_cert is specified. 2015*8975f5c5SAndroid Build Coastguard Worker verification_hash_info = pem_certificate_pattern.sub('', stdout) 2016*8975f5c5SAndroid Build Coastguard Worker print(verification_hash_info) 2017*8975f5c5SAndroid Build Coastguard Worker if self.args.full_cert: 2018*8975f5c5SAndroid Build Coastguard Worker m = pem_certificate_pattern.search(stdout) 2019*8975f5c5SAndroid Build Coastguard Worker if not m: 2020*8975f5c5SAndroid Build Coastguard Worker raise Exception('apksigner did not print a certificate') 2021*8975f5c5SAndroid Build Coastguard Worker pem_encoded_certificate = m.group(0) 2022*8975f5c5SAndroid Build Coastguard Worker 2023*8975f5c5SAndroid Build Coastguard Worker 2024*8975f5c5SAndroid Build Coastguard Worker if self.args.full_cert: 2025*8975f5c5SAndroid Build Coastguard Worker m = pem_certificate_pattern.search(pem_encoded_certificate) 2026*8975f5c5SAndroid Build Coastguard Worker if not m: 2027*8975f5c5SAndroid Build Coastguard Worker raise Exception( 2028*8975f5c5SAndroid Build Coastguard Worker 'Unable to parse certificate:\n{}'.format(pem_encoded_certificate)) 2029*8975f5c5SAndroid Build Coastguard Worker signature = re.sub(r'[\r\n]+', '', m.group(1)) 2030*8975f5c5SAndroid Build Coastguard Worker print() 2031*8975f5c5SAndroid Build Coastguard Worker print('Full Signature:') 2032*8975f5c5SAndroid Build Coastguard Worker print(signature) 2033*8975f5c5SAndroid Build Coastguard Worker 2034*8975f5c5SAndroid Build Coastguard Worker 2035*8975f5c5SAndroid Build Coastguard Workerclass _ProfileCommand(_Command): 2036*8975f5c5SAndroid Build Coastguard Worker name = 'profile' 2037*8975f5c5SAndroid Build Coastguard Worker description = ('Run the simpleperf sampling CPU profiler on the currently-' 2038*8975f5c5SAndroid Build Coastguard Worker 'running APK. If --args is used, the extra arguments will be ' 2039*8975f5c5SAndroid Build Coastguard Worker 'passed on to simpleperf; otherwise, the following default ' 2040*8975f5c5SAndroid Build Coastguard Worker 'arguments are used: -g -f 1000 -o /data/local/tmp/perf.data') 2041*8975f5c5SAndroid Build Coastguard Worker needs_package_name = True 2042*8975f5c5SAndroid Build Coastguard Worker needs_output_directory = True 2043*8975f5c5SAndroid Build Coastguard Worker supports_multiple_devices = False 2044*8975f5c5SAndroid Build Coastguard Worker accepts_args = True 2045*8975f5c5SAndroid Build Coastguard Worker 2046*8975f5c5SAndroid Build Coastguard Worker def _RegisterExtraArgs(self, group): 2047*8975f5c5SAndroid Build Coastguard Worker group.add_argument( 2048*8975f5c5SAndroid Build Coastguard Worker '--profile-process', default='browser', 2049*8975f5c5SAndroid Build Coastguard Worker help=('Which process to profile. This may be a process name or pid ' 2050*8975f5c5SAndroid Build Coastguard Worker 'such as you would get from running `%s ps`; or ' 2051*8975f5c5SAndroid Build Coastguard Worker 'it can be one of (browser, renderer, gpu).' % sys.argv[0])) 2052*8975f5c5SAndroid Build Coastguard Worker group.add_argument( 2053*8975f5c5SAndroid Build Coastguard Worker '--profile-thread', default=None, 2054*8975f5c5SAndroid Build Coastguard Worker help=('(Optional) Profile only a single thread. This may be either a ' 2055*8975f5c5SAndroid Build Coastguard Worker 'thread ID such as you would get by running `adb shell ps -t` ' 2056*8975f5c5SAndroid Build Coastguard Worker '(pre-Oreo) or `adb shell ps -e -T` (Oreo and later); or it may ' 2057*8975f5c5SAndroid Build Coastguard Worker 'be one of (io, compositor, main, render), in which case ' 2058*8975f5c5SAndroid Build Coastguard Worker '--profile-process is also required. (Note that "render" thread ' 2059*8975f5c5SAndroid Build Coastguard Worker 'refers to a thread in the browser process that manages a ' 2060*8975f5c5SAndroid Build Coastguard Worker 'renderer; to profile the main thread of the renderer process, ' 2061*8975f5c5SAndroid Build Coastguard Worker 'use --profile-thread=main).')) 2062*8975f5c5SAndroid Build Coastguard Worker group.add_argument('--profile-output', default='profile.pb', 2063*8975f5c5SAndroid Build Coastguard Worker help='Output file for profiling data') 2064*8975f5c5SAndroid Build Coastguard Worker group.add_argument('--profile-events', default='cpu-cycles', 2065*8975f5c5SAndroid Build Coastguard Worker help=('A comma separated list of perf events to capture ' 2066*8975f5c5SAndroid Build Coastguard Worker '(e.g. \'cpu-cycles,branch-misses\'). Run ' 2067*8975f5c5SAndroid Build Coastguard Worker '`simpleperf list` on your device to see available ' 2068*8975f5c5SAndroid Build Coastguard Worker 'events.')) 2069*8975f5c5SAndroid Build Coastguard Worker 2070*8975f5c5SAndroid Build Coastguard Worker def Run(self): 2071*8975f5c5SAndroid Build Coastguard Worker extra_args = shlex.split(self.args.args or '') 2072*8975f5c5SAndroid Build Coastguard Worker _RunProfile(self.devices[0], self.args.package_name, 2073*8975f5c5SAndroid Build Coastguard Worker self.args.output_directory, self.args.profile_output, 2074*8975f5c5SAndroid Build Coastguard Worker self.args.profile_process, self.args.profile_thread, 2075*8975f5c5SAndroid Build Coastguard Worker self.args.profile_events, extra_args) 2076*8975f5c5SAndroid Build Coastguard Worker 2077*8975f5c5SAndroid Build Coastguard Worker 2078*8975f5c5SAndroid Build Coastguard Workerclass _RunCommand(_InstallCommand, _LaunchCommand, _LogcatCommand): 2079*8975f5c5SAndroid Build Coastguard Worker name = 'run' 2080*8975f5c5SAndroid Build Coastguard Worker description = 'Install, launch, and show logcat (when targeting one device).' 2081*8975f5c5SAndroid Build Coastguard Worker all_devices_by_default = False 2082*8975f5c5SAndroid Build Coastguard Worker supports_multiple_devices = True 2083*8975f5c5SAndroid Build Coastguard Worker 2084*8975f5c5SAndroid Build Coastguard Worker def _RegisterExtraArgs(self, group): 2085*8975f5c5SAndroid Build Coastguard Worker _InstallCommand._RegisterExtraArgs(self, group) 2086*8975f5c5SAndroid Build Coastguard Worker _LaunchCommand._RegisterExtraArgs(self, group) 2087*8975f5c5SAndroid Build Coastguard Worker _LogcatCommand._RegisterExtraArgs(self, group) 2088*8975f5c5SAndroid Build Coastguard Worker group.add_argument('--no-logcat', action='store_true', 2089*8975f5c5SAndroid Build Coastguard Worker help='Install and launch, but do not enter logcat.') 2090*8975f5c5SAndroid Build Coastguard Worker 2091*8975f5c5SAndroid Build Coastguard Worker def Run(self): 2092*8975f5c5SAndroid Build Coastguard Worker if self.is_test_apk: 2093*8975f5c5SAndroid Build Coastguard Worker raise Exception('Use the bin/run_* scripts to run test apks.') 2094*8975f5c5SAndroid Build Coastguard Worker logging.warning('Installing...') 2095*8975f5c5SAndroid Build Coastguard Worker _InstallCommand.Run(self) 2096*8975f5c5SAndroid Build Coastguard Worker logging.warning('Sending launch intent...') 2097*8975f5c5SAndroid Build Coastguard Worker _LaunchCommand.Run(self) 2098*8975f5c5SAndroid Build Coastguard Worker if len(self.devices) == 1 and not self.args.no_logcat: 2099*8975f5c5SAndroid Build Coastguard Worker logging.warning('Entering logcat...') 2100*8975f5c5SAndroid Build Coastguard Worker _LogcatCommand.Run(self) 2101*8975f5c5SAndroid Build Coastguard Worker 2102*8975f5c5SAndroid Build Coastguard Worker 2103*8975f5c5SAndroid Build Coastguard Workerclass _BuildBundleApks(_Command): 2104*8975f5c5SAndroid Build Coastguard Worker name = 'build-bundle-apks' 2105*8975f5c5SAndroid Build Coastguard Worker description = ('Build the .apks archive from an Android app bundle, and ' 2106*8975f5c5SAndroid Build Coastguard Worker 'optionally copy it to a specific destination.') 2107*8975f5c5SAndroid Build Coastguard Worker need_device_args = False 2108*8975f5c5SAndroid Build Coastguard Worker 2109*8975f5c5SAndroid Build Coastguard Worker def _RegisterExtraArgs(self, group): 2110*8975f5c5SAndroid Build Coastguard Worker group.add_argument( 2111*8975f5c5SAndroid Build Coastguard Worker '--output-apks', required=True, help='Destination path for .apks file.') 2112*8975f5c5SAndroid Build Coastguard Worker group.add_argument( 2113*8975f5c5SAndroid Build Coastguard Worker '--minimal', 2114*8975f5c5SAndroid Build Coastguard Worker action='store_true', 2115*8975f5c5SAndroid Build Coastguard Worker help='Build .apks archive that targets the bundle\'s minSdkVersion and ' 2116*8975f5c5SAndroid Build Coastguard Worker 'contains only english splits. It still contains optional splits.') 2117*8975f5c5SAndroid Build Coastguard Worker group.add_argument( 2118*8975f5c5SAndroid Build Coastguard Worker '--sdk-version', help='The sdkVersion to build the .apks for.') 2119*8975f5c5SAndroid Build Coastguard Worker group.add_argument( 2120*8975f5c5SAndroid Build Coastguard Worker '--build-mode', 2121*8975f5c5SAndroid Build Coastguard Worker choices=app_bundle_utils.BUILD_APKS_MODES, 2122*8975f5c5SAndroid Build Coastguard Worker help='Specify which type of APKs archive to build. "default" ' 2123*8975f5c5SAndroid Build Coastguard Worker 'generates regular splits, "universal" generates an archive with a ' 2124*8975f5c5SAndroid Build Coastguard Worker 'single universal APK, "system" generates an archive with a system ' 2125*8975f5c5SAndroid Build Coastguard Worker 'image APK, while "system_compressed" generates a compressed system ' 2126*8975f5c5SAndroid Build Coastguard Worker 'APK, with an additional stub APK for the system image.') 2127*8975f5c5SAndroid Build Coastguard Worker group.add_argument( 2128*8975f5c5SAndroid Build Coastguard Worker '--optimize-for', 2129*8975f5c5SAndroid Build Coastguard Worker choices=app_bundle_utils.OPTIMIZE_FOR_OPTIONS, 2130*8975f5c5SAndroid Build Coastguard Worker help='Override split configuration.') 2131*8975f5c5SAndroid Build Coastguard Worker 2132*8975f5c5SAndroid Build Coastguard Worker def Run(self): 2133*8975f5c5SAndroid Build Coastguard Worker _GenerateBundleApks( 2134*8975f5c5SAndroid Build Coastguard Worker self.bundle_generation_info, 2135*8975f5c5SAndroid Build Coastguard Worker output_path=self.args.output_apks, 2136*8975f5c5SAndroid Build Coastguard Worker minimal=self.args.minimal, 2137*8975f5c5SAndroid Build Coastguard Worker minimal_sdk_version=self.args.sdk_version, 2138*8975f5c5SAndroid Build Coastguard Worker mode=self.args.build_mode, 2139*8975f5c5SAndroid Build Coastguard Worker optimize_for=self.args.optimize_for) 2140*8975f5c5SAndroid Build Coastguard Worker 2141*8975f5c5SAndroid Build Coastguard Worker 2142*8975f5c5SAndroid Build Coastguard Workerclass _ManifestCommand(_Command): 2143*8975f5c5SAndroid Build Coastguard Worker name = 'dump-manifest' 2144*8975f5c5SAndroid Build Coastguard Worker description = 'Dump the android manifest as XML, to stdout.' 2145*8975f5c5SAndroid Build Coastguard Worker need_device_args = False 2146*8975f5c5SAndroid Build Coastguard Worker needs_apk_helper = True 2147*8975f5c5SAndroid Build Coastguard Worker 2148*8975f5c5SAndroid Build Coastguard Worker def Run(self): 2149*8975f5c5SAndroid Build Coastguard Worker if self.is_bundle: 2150*8975f5c5SAndroid Build Coastguard Worker sys.stdout.write( 2151*8975f5c5SAndroid Build Coastguard Worker bundletool.RunBundleTool([ 2152*8975f5c5SAndroid Build Coastguard Worker 'dump', 'manifest', '--bundle', 2153*8975f5c5SAndroid Build Coastguard Worker self.bundle_generation_info.bundle_path 2154*8975f5c5SAndroid Build Coastguard Worker ])) 2155*8975f5c5SAndroid Build Coastguard Worker else: 2156*8975f5c5SAndroid Build Coastguard Worker apkanalyzer = os.path.join(_DIR_SOURCE_ROOT, 'third_party', 'android_sdk', 2157*8975f5c5SAndroid Build Coastguard Worker 'public', 'cmdline-tools', 'latest', 'bin', 2158*8975f5c5SAndroid Build Coastguard Worker 'apkanalyzer') 2159*8975f5c5SAndroid Build Coastguard Worker cmd = [apkanalyzer, 'manifest', 'print', self.apk_helper.path] 2160*8975f5c5SAndroid Build Coastguard Worker logging.info('Running: %s', shlex.join(cmd)) 2161*8975f5c5SAndroid Build Coastguard Worker subprocess.check_call(cmd) 2162*8975f5c5SAndroid Build Coastguard Worker 2163*8975f5c5SAndroid Build Coastguard Worker 2164*8975f5c5SAndroid Build Coastguard Workerclass _StackCommand(_Command): 2165*8975f5c5SAndroid Build Coastguard Worker name = 'stack' 2166*8975f5c5SAndroid Build Coastguard Worker description = 'Decodes an Android stack.' 2167*8975f5c5SAndroid Build Coastguard Worker need_device_args = False 2168*8975f5c5SAndroid Build Coastguard Worker 2169*8975f5c5SAndroid Build Coastguard Worker def _RegisterExtraArgs(self, group): 2170*8975f5c5SAndroid Build Coastguard Worker group.add_argument( 2171*8975f5c5SAndroid Build Coastguard Worker 'file', 2172*8975f5c5SAndroid Build Coastguard Worker nargs='?', 2173*8975f5c5SAndroid Build Coastguard Worker help='File to decode. If not specified, stdin is processed.') 2174*8975f5c5SAndroid Build Coastguard Worker 2175*8975f5c5SAndroid Build Coastguard Worker def Run(self): 2176*8975f5c5SAndroid Build Coastguard Worker apk_path = self.args.apk_path or self.incremental_apk_path 2177*8975f5c5SAndroid Build Coastguard Worker context = _StackScriptContext(self.args.output_directory, apk_path, 2178*8975f5c5SAndroid Build Coastguard Worker self.bundle_generation_info) 2179*8975f5c5SAndroid Build Coastguard Worker try: 2180*8975f5c5SAndroid Build Coastguard Worker proc = context.Popen(input_file=self.args.file) 2181*8975f5c5SAndroid Build Coastguard Worker if proc.wait(): 2182*8975f5c5SAndroid Build Coastguard Worker raise Exception('stack script returned {}'.format(proc.returncode)) 2183*8975f5c5SAndroid Build Coastguard Worker finally: 2184*8975f5c5SAndroid Build Coastguard Worker context.Close() 2185*8975f5c5SAndroid Build Coastguard Worker 2186*8975f5c5SAndroid Build Coastguard Worker 2187*8975f5c5SAndroid Build Coastguard Worker# Shared commands for regular APKs and app bundles. 2188*8975f5c5SAndroid Build Coastguard Worker_COMMANDS = [ 2189*8975f5c5SAndroid Build Coastguard Worker _DevicesCommand, 2190*8975f5c5SAndroid Build Coastguard Worker _PackageInfoCommand, 2191*8975f5c5SAndroid Build Coastguard Worker _InstallCommand, 2192*8975f5c5SAndroid Build Coastguard Worker _UninstallCommand, 2193*8975f5c5SAndroid Build Coastguard Worker _SetWebViewProviderCommand, 2194*8975f5c5SAndroid Build Coastguard Worker _LaunchCommand, 2195*8975f5c5SAndroid Build Coastguard Worker _StopCommand, 2196*8975f5c5SAndroid Build Coastguard Worker _ClearDataCommand, 2197*8975f5c5SAndroid Build Coastguard Worker _ArgvCommand, 2198*8975f5c5SAndroid Build Coastguard Worker _GdbCommand, 2199*8975f5c5SAndroid Build Coastguard Worker _LldbCommand, 2200*8975f5c5SAndroid Build Coastguard Worker _LogcatCommand, 2201*8975f5c5SAndroid Build Coastguard Worker _PsCommand, 2202*8975f5c5SAndroid Build Coastguard Worker _DiskUsageCommand, 2203*8975f5c5SAndroid Build Coastguard Worker _MemUsageCommand, 2204*8975f5c5SAndroid Build Coastguard Worker _ShellCommand, 2205*8975f5c5SAndroid Build Coastguard Worker _CompileDexCommand, 2206*8975f5c5SAndroid Build Coastguard Worker _PrintCertsCommand, 2207*8975f5c5SAndroid Build Coastguard Worker _ProfileCommand, 2208*8975f5c5SAndroid Build Coastguard Worker _RunCommand, 2209*8975f5c5SAndroid Build Coastguard Worker _StackCommand, 2210*8975f5c5SAndroid Build Coastguard Worker _ManifestCommand, 2211*8975f5c5SAndroid Build Coastguard Worker] 2212*8975f5c5SAndroid Build Coastguard Worker 2213*8975f5c5SAndroid Build Coastguard Worker# Commands specific to app bundles. 2214*8975f5c5SAndroid Build Coastguard Worker_BUNDLE_COMMANDS = [ 2215*8975f5c5SAndroid Build Coastguard Worker _BuildBundleApks, 2216*8975f5c5SAndroid Build Coastguard Worker] 2217*8975f5c5SAndroid Build Coastguard Worker 2218*8975f5c5SAndroid Build Coastguard Worker 2219*8975f5c5SAndroid Build Coastguard Workerdef _ParseArgs(parser, from_wrapper_script, is_bundle, is_test_apk): 2220*8975f5c5SAndroid Build Coastguard Worker subparsers = parser.add_subparsers() 2221*8975f5c5SAndroid Build Coastguard Worker command_list = _COMMANDS + (_BUNDLE_COMMANDS if is_bundle else []) 2222*8975f5c5SAndroid Build Coastguard Worker commands = [ 2223*8975f5c5SAndroid Build Coastguard Worker clazz(from_wrapper_script, is_bundle, is_test_apk) 2224*8975f5c5SAndroid Build Coastguard Worker for clazz in command_list 2225*8975f5c5SAndroid Build Coastguard Worker ] 2226*8975f5c5SAndroid Build Coastguard Worker 2227*8975f5c5SAndroid Build Coastguard Worker for command in commands: 2228*8975f5c5SAndroid Build Coastguard Worker if from_wrapper_script or not command.needs_output_directory: 2229*8975f5c5SAndroid Build Coastguard Worker command.RegisterArgs(subparsers) 2230*8975f5c5SAndroid Build Coastguard Worker 2231*8975f5c5SAndroid Build Coastguard Worker # Show extended help when no command is passed. 2232*8975f5c5SAndroid Build Coastguard Worker argv = sys.argv[1:] 2233*8975f5c5SAndroid Build Coastguard Worker if not argv: 2234*8975f5c5SAndroid Build Coastguard Worker argv = ['--help'] 2235*8975f5c5SAndroid Build Coastguard Worker 2236*8975f5c5SAndroid Build Coastguard Worker return parser.parse_args(argv) 2237*8975f5c5SAndroid Build Coastguard Worker 2238*8975f5c5SAndroid Build Coastguard Worker 2239*8975f5c5SAndroid Build Coastguard Workerdef _RunInternal(parser, 2240*8975f5c5SAndroid Build Coastguard Worker output_directory=None, 2241*8975f5c5SAndroid Build Coastguard Worker additional_apk_paths=None, 2242*8975f5c5SAndroid Build Coastguard Worker bundle_generation_info=None, 2243*8975f5c5SAndroid Build Coastguard Worker is_test_apk=False): 2244*8975f5c5SAndroid Build Coastguard Worker colorama.init() 2245*8975f5c5SAndroid Build Coastguard Worker parser.set_defaults( 2246*8975f5c5SAndroid Build Coastguard Worker additional_apk_paths=additional_apk_paths, 2247*8975f5c5SAndroid Build Coastguard Worker output_directory=output_directory) 2248*8975f5c5SAndroid Build Coastguard Worker from_wrapper_script = bool(output_directory) 2249*8975f5c5SAndroid Build Coastguard Worker args = _ParseArgs(parser, 2250*8975f5c5SAndroid Build Coastguard Worker from_wrapper_script, 2251*8975f5c5SAndroid Build Coastguard Worker is_bundle=bool(bundle_generation_info), 2252*8975f5c5SAndroid Build Coastguard Worker is_test_apk=is_test_apk) 2253*8975f5c5SAndroid Build Coastguard Worker run_tests_helper.SetLogLevel(args.verbose_count) 2254*8975f5c5SAndroid Build Coastguard Worker if bundle_generation_info: 2255*8975f5c5SAndroid Build Coastguard Worker args.command.RegisterBundleGenerationInfo(bundle_generation_info) 2256*8975f5c5SAndroid Build Coastguard Worker if args.additional_apk_paths: 2257*8975f5c5SAndroid Build Coastguard Worker for i, path in enumerate(args.additional_apk_paths): 2258*8975f5c5SAndroid Build Coastguard Worker if path and not os.path.exists(path): 2259*8975f5c5SAndroid Build Coastguard Worker inc_path = path.replace('.apk', '_incremental.apk') 2260*8975f5c5SAndroid Build Coastguard Worker if os.path.exists(inc_path): 2261*8975f5c5SAndroid Build Coastguard Worker args.additional_apk_paths[i] = inc_path 2262*8975f5c5SAndroid Build Coastguard Worker path = inc_path 2263*8975f5c5SAndroid Build Coastguard Worker if not path or not os.path.exists(path): 2264*8975f5c5SAndroid Build Coastguard Worker raise Exception('Invalid additional APK path "{}"'.format(path)) 2265*8975f5c5SAndroid Build Coastguard Worker args.command.ProcessArgs(args) 2266*8975f5c5SAndroid Build Coastguard Worker args.command.Run() 2267*8975f5c5SAndroid Build Coastguard Worker # Incremental install depends on the cache being cleared when uninstalling. 2268*8975f5c5SAndroid Build Coastguard Worker if args.command.name != 'uninstall': 2269*8975f5c5SAndroid Build Coastguard Worker _SaveDeviceCaches(args.command.devices, output_directory) 2270*8975f5c5SAndroid Build Coastguard Worker 2271*8975f5c5SAndroid Build Coastguard Worker 2272*8975f5c5SAndroid Build Coastguard Workerdef Run(output_directory, apk_path, additional_apk_paths, incremental_json, 2273*8975f5c5SAndroid Build Coastguard Worker command_line_flags_file, target_cpu, proguard_mapping_path): 2274*8975f5c5SAndroid Build Coastguard Worker """Entry point for generated wrapper scripts.""" 2275*8975f5c5SAndroid Build Coastguard Worker constants.SetOutputDirectory(output_directory) 2276*8975f5c5SAndroid Build Coastguard Worker devil_chromium.Initialize(output_directory=output_directory) 2277*8975f5c5SAndroid Build Coastguard Worker parser = argparse.ArgumentParser() 2278*8975f5c5SAndroid Build Coastguard Worker exists_or_none = lambda p: p if p and os.path.exists(p) else None 2279*8975f5c5SAndroid Build Coastguard Worker 2280*8975f5c5SAndroid Build Coastguard Worker parser.set_defaults( 2281*8975f5c5SAndroid Build Coastguard Worker command_line_flags_file=command_line_flags_file, 2282*8975f5c5SAndroid Build Coastguard Worker target_cpu=target_cpu, 2283*8975f5c5SAndroid Build Coastguard Worker apk_path=exists_or_none(apk_path), 2284*8975f5c5SAndroid Build Coastguard Worker incremental_json=exists_or_none(incremental_json), 2285*8975f5c5SAndroid Build Coastguard Worker proguard_mapping_path=proguard_mapping_path) 2286*8975f5c5SAndroid Build Coastguard Worker _RunInternal( 2287*8975f5c5SAndroid Build Coastguard Worker parser, 2288*8975f5c5SAndroid Build Coastguard Worker output_directory=output_directory, 2289*8975f5c5SAndroid Build Coastguard Worker additional_apk_paths=additional_apk_paths) 2290*8975f5c5SAndroid Build Coastguard Worker 2291*8975f5c5SAndroid Build Coastguard Worker 2292*8975f5c5SAndroid Build Coastguard Workerdef RunForBundle(output_directory, bundle_path, bundle_apks_path, 2293*8975f5c5SAndroid Build Coastguard Worker additional_apk_paths, aapt2_path, keystore_path, 2294*8975f5c5SAndroid Build Coastguard Worker keystore_password, keystore_alias, package_name, 2295*8975f5c5SAndroid Build Coastguard Worker command_line_flags_file, proguard_mapping_path, target_cpu, 2296*8975f5c5SAndroid Build Coastguard Worker system_image_locales, default_modules, is_official_build): 2297*8975f5c5SAndroid Build Coastguard Worker """Entry point for generated app bundle wrapper scripts. 2298*8975f5c5SAndroid Build Coastguard Worker 2299*8975f5c5SAndroid Build Coastguard Worker Args: 2300*8975f5c5SAndroid Build Coastguard Worker output_dir: Chromium output directory path. 2301*8975f5c5SAndroid Build Coastguard Worker bundle_path: Input bundle path. 2302*8975f5c5SAndroid Build Coastguard Worker bundle_apks_path: Output bundle .apks archive path. 2303*8975f5c5SAndroid Build Coastguard Worker additional_apk_paths: Additional APKs to install prior to bundle install. 2304*8975f5c5SAndroid Build Coastguard Worker aapt2_path: Aapt2 tool path. 2305*8975f5c5SAndroid Build Coastguard Worker keystore_path: Keystore file path. 2306*8975f5c5SAndroid Build Coastguard Worker keystore_password: Keystore password. 2307*8975f5c5SAndroid Build Coastguard Worker keystore_alias: Signing key name alias in keystore file. 2308*8975f5c5SAndroid Build Coastguard Worker package_name: Application's package name. 2309*8975f5c5SAndroid Build Coastguard Worker command_line_flags_file: Optional. Name of an on-device file that will be 2310*8975f5c5SAndroid Build Coastguard Worker used to store command-line flags for this bundle. 2311*8975f5c5SAndroid Build Coastguard Worker proguard_mapping_path: Input path to the Proguard mapping file, used to 2312*8975f5c5SAndroid Build Coastguard Worker deobfuscate Java stack traces. 2313*8975f5c5SAndroid Build Coastguard Worker target_cpu: Chromium target CPU name, used by the 'gdb' command. 2314*8975f5c5SAndroid Build Coastguard Worker system_image_locales: List of Chromium locales that should be included in 2315*8975f5c5SAndroid Build Coastguard Worker system image APKs. 2316*8975f5c5SAndroid Build Coastguard Worker default_modules: List of modules that are installed in addition to those 2317*8975f5c5SAndroid Build Coastguard Worker given by the '-m' switch. 2318*8975f5c5SAndroid Build Coastguard Worker """ 2319*8975f5c5SAndroid Build Coastguard Worker constants.SetOutputDirectory(output_directory) 2320*8975f5c5SAndroid Build Coastguard Worker devil_chromium.Initialize(output_directory=output_directory) 2321*8975f5c5SAndroid Build Coastguard Worker bundle_generation_info = BundleGenerationInfo( 2322*8975f5c5SAndroid Build Coastguard Worker bundle_path=bundle_path, 2323*8975f5c5SAndroid Build Coastguard Worker bundle_apks_path=bundle_apks_path, 2324*8975f5c5SAndroid Build Coastguard Worker aapt2_path=aapt2_path, 2325*8975f5c5SAndroid Build Coastguard Worker keystore_path=keystore_path, 2326*8975f5c5SAndroid Build Coastguard Worker keystore_password=keystore_password, 2327*8975f5c5SAndroid Build Coastguard Worker keystore_alias=keystore_alias, 2328*8975f5c5SAndroid Build Coastguard Worker system_image_locales=system_image_locales) 2329*8975f5c5SAndroid Build Coastguard Worker _InstallCommand.default_modules = default_modules 2330*8975f5c5SAndroid Build Coastguard Worker 2331*8975f5c5SAndroid Build Coastguard Worker parser = argparse.ArgumentParser() 2332*8975f5c5SAndroid Build Coastguard Worker parser.set_defaults(package_name=package_name, 2333*8975f5c5SAndroid Build Coastguard Worker command_line_flags_file=command_line_flags_file, 2334*8975f5c5SAndroid Build Coastguard Worker proguard_mapping_path=proguard_mapping_path, 2335*8975f5c5SAndroid Build Coastguard Worker target_cpu=target_cpu, 2336*8975f5c5SAndroid Build Coastguard Worker is_official_build=is_official_build) 2337*8975f5c5SAndroid Build Coastguard Worker _RunInternal(parser, 2338*8975f5c5SAndroid Build Coastguard Worker output_directory=output_directory, 2339*8975f5c5SAndroid Build Coastguard Worker additional_apk_paths=additional_apk_paths, 2340*8975f5c5SAndroid Build Coastguard Worker bundle_generation_info=bundle_generation_info) 2341*8975f5c5SAndroid Build Coastguard Worker 2342*8975f5c5SAndroid Build Coastguard Worker 2343*8975f5c5SAndroid Build Coastguard Workerdef RunForTestApk(*, output_directory, package_name, test_apk_path, 2344*8975f5c5SAndroid Build Coastguard Worker test_apk_json, proguard_mapping_path, additional_apk_paths): 2345*8975f5c5SAndroid Build Coastguard Worker """Entry point for generated test apk wrapper scripts. 2346*8975f5c5SAndroid Build Coastguard Worker 2347*8975f5c5SAndroid Build Coastguard Worker This is intended to make commands like logcat (with proguard deobfuscation) 2348*8975f5c5SAndroid Build Coastguard Worker available. The run_* scripts should be used to actually run tests. 2349*8975f5c5SAndroid Build Coastguard Worker 2350*8975f5c5SAndroid Build Coastguard Worker Args: 2351*8975f5c5SAndroid Build Coastguard Worker output_dir: Chromium output directory path. 2352*8975f5c5SAndroid Build Coastguard Worker package_name: The package name for the test apk. 2353*8975f5c5SAndroid Build Coastguard Worker test_apk_path: The test apk to install. 2354*8975f5c5SAndroid Build Coastguard Worker test_apk_json: The incremental json dict for the test apk. 2355*8975f5c5SAndroid Build Coastguard Worker proguard_mapping_path: Input path to the Proguard mapping file, used to 2356*8975f5c5SAndroid Build Coastguard Worker deobfuscate Java stack traces. 2357*8975f5c5SAndroid Build Coastguard Worker additional_apk_paths: Additional APKs to install. 2358*8975f5c5SAndroid Build Coastguard Worker """ 2359*8975f5c5SAndroid Build Coastguard Worker constants.SetOutputDirectory(output_directory) 2360*8975f5c5SAndroid Build Coastguard Worker devil_chromium.Initialize(output_directory=output_directory) 2361*8975f5c5SAndroid Build Coastguard Worker 2362*8975f5c5SAndroid Build Coastguard Worker parser = argparse.ArgumentParser() 2363*8975f5c5SAndroid Build Coastguard Worker exists_or_none = lambda p: p if p and os.path.exists(p) else None 2364*8975f5c5SAndroid Build Coastguard Worker 2365*8975f5c5SAndroid Build Coastguard Worker parser.set_defaults(apk_path=exists_or_none(test_apk_path), 2366*8975f5c5SAndroid Build Coastguard Worker incremental_json=exists_or_none(test_apk_json), 2367*8975f5c5SAndroid Build Coastguard Worker package_name=package_name, 2368*8975f5c5SAndroid Build Coastguard Worker proguard_mapping_path=proguard_mapping_path) 2369*8975f5c5SAndroid Build Coastguard Worker 2370*8975f5c5SAndroid Build Coastguard Worker _RunInternal(parser, 2371*8975f5c5SAndroid Build Coastguard Worker output_directory=output_directory, 2372*8975f5c5SAndroid Build Coastguard Worker additional_apk_paths=additional_apk_paths, 2373*8975f5c5SAndroid Build Coastguard Worker is_test_apk=True) 2374*8975f5c5SAndroid Build Coastguard Worker 2375*8975f5c5SAndroid Build Coastguard Worker 2376*8975f5c5SAndroid Build Coastguard Workerdef main(): 2377*8975f5c5SAndroid Build Coastguard Worker devil_chromium.Initialize() 2378*8975f5c5SAndroid Build Coastguard Worker _RunInternal(argparse.ArgumentParser()) 2379*8975f5c5SAndroid Build Coastguard Worker 2380*8975f5c5SAndroid Build Coastguard Worker 2381*8975f5c5SAndroid Build Coastguard Workerif __name__ == '__main__': 2382*8975f5c5SAndroid Build Coastguard Worker main() 2383