def _initializeApkAttributes(self, args, error_func): if args.apk_under_test: apk_under_test_path = args.apk_under_test if not args.apk_under_test.endswith('.apk'): apk_under_test_path = os.path.join( constants.GetOutDirectory(), constants.SDK_BUILD_APKS_DIR, '%s.apk' % args.apk_under_test) if not os.path.exists(apk_under_test_path): error_func('Unable to find APK under test: %s' % apk_under_test_path) self._apk_under_test = apk_helper.ToHelper(apk_under_test_path) if args.test_apk.endswith('.apk'): self._suite = os.path.splitext(os.path.basename(args.test_apk))[0] self._test_apk = apk_helper.ToHelper(args.test_apk) else: self._suite = args.test_apk self._test_apk = apk_helper.ToHelper(os.path.join( constants.GetOutDirectory(), constants.SDK_BUILD_APKS_DIR, '%s.apk' % args.test_apk)) self._apk_under_test_incremental_install_script = ( args.apk_under_test_incremental_install_script) self._test_apk_incremental_install_script = ( args.test_apk_incremental_install_script) if self._test_apk_incremental_install_script: assert self._suite.endswith('_incremental') self._suite = self._suite[:-len('_incremental')] self._test_jar = os.path.join( constants.GetOutDirectory(), constants.SDK_BUILD_TEST_JAVALIB_DIR, '%s.jar' % self._suite) self._test_support_apk = apk_helper.ToHelper(os.path.join( constants.GetOutDirectory(), constants.SDK_BUILD_TEST_JAVALIB_DIR, '%sSupport.apk' % self._suite)) if not os.path.exists(self._test_apk.path): error_func('Unable to find test APK: %s' % self._test_apk.path) if not os.path.exists(self._test_jar): error_func('Unable to find test JAR: %s' % self._test_jar) self._test_package = self._test_apk.GetPackageName() self._test_runner = self._test_apk.GetInstrumentationName() self._package_info = None if self._apk_under_test: package_under_test = self._apk_under_test.GetPackageName() for package_info in constants.PACKAGE_INFO.itervalues(): if package_under_test == package_info.package: self._package_info = package_info if not self._package_info: logging.warning('Unable to find package info for %s', self._test_package) for apk in args.additional_apks: if not os.path.exists(apk): error_func('Unable to find additional APK: %s' % apk) self._additional_apks = ( [apk_helper.ToHelper(x) for x in args.additional_apks])
def _CanPossiblyHandlePath(apk_path): if not apk_path: return False _, ext = os.path.splitext(apk_path) if ext.lower() == '.apk': return True return apk_helper.ToHelper(apk_path).is_bundle
def _CanPossiblyHandlePath(apk_path): if not apk_path: return False try: apk_helper.ToHelper(apk_path) return True except apk_helper.ApkHelperError: return False
def main(): parser = argparse.ArgumentParser() parser.add_argument( 'json_path', help='The path to the generated incremental apk .json.') parser.add_argument('-d', '--device', dest='device', help='Target device for apk to install on.') parser.add_argument('--uninstall', action='store_true', default=False, help='Remove the app and all side-loaded files.') parser.add_argument('--output-directory', help='Path to the root build directory.') parser.add_argument('--no-threading', action='store_false', default=True, dest='threading', help='Do not install and push concurrently') parser.add_argument( '--no-cache', action='store_false', default=True, dest='cache', help='Do not use cached information about what files are ' 'currently on the target device.') parser.add_argument('-v', '--verbose', dest='verbose_count', default=0, action='count', help='Verbose level (multiple times for more)') args = parser.parse_args() run_tests_helper.SetLogLevel(args.verbose_count) if args.output_directory: constants.SetOutputDirectory(args.output_directory) devil_chromium.Initialize(output_directory=constants.GetOutDirectory()) # Retries are annoying when commands fail for legitimate reasons. Might want # to enable them if this is ever used on bots though. device = device_utils.DeviceUtils.HealthyDevices( device_arg=args.device, default_retries=0, enable_device_files_cache=True)[0] if args.uninstall: with open(args.json_path) as f: install_dict = json.load(f) apk = apk_helper.ToHelper(install_dict['apk_path']) Uninstall(device, apk.GetPackageName(), enable_device_cache=args.cache) else: Install(device, args.json_path, enable_device_cache=args.cache, use_concurrency=args.threading)
def testGetSplitsApks(self): apk = apk_helper.ToHelper('abc.apks') with self.assertCalls( (mock.call.tempfile.mkdtemp(), '/tmp'), (mock.call.devil.android.sdk.bundletool.ExtractApks( '/tmp', 'abc.apks', ['arm64-v8a', 'armeabi-v7a'], [('en', 'US')], ['android.hardware.wifi', 'android.hardware.nfc'], 500, 28, None)), (mock.call.os.listdir('/tmp'), ['base-master.apk', 'foo-master.apk']), (mock.call.shutil.rmtree('/tmp')), ),\ apk.GetApkPaths(_MockDeviceUtils()) as apk_paths: self.assertEquals(apk_paths, ['/tmp/base-master.apk', '/tmp/foo-master.apk'])
def GetWebViewLibraryNameAndPath(self, package_name): """Get WebView library name and path on the device.""" apk_path = self._GetWebViewApkPath(package_name) logging.debug('WebView APK path:' + apk_path) # TODO(changwan): check if we need support for bundle. tmp_apk_path = os.path.join(self.tmp_dir, 'base.apk') self.device.adb.Pull(apk_path, tmp_apk_path) self.apk_helper = apk_helper.ToHelper(tmp_apk_path) metadata = self.apk_helper.GetAllMetadata() lib_name = None for key, value in metadata: if key == 'com.android.webview.WebViewLibrary': lib_name = value lib_path = os.path.join(apk_path, 'lib', self._GetFormattedArch(), lib_name) logging.debug("WebView's library path on the device should be:" + lib_path) return lib_name, lib_path
def __init__(self, browser_type, finder_options, android_platform, backend_settings, local_apk=None): super(PossibleAndroidBrowser, self).__init__(browser_type, 'android', backend_settings.supports_tab_control) assert browser_type in FindAllBrowserTypes(), ( 'Please add %s to android_browser_finder.FindAllBrowserTypes' % browser_type) self._platform = android_platform self._platform_backend = (android_platform._platform_backend) # pylint: disable=protected-access self._backend_settings = backend_settings self._local_apk = local_apk self._flag_changer = None self._modules_to_install = None if self._local_apk is None and finder_options.chrome_root is not None: self._local_apk = self._backend_settings.FindLocalApk( self._platform_backend.device, finder_options.chrome_root) # At this point the local_apk, if any, must exist. assert self._local_apk is None or os.path.exists(self._local_apk) if self._local_apk and apk_helper.ToHelper(self._local_apk).is_bundle: self._modules_to_install = set(finder_options.modules_to_install) self._embedder_apk = None if self._backend_settings.requires_embedder: if finder_options.webview_embedder_apk: self._embedder_apk = finder_options.webview_embedder_apk else: self._embedder_apk = self._backend_settings.FindEmbedderApk( self._local_apk, finder_options.chrome_root) elif finder_options.webview_embedder_apk: logging.warning( 'No embedder needed for %s, ignoring --webview-embedder-apk option', self._backend_settings.browser_type) # At this point the embedder_apk, if any, must exist. assert self._embedder_apk is None or os.path.exists(self._embedder_apk)
def testGetSplitsBundleScript(self): apk = apk_helper.ToHelper('abc_bundle') device = _MockDeviceUtils() with self.assertCalls( (mock.call.tempfile.mkstemp(suffix='.apks'), (0, '/tmp/abc.apks')), (mock.call.devil.utils.cmd_helper.GetCmdStatusOutputAndError([ 'abc_bundle', 'build-bundle-apks', '--output-apks', '/tmp/abc.apks' ]), (0, '', '')), (mock.call.tempfile.mkdtemp(), '/tmp2'), (mock.call.devil.android.sdk.bundletool.ExtractApks( '/tmp2', '/tmp/abc.apks', ['arm64-v8a', 'armeabi-v7a'], [('en', 'US')], ['android.hardware.wifi', 'android.hardware.nfc'], 500, 28, ['bar'])), (mock.call.os.listdir('/tmp2'), ['base-master.apk', 'bar-master.apk']), (mock.call.os.path.isfile('/tmp/abc.apks'), True), (mock.call.os.remove('/tmp/abc.apks')), (mock.call.os.path.isfile('/tmp2'), False), (mock.call.os.path.isdir('/tmp2'), True), (mock.call.shutil.rmtree('/tmp2')), ),\ apk.GetApkPaths(device, modules=['bar']) as apk_paths: self.assertEquals( apk_paths, ['/tmp2/base-master.apk', '/tmp2/bar-master.apk'])
def _initializeApkAttributes(self, args, error_func): if args.apk_under_test: apk_under_test_path = args.apk_under_test if (not args.apk_under_test.endswith('.apk') and not args.apk_under_test.endswith('.apks')): apk_under_test_path = os.path.join( constants.GetOutDirectory(), constants.SDK_BUILD_APKS_DIR, '%s.apk' % args.apk_under_test) # TODO(jbudorick): Move the realpath up to the argument parser once # APK-by-name is no longer supported. apk_under_test_path = os.path.realpath(apk_under_test_path) if not os.path.exists(apk_under_test_path): error_func('Unable to find APK under test: %s' % apk_under_test_path) self._apk_under_test = apk_helper.ToHelper(apk_under_test_path) test_apk_path = args.test_apk if not os.path.exists(test_apk_path): test_apk_path = os.path.join( constants.GetOutDirectory(), constants.SDK_BUILD_APKS_DIR, '%s.apk' % args.test_apk) # TODO(jbudorick): Move the realpath up to the argument parser once # APK-by-name is no longer supported. test_apk_path = os.path.realpath(test_apk_path) if not os.path.exists(test_apk_path): error_func('Unable to find test APK: %s' % test_apk_path) self._test_apk = apk_helper.ToHelper(test_apk_path) self._suite = os.path.splitext(os.path.basename(args.test_apk))[0] self._apk_under_test_incremental_install_json = ( args.apk_under_test_incremental_install_json) self._test_apk_incremental_install_json = ( args.test_apk_incremental_install_json) if self._test_apk_incremental_install_json: assert self._suite.endswith('_incremental') self._suite = self._suite[:-len('_incremental')] self._modules = args.modules self._fake_modules = args.fake_modules self._test_jar = args.test_jar self._test_support_apk = apk_helper.ToHelper(os.path.join( constants.GetOutDirectory(), constants.SDK_BUILD_TEST_JAVALIB_DIR, '%sSupport.apk' % self._suite)) if not self._test_jar: logging.warning('Test jar not specified. Test runner will not have ' 'Java annotation info available. May not handle test ' 'timeouts correctly.') elif not os.path.exists(self._test_jar): error_func('Unable to find test JAR: %s' % self._test_jar) self._test_package = self._test_apk.GetPackageName() all_instrumentations = self._test_apk.GetAllInstrumentations() all_junit3_runner_classes = [ x for x in all_instrumentations if ('0xffffffff' in x.get( 'chromium-junit3', ''))] all_junit4_runner_classes = [ x for x in all_instrumentations if ('0xffffffff' not in x.get( 'chromium-junit3', ''))] if len(all_junit3_runner_classes) > 1: logging.warning('This test apk has more than one JUnit3 instrumentation') if len(all_junit4_runner_classes) > 1: logging.warning('This test apk has more than one JUnit4 instrumentation') self._junit3_runner_class = ( all_junit3_runner_classes[0]['android:name'] if all_junit3_runner_classes else self.test_apk.GetInstrumentationName()) self._junit4_runner_class = ( all_junit4_runner_classes[0]['android:name'] if all_junit4_runner_classes else None) if self._junit4_runner_class: if self._test_apk_incremental_install_json: self._junit4_runner_supports_listing = next( (True for x in self._test_apk.GetAllMetadata() if 'real-instr' in x[0] and x[1] in _TEST_LIST_JUNIT4_RUNNERS), False) else: self._junit4_runner_supports_listing = ( self._junit4_runner_class in _TEST_LIST_JUNIT4_RUNNERS) self._package_info = None if self._apk_under_test: package_under_test = self._apk_under_test.GetPackageName() for package_info in constants.PACKAGE_INFO.itervalues(): if package_under_test == package_info.package: self._package_info = package_info break if not self._package_info: logging.warning(("Unable to find package info for %s. " + "(This may just mean that the test package is" + "currently being installed.)"), self._test_package) for apk in args.additional_apks: if not os.path.exists(apk): error_func('Unable to find additional APK: %s' % apk) self._additional_apks = ( [apk_helper.ToHelper(x) for x in args.additional_apks])
def Install(device, apk, split_globs=None, lib_dir=None, dex_files=None, enable_device_cache=True, use_concurrency=True): """Installs the given incremental apk and all required supporting files. Args: device: A DeviceUtils instance. apk: The path to the apk, or an ApkHelper instance. split_globs: Glob patterns for any required apk splits (optional). lib_dir: Directory containing the app's native libraries (optional). dex_files: List of .dex.jar files that comprise the app's Dalvik code. enable_device_cache: Whether to enable on-device caching of checksums. use_concurrency: Whether to speed things up using multiple threads. """ main_timer = time_profile.TimeProfile() install_timer = time_profile.TimeProfile() push_native_timer = time_profile.TimeProfile() push_dex_timer = time_profile.TimeProfile() apk = apk_helper.ToHelper(apk) apk_package = apk.GetPackageName() device_incremental_dir = _GetDeviceIncrementalDir(apk_package) # Install .apk(s) if any of them have changed. def do_install(): install_timer.Start() if split_globs: splits = [] for split_glob in split_globs: splits.extend((f for f in glob.glob(split_glob))) device.InstallSplitApk(apk, splits, reinstall=True, allow_cached_props=True, permissions=()) else: device.Install(apk, reinstall=True, permissions=()) install_timer.Stop(log=False) # Push .so and .dex files to the device (if they have changed). def do_push_files(): if lib_dir: push_native_timer.Start() device_lib_dir = posixpath.join(device_incremental_dir, 'lib') device.PushChangedFiles([(lib_dir, device_lib_dir)], delete_device_stale=True) push_native_timer.Stop(log=False) if dex_files: push_dex_timer.Start() # Put all .dex files to be pushed into a temporary directory so that we # can use delete_device_stale=True. with build_utils.TempDir() as temp_dir: device_dex_dir = posixpath.join(device_incremental_dir, 'dex') # Ensure no two files have the same name. transformed_names = _TransformDexPaths(dex_files) for src_path, dest_name in zip(dex_files, transformed_names): shutil.copyfile(src_path, os.path.join(temp_dir, dest_name)) device.PushChangedFiles([(temp_dir, device_dex_dir)], delete_device_stale=True) push_dex_timer.Stop(log=False) def check_selinux(): # Samsung started using SELinux before Marshmallow. There may be even more # cases where this is required... has_selinux = (device.build_version_sdk >= version_codes.MARSHMALLOW or device.GetProp('selinux.policy_version')) if has_selinux and apk.HasIsolatedProcesses(): raise Exception( 'Cannot use incremental installs on versions of Android ' 'where isoloated processes cannot access the filesystem ' '(this includes Android M+, and Samsung L+) without ' 'first disabling isoloated processes.\n' 'To do so, use GN arg:\n' ' disable_incremental_isolated_processes=true') cache_path = '%s/files-cache.json' % device_incremental_dir def restore_cache(): if not enable_device_cache: logging.info('Ignoring device cache') return # Delete the cached file so that any exceptions cause the next attempt # to re-compute md5s. cmd = 'P=%s;cat $P 2>/dev/null && rm $P' % cache_path lines = device.RunShellCommand(cmd, check_return=False, large_output=True) if lines: device.LoadCacheData(lines[0]) else: logging.info('Device cache not found: %s', cache_path) def save_cache(): cache_data = device.DumpCacheData() device.WriteFile(cache_path, cache_data) # Create 2 lock files: # * install.lock tells the app to pause on start-up (until we release it). # * firstrun.lock is used by the app to pause all secondary processes until # the primary process finishes loading the .dex / .so files. def create_lock_files(): # Creates or zeros out lock files. cmd = ('D="%s";' 'mkdir -p $D &&' 'echo -n >$D/install.lock 2>$D/firstrun.lock') device.RunShellCommand(cmd % device_incremental_dir, check_return=True) # The firstrun.lock is released by the app itself. def release_installer_lock(): device.RunShellCommand('echo > %s/install.lock' % device_incremental_dir, check_return=True) # Concurrency here speeds things up quite a bit, but DeviceUtils hasn't # been designed for multi-threading. Enabling only because this is a # developer-only tool. setup_timer = _Execute(use_concurrency, create_lock_files, restore_cache, check_selinux) _Execute(use_concurrency, do_install, do_push_files) finalize_timer = _Execute(use_concurrency, release_installer_lock, save_cache) logging.info( 'Took %s seconds (setup=%s, install=%s, libs=%s, dex=%s, finalize=%s)', main_timer.GetDelta(), setup_timer.GetDelta(), install_timer.GetDelta(), push_native_timer.GetDelta(), push_dex_timer.GetDelta(), finalize_timer.GetDelta())
def Install(device, install_json, apk=None, enable_device_cache=False, use_concurrency=True, permissions=()): """Installs the given incremental apk and all required supporting files. Args: device: A DeviceUtils instance (to install to). install_json: Path to .json file or already parsed .json object. apk: An existing ApkHelper instance for the apk (optional). enable_device_cache: Whether to enable on-device caching of checksums. use_concurrency: Whether to speed things up using multiple threads. permissions: A list of the permissions to grant, or None to grant all non-blacklisted permissions in the manifest. """ if isinstance(install_json, basestring): with open(install_json) as f: install_dict = json.load(f) else: install_dict = install_json if install_dict.get('dont_even_try'): raise Exception(install_dict['dont_even_try']) main_timer = time_profile.TimeProfile() install_timer = time_profile.TimeProfile() push_native_timer = time_profile.TimeProfile() push_dex_timer = time_profile.TimeProfile() def fix_path(p): return os.path.normpath(os.path.join(constants.GetOutDirectory(), p)) if not apk: apk = apk_helper.ToHelper(fix_path(install_dict['apk_path'])) split_globs = [fix_path(p) for p in install_dict['split_globs']] native_libs = [fix_path(p) for p in install_dict['native_libs']] dex_files = [fix_path(p) for p in install_dict['dex_files']] show_proguard_warning = install_dict.get('show_proguard_warning') apk_package = apk.GetPackageName() device_incremental_dir = _GetDeviceIncrementalDir(apk_package) # Install .apk(s) if any of them have changed. def do_install(): install_timer.Start() if split_globs: splits = [] for split_glob in split_globs: splits.extend((f for f in glob.glob(split_glob))) device.InstallSplitApk( apk, splits, allow_downgrade=True, reinstall=True, allow_cached_props=True, permissions=permissions) else: device.Install( apk, allow_downgrade=True, reinstall=True, permissions=permissions) install_timer.Stop(log=False) # Push .so and .dex files to the device (if they have changed). def do_push_files(): push_native_timer.Start() if native_libs: with build_utils.TempDir() as temp_dir: device_lib_dir = posixpath.join(device_incremental_dir, 'lib') for path in native_libs: # Note: Can't use symlinks as they don't work when # "adb push parent_dir" is used (like we do here). shutil.copy(path, os.path.join(temp_dir, os.path.basename(path))) device.PushChangedFiles([(temp_dir, device_lib_dir)], delete_device_stale=True) push_native_timer.Stop(log=False) push_dex_timer.Start() if dex_files: # Put all .dex files to be pushed into a temporary directory so that we # can use delete_device_stale=True. with build_utils.TempDir() as temp_dir: device_dex_dir = posixpath.join(device_incremental_dir, 'dex') # Ensure no two files have the same name. transformed_names = _TransformDexPaths(dex_files) for src_path, dest_name in zip(dex_files, transformed_names): # Binary targets with no extra classes create .dex.jar without a # classes.dex (which Android chokes on). if _HasClasses(src_path): shutil.copy(src_path, os.path.join(temp_dir, dest_name)) device.PushChangedFiles([(temp_dir, device_dex_dir)], delete_device_stale=True) push_dex_timer.Stop(log=False) def check_selinux(): # Marshmallow has no filesystem access whatsoever. It might be possible to # get things working on Lollipop, but attempts so far have failed. # http://crbug.com/558818 has_selinux = device.build_version_sdk >= version_codes.LOLLIPOP if has_selinux and apk.HasIsolatedProcesses(): raise Exception('Cannot use incremental installs on Android L+ without ' 'first disabling isolated processes.\n' 'To do so, use GN arg:\n' ' disable_incremental_isolated_processes=true') target_sdk_version = int(apk.GetTargetSdkVersion()) # Beta Q builds apply whitelist to targetSdk=28 as well. if target_sdk_version >= 28 and device.build_version_sdk >= 29: apis_allowed = ''.join( device.RunShellCommand( ['settings', 'get', 'global', 'hidden_api_policy'], check_return=True)) if apis_allowed.strip() not in '01': msg = """\ Cannot use incremental installs on Android Q+ without first enabling access to non-SDK interfaces (https://developer.android.com/preview/non-sdk-q). To enable access: adb -s {0} shell settings put global hidden_api_policy 0 To restore back to default: adb -s {0} shell settings delete global hidden_api_policy""" raise Exception(msg.format(device.serial)) cache_path = _DeviceCachePath(device) def restore_cache(): if not enable_device_cache: return if os.path.exists(cache_path): logging.info('Using device cache: %s', cache_path) with open(cache_path) as f: device.LoadCacheData(f.read()) # Delete the cached file so that any exceptions cause it to be cleared. os.unlink(cache_path) else: logging.info('No device cache present: %s', cache_path) def save_cache(): if not enable_device_cache: return with open(cache_path, 'w') as f: f.write(device.DumpCacheData()) logging.info('Wrote device cache: %s', cache_path) # Create 2 lock files: # * install.lock tells the app to pause on start-up (until we release it). # * firstrun.lock is used by the app to pause all secondary processes until # the primary process finishes loading the .dex / .so files. def create_lock_files(): # Creates or zeros out lock files. cmd = ('D="%s";' 'mkdir -p $D &&' 'echo -n >$D/install.lock 2>$D/firstrun.lock') device.RunShellCommand( cmd % device_incremental_dir, shell=True, check_return=True) # The firstrun.lock is released by the app itself. def release_installer_lock(): device.RunShellCommand('echo > %s/install.lock' % device_incremental_dir, check_return=True, shell=True) # Concurrency here speeds things up quite a bit, but DeviceUtils hasn't # been designed for multi-threading. Enabling only because this is a # developer-only tool. setup_timer = _Execute( use_concurrency, create_lock_files, restore_cache, check_selinux) _Execute(use_concurrency, do_install, do_push_files) finalize_timer = _Execute(use_concurrency, release_installer_lock, save_cache) logging.info( 'Install of %s took %s seconds ' '(setup=%s, install=%s, libs=%s, dex=%s, finalize=%s)', os.path.basename(apk.path), main_timer.GetDelta(), setup_timer.GetDelta(), install_timer.GetDelta(), push_native_timer.GetDelta(), push_dex_timer.GetDelta(), finalize_timer.GetDelta()) if show_proguard_warning: logging.warning('Target had proguard enabled, but incremental install uses ' 'non-proguarded .dex files. Performance characteristics ' 'may differ.')
def _initializeApkAttributes(self, args, error_func): if args.apk_under_test: apk_under_test_path = args.apk_under_test if not args.apk_under_test.endswith('.apk'): apk_under_test_path = os.path.join( constants.GetOutDirectory(), constants.SDK_BUILD_APKS_DIR, '%s.apk' % args.apk_under_test) # TODO(jbudorick): Move the realpath up to the argument parser once # APK-by-name is no longer supported. apk_under_test_path = os.path.realpath(apk_under_test_path) if not os.path.exists(apk_under_test_path): error_func('Unable to find APK under test: %s' % apk_under_test_path) self._apk_under_test = apk_helper.ToHelper(apk_under_test_path) if args.test_apk.endswith('.apk'): self._suite = os.path.splitext(os.path.basename(args.test_apk))[0] test_apk_path = args.test_apk self._test_apk = apk_helper.ToHelper(args.test_apk) else: self._suite = args.test_apk test_apk_path = os.path.join(constants.GetOutDirectory(), constants.SDK_BUILD_APKS_DIR, '%s.apk' % args.test_apk) # TODO(jbudorick): Move the realpath up to the argument parser once # APK-by-name is no longer supported. test_apk_path = os.path.realpath(test_apk_path) if not os.path.exists(test_apk_path): error_func('Unable to find test APK: %s' % test_apk_path) self._test_apk = apk_helper.ToHelper(test_apk_path) self._apk_under_test_incremental_install_script = ( args.apk_under_test_incremental_install_script) self._test_apk_incremental_install_script = ( args.test_apk_incremental_install_script) if self._test_apk_incremental_install_script: assert self._suite.endswith('_incremental') self._suite = self._suite[:-len('_incremental')] self._test_jar = args.test_jar self._test_support_apk = apk_helper.ToHelper( os.path.join(constants.GetOutDirectory(), constants.SDK_BUILD_TEST_JAVALIB_DIR, '%sSupport.apk' % self._suite)) if not os.path.exists(self._test_apk.path): error_func('Unable to find test APK: %s' % self._test_apk.path) if not self._test_jar: logging.warning( 'Test jar not specified. Test runner will not have ' 'Java annotation info available. May not handle test ' 'timeouts correctly.') elif not os.path.exists(self._test_jar): error_func('Unable to find test JAR: %s' % self._test_jar) self._test_package = self._test_apk.GetPackageName() all_instrumentations = self._test_apk.GetAllInstrumentations() junit3_runners = [ x for x in all_instrumentations if ('true' not in x.get('chromium-junit4', '')) ] junit4_runners = [ x for x in all_instrumentations if ('true' in x.get('chromium-junit4', '')) ] if len(junit3_runners) > 1: logging.warning( 'This test apk has more than one JUnit3 instrumentation') if len(junit4_runners) > 1: logging.warning( 'This test apk has more than one JUnit4 instrumentation') self._test_runner = (junit3_runners[0]['android:name'] if junit3_runners else self.test_apk.GetInstrumentationName()) self._test_runner_junit4 = (junit4_runners[0]['android:name'] if junit4_runners else None) self._package_info = None if self._apk_under_test: package_under_test = self._apk_under_test.GetPackageName() for package_info in constants.PACKAGE_INFO.itervalues(): if package_under_test == package_info.package: self._package_info = package_info break if not self._package_info: logging.warning('Unable to find package info for %s', self._test_package) for apk in args.additional_apks: if not os.path.exists(apk): error_func('Unable to find additional APK: %s' % apk) self._additional_apks = ([ apk_helper.ToHelper(x) for x in args.additional_apks ])
def ProcessArgs(self, args): devices = device_utils.DeviceUtils.HealthyDevices( device_arg=args.devices, enable_device_files_cache=bool(args.output_directory), default_retries=0) self.args = args self.devices = devices # TODO(agrieve): Device cache should not depend on output directory. # Maybe put int /tmp? _LoadDeviceCaches(devices, args.output_directory) # Ensure these keys always exist. They are set by wrapper scripts, but not # always added when not using wrapper scripts. args.__dict__.setdefault('apk_path', None) args.__dict__.setdefault('incremental_json', None) try: if len(devices) > 1: if not self.supports_multiple_devices: self._parser.error(device_errors.MultipleDevicesError(devices)) if not args.all and not args.devices: self._parser.error(_GenerateMissingAllFlagMessage(devices)) if self.supports_incremental: if args.incremental and args.non_incremental: self._parser.error('Must use only one of --incremental and ' '--non-incremental') elif args.non_incremental: if not args.apk_path: self._parser.error('Apk has not been built.') args.incremental_json = None elif args.incremental: if not args.incremental_json: self._parser.error('Incremental apk has not been built.') args.apk_path = None if args.apk_path and args.incremental_json: self._parser.error('Both incremental and non-incremental apks exist. ' 'Select using --incremental or --non-incremental') if self.needs_apk_path or args.apk_path or args.incremental_json: if args.incremental_json: with open(args.incremental_json) as f: install_dict = json.load(f) apk_path = os.path.join(args.output_directory, install_dict['apk_path']) if os.path.exists(apk_path): self.install_dict = install_dict self.apk_helper = apk_helper.ToHelper( os.path.join(args.output_directory, self.install_dict['apk_path'])) if not self.apk_helper and args.apk_path: self.apk_helper = apk_helper.ToHelper(args.apk_path) if not self.apk_helper: self._parser.error( 'Neither incremental nor non-incremental apk is built.') if self.needs_package_name and not args.package_name: if self.apk_helper: args.package_name = self.apk_helper.GetPackageName() elif self._from_wrapper_script: self._parser.error( 'Neither incremental nor non-incremental apk is built.') else: self._parser.error('One of --package-name or --apk-path is required.') # Save cache now if command will not get a chance to afterwards. if self.calls_exec: _SaveDeviceCaches(devices, args.output_directory) except: _SaveDeviceCaches(devices, args.output_directory) raise
def main(): parser = argparse.ArgumentParser() parser.add_argument('apk_path', help='The path to the APK to install.') parser.add_argument('--split', action='append', dest='splits', help='A glob matching the apk splits. ' 'Can be specified multiple times.') parser.add_argument('--native_lib', dest='native_libs', help='Path to native library (repeatable)', action='append', default=[]) parser.add_argument('--dex-file', dest='dex_files', help='Path to dex files (repeatable)', action='append', default=[]) parser.add_argument('-d', '--device', dest='device', help='Target device for apk to install on.') parser.add_argument('--uninstall', action='store_true', default=False, help='Remove the app and all side-loaded files.') parser.add_argument('--output-directory', help='Path to the root build directory.') parser.add_argument('--no-threading', action='store_false', default=True, dest='threading', help='Do not install and push concurrently') parser.add_argument( '--no-cache', action='store_false', default=True, dest='cache', help='Do not use cached information about what files are ' 'currently on the target device.') parser.add_argument('--show-proguard-warning', action='store_true', default=False, help='Print a warning about proguard being disabled') parser.add_argument('--dont-even-try', help='Prints this message and exits.') parser.add_argument('-v', '--verbose', dest='verbose_count', default=0, action='count', help='Verbose level (multiple times for more)') args = parser.parse_args() run_tests_helper.SetLogLevel(args.verbose_count) constants.SetBuildType('Debug') if args.output_directory: constants.SetOutputDirectory(args.output_directory) devil_chromium.Initialize(output_directory=constants.GetOutDirectory()) if args.dont_even_try: logging.fatal(args.dont_even_try) return 1 # Retries are annoying when commands fail for legitimate reasons. Might want # to enable them if this is ever used on bots though. device = device_utils.DeviceUtils.HealthyDevices( device_arg=args.device, default_retries=0, enable_device_files_cache=True)[0] apk = apk_helper.ToHelper(args.apk_path) if args.uninstall: Uninstall(device, apk.GetPackageName(), enable_device_cache=args.cache) else: Install(device, apk, split_globs=args.splits, native_libs=args.native_libs, dex_files=args.dex_files, enable_device_cache=args.cache, use_concurrency=args.threading, show_proguard_warning=args.show_proguard_warning)
def Install(device, apk, split_globs=None, native_libs=None, dex_files=None, enable_device_cache=False, use_concurrency=True, show_proguard_warning=False, permissions=()): """Installs the given incremental apk and all required supporting files. Args: device: A DeviceUtils instance. apk: The path to the apk, or an ApkHelper instance. split_globs: Glob patterns for any required apk splits (optional). native_libs: List of app's native libraries (optional). dex_files: List of .dex.jar files that comprise the app's Dalvik code. enable_device_cache: Whether to enable on-device caching of checksums. use_concurrency: Whether to speed things up using multiple threads. show_proguard_warning: Whether to print a warning about Proguard not being enabled after installing. permissions: A list of the permissions to grant, or None to grant all non-blacklisted permissions in the manifest. """ main_timer = time_profile.TimeProfile() install_timer = time_profile.TimeProfile() push_native_timer = time_profile.TimeProfile() push_dex_timer = time_profile.TimeProfile() apk = apk_helper.ToHelper(apk) apk_package = apk.GetPackageName() device_incremental_dir = _GetDeviceIncrementalDir(apk_package) # Install .apk(s) if any of them have changed. def do_install(): install_timer.Start() if split_globs: splits = [] for split_glob in split_globs: splits.extend((f for f in glob.glob(split_glob))) device.InstallSplitApk(apk, splits, reinstall=True, allow_cached_props=True, permissions=permissions) else: device.Install(apk, reinstall=True, permissions=permissions) install_timer.Stop(log=False) # Push .so and .dex files to the device (if they have changed). def do_push_files(): if native_libs: push_native_timer.Start() with build_utils.TempDir() as temp_dir: device_lib_dir = posixpath.join(device_incremental_dir, 'lib') for path in native_libs: # Note: Can't use symlinks as they don't work when # "adb push parent_dir" is used (like we do here). shutil.copy(path, os.path.join(temp_dir, os.path.basename(path))) device.PushChangedFiles([(temp_dir, device_lib_dir)], delete_device_stale=True) push_native_timer.Stop(log=False) if dex_files: push_dex_timer.Start() # Put all .dex files to be pushed into a temporary directory so that we # can use delete_device_stale=True. with build_utils.TempDir() as temp_dir: device_dex_dir = posixpath.join(device_incremental_dir, 'dex') # Ensure no two files have the same name. transformed_names = _TransformDexPaths(dex_files) for src_path, dest_name in zip(dex_files, transformed_names): # Binary targets with no extra classes create .dex.jar without a # classes.dex (which Android chokes on). if _HasClasses(src_path): shutil.copy(src_path, os.path.join(temp_dir, dest_name)) device.PushChangedFiles([(temp_dir, device_dex_dir)], delete_device_stale=True) push_dex_timer.Stop(log=False) def check_selinux(): # Marshmallow has no filesystem access whatsoever. It might be possible to # get things working on Lollipop, but attempts so far have failed. # http://crbug.com/558818 has_selinux = device.build_version_sdk >= version_codes.LOLLIPOP if has_selinux and apk.HasIsolatedProcesses(): raise Exception( 'Cannot use incremental installs on Android L+ without ' 'first disabling isoloated processes.\n' 'To do so, use GN arg:\n' ' disable_incremental_isolated_processes=true') cache_path = _DeviceCachePath(device) def restore_cache(): if not enable_device_cache: logging.info('Ignoring device cache') return if os.path.exists(cache_path): logging.info('Using device cache: %s', cache_path) with open(cache_path) as f: device.LoadCacheData(f.read()) # Delete the cached file so that any exceptions cause it to be cleared. os.unlink(cache_path) else: logging.info('No device cache present: %s', cache_path) def save_cache(): with open(cache_path, 'w') as f: f.write(device.DumpCacheData()) logging.info('Wrote device cache: %s', cache_path) # Create 2 lock files: # * install.lock tells the app to pause on start-up (until we release it). # * firstrun.lock is used by the app to pause all secondary processes until # the primary process finishes loading the .dex / .so files. def create_lock_files(): # Creates or zeros out lock files. cmd = ('D="%s";' 'mkdir -p $D &&' 'echo -n >$D/install.lock 2>$D/firstrun.lock') device.RunShellCommand(cmd % device_incremental_dir, check_return=True) # The firstrun.lock is released by the app itself. def release_installer_lock(): device.RunShellCommand('echo > %s/install.lock' % device_incremental_dir, check_return=True) # Concurrency here speeds things up quite a bit, but DeviceUtils hasn't # been designed for multi-threading. Enabling only because this is a # developer-only tool. setup_timer = _Execute(use_concurrency, create_lock_files, restore_cache, check_selinux) _Execute(use_concurrency, do_install, do_push_files) finalize_timer = _Execute(use_concurrency, release_installer_lock, save_cache) logging.info( 'Took %s seconds (setup=%s, install=%s, libs=%s, dex=%s, finalize=%s)', main_timer.GetDelta(), setup_timer.GetDelta(), install_timer.GetDelta(), push_native_timer.GetDelta(), push_dex_timer.GetDelta(), finalize_timer.GetDelta()) if show_proguard_warning: logging.warning( 'Target had proguard enabled, but incremental install uses ' 'non-proguarded .dex files. Performance characteristics ' 'may differ.')
def testGetSplitsApksWithAdditionalLocalesIncorrectFormat(self): apk = apk_helper.ToHelper('abc.apks') with self.assertRaises(apk_helper.ApkHelperError): apk.GetApkPaths(_MockDeviceUtils(), additional_locales=['es'])
def main(): parser = argparse.ArgumentParser() parser.add_argument('apk_path', help='The path to the APK to install.') parser.add_argument('--split', action='append', dest='splits', help='A glob matching the apk splits. ' 'Can be specified multiple times.') parser.add_argument('--native_lib', dest='native_libs', help='Path to native library (repeatable)', action='append', default=[]) parser.add_argument('--dex-file', dest='dex_files', help='Path to dex files (repeatable)', action='append', default=[]) parser.add_argument('-d', '--device', dest='device', help='Target device for apk to install on.') parser.add_argument('--uninstall', action='store_true', default=False, help='Remove the app and all side-loaded files.') parser.add_argument('--output-directory', help='Path to the root build directory.') parser.add_argument('--no-threading', action='store_false', default=True, dest='threading', help='Do not install and push concurrently') parser.add_argument( '--no-cache', action='store_false', default=True, dest='cache', help='Do not use cached information about what files are ' 'currently on the target device.') parser.add_argument('--show-proguard-warning', action='store_true', default=False, help='Print a warning about proguard being disabled') parser.add_argument('-v', '--verbose', dest='verbose_count', default=0, action='count', help='Verbose level (multiple times for more)') args = parser.parse_args() run_tests_helper.SetLogLevel(args.verbose_count) constants.SetBuildType('Debug') if args.output_directory: constants.SetOutputDirectory(args.output_directory) if args.device: # Retries are annoying when commands fail for legitimate reasons. Might want # to enable them if this is ever used on bots though. device = device_utils.DeviceUtils(args.device, default_retries=0, enable_device_files_cache=True) else: devices = device_utils.DeviceUtils.HealthyDevices( default_retries=0, enable_device_files_cache=True) if not devices: raise device_errors.NoDevicesError() elif len(devices) == 1: device = devices[0] else: all_devices = device_utils.DeviceUtils.parallel(devices) msg = ('More than one device available.\n' 'Use --device=SERIAL to select a device.\n' 'Available devices:\n') descriptions = all_devices.pMap( lambda d: d.build_description).pGet(None) for d, desc in zip(devices, descriptions): msg += ' %s (%s)\n' % (d, desc) raise Exception(msg) apk = apk_helper.ToHelper(args.apk_path) if args.uninstall: Uninstall(device, apk.GetPackageName()) else: Install(device, apk, split_globs=args.splits, native_libs=args.native_libs, dex_files=args.dex_files, enable_device_cache=args.cache, use_concurrency=args.threading, show_proguard_warning=args.show_proguard_warning)
def testToHelperApks(self): apk = apk_helper.ToHelper('abc.apks') self.assertTrue(isinstance(apk, apk_helper.ApksHelper))
def Install(device, install_json, apk=None, enable_device_cache=False, use_concurrency=True, permissions=()): """Installs the given incremental apk and all required supporting files. Args: device: A DeviceUtils instance (to install to). install_json: Path to .json file or already parsed .json object. apk: An existing ApkHelper instance for the apk (optional). enable_device_cache: Whether to enable on-device caching of checksums. use_concurrency: Whether to speed things up using multiple threads. permissions: A list of the permissions to grant, or None to grant all non-denylisted permissions in the manifest. """ if isinstance(install_json, basestring): with open(install_json) as f: install_dict = json.load(f) else: install_dict = install_json if install_dict.get('dont_even_try'): raise Exception(install_dict['dont_even_try']) main_timer = time_profile.TimeProfile() install_timer = time_profile.TimeProfile() push_native_timer = time_profile.TimeProfile() merge_dex_timer = time_profile.TimeProfile() push_dex_timer = time_profile.TimeProfile() def fix_path(p): return os.path.normpath(os.path.join(constants.GetOutDirectory(), p)) if not apk: apk = apk_helper.ToHelper(fix_path(install_dict['apk_path'])) split_globs = [fix_path(p) for p in install_dict['split_globs']] native_libs = [fix_path(p) for p in install_dict['native_libs']] dex_files = [fix_path(p) for p in install_dict['dex_files']] show_proguard_warning = install_dict.get('show_proguard_warning') apk_package = apk.GetPackageName() device_incremental_dir = _GetDeviceIncrementalDir(apk_package) dex_staging_dir = os.path.join(constants.GetOutDirectory(), 'incremental-install', install_dict['apk_path']) device_dex_dir = posixpath.join(device_incremental_dir, 'dex') # Install .apk(s) if any of them have changed. def do_install(): install_timer.Start() if split_globs: splits = [] for split_glob in split_globs: splits.extend((f for f in glob.glob(split_glob))) device.InstallSplitApk(apk, splits, allow_downgrade=True, reinstall=True, allow_cached_props=True, permissions=permissions) else: device.Install(apk, allow_downgrade=True, reinstall=True, permissions=permissions) install_timer.Stop(log=False) # Push .so and .dex files to the device (if they have changed). def do_push_files(): def do_push_native(): push_native_timer.Start() if native_libs: with build_utils.TempDir() as temp_dir: device_lib_dir = posixpath.join(device_incremental_dir, 'lib') for path in native_libs: # Note: Can't use symlinks as they don't work when # "adb push parent_dir" is used (like we do here). shutil.copy( path, os.path.join(temp_dir, os.path.basename(path))) device.PushChangedFiles([(temp_dir, device_lib_dir)], delete_device_stale=True) push_native_timer.Stop(log=False) def do_merge_dex(): merge_dex_timer.Start() shards = _AllocateDexShards(dex_files) build_utils.MakeDirectory(dex_staging_dir) _CreateDexFiles(shards, dex_staging_dir, use_concurrency) merge_dex_timer.Stop(log=False) def do_push_dex(): push_dex_timer.Start() device.PushChangedFiles([(dex_staging_dir, device_dex_dir)], delete_device_stale=True) push_dex_timer.Stop(log=False) _Execute(use_concurrency, do_push_native, do_merge_dex) do_push_dex() def check_device_configured(): target_sdk_version = int(apk.GetTargetSdkVersion()) # Beta Q builds apply whitelist to targetSdk=28 as well. if target_sdk_version >= 28 and device.build_version_sdk >= 28: # In P, there are two settings: # * hidden_api_policy_p_apps # * hidden_api_policy_pre_p_apps # In Q, there is just one: # * hidden_api_policy if device.build_version_sdk == 28: setting_name = 'hidden_api_policy_p_apps' else: setting_name = 'hidden_api_policy' apis_allowed = ''.join( device.RunShellCommand( ['settings', 'get', 'global', setting_name], check_return=True)) if apis_allowed.strip() not in '01': msg = """\ Cannot use incremental installs on Android P+ without first enabling access to non-SDK interfaces (https://developer.android.com/preview/non-sdk-q). To enable access: adb -s {0} shell settings put global {1} 0 To restore back to default: adb -s {0} shell settings delete global {1}""" raise Exception(msg.format(device.serial, setting_name)) cache_path = _DeviceCachePath(device) def restore_cache(): if not enable_device_cache: return if os.path.exists(cache_path): logging.info('Using device cache: %s', cache_path) with open(cache_path) as f: device.LoadCacheData(f.read()) # Delete the cached file so that any exceptions cause it to be cleared. os.unlink(cache_path) else: logging.info('No device cache present: %s', cache_path) def save_cache(): if not enable_device_cache: return with open(cache_path, 'w') as f: f.write(device.DumpCacheData()) logging.info('Wrote device cache: %s', cache_path) # Create 2 lock files: # * install.lock tells the app to pause on start-up (until we release it). # * firstrun.lock is used by the app to pause all secondary processes until # the primary process finishes loading the .dex / .so files. def create_lock_files(): # Creates or zeros out lock files. cmd = ('D="%s";' 'mkdir -p $D &&' 'echo -n >$D/install.lock 2>$D/firstrun.lock') device.RunShellCommand(cmd % device_incremental_dir, shell=True, check_return=True) # The firstrun.lock is released by the app itself. def release_installer_lock(): device.RunShellCommand('echo > %s/install.lock' % device_incremental_dir, check_return=True, shell=True) # Concurrency here speeds things up quite a bit, but DeviceUtils hasn't # been designed for multi-threading. Enabling only because this is a # developer-only tool. setup_timer = _Execute(use_concurrency, create_lock_files, restore_cache, check_device_configured) _Execute(use_concurrency, do_install, do_push_files) finalize_timer = _Execute(use_concurrency, release_installer_lock, save_cache) logging.info( 'Install of %s took %s seconds (setup=%s, install=%s, lib_push=%s, ' 'dex_merge=%s dex_push=%s, finalize=%s)', os.path.basename(apk.path), main_timer.GetDelta(), setup_timer.GetDelta(), install_timer.GetDelta(), push_native_timer.GetDelta(), merge_dex_timer.GetDelta(), push_dex_timer.GetDelta(), finalize_timer.GetDelta()) if show_proguard_warning: logging.warning( 'Target had proguard enabled, but incremental install uses ' 'non-proguarded .dex files. Performance characteristics ' 'may differ.')
def Run(output_directory, apk_path, incremental_install_json_path, command_line_flags_file): constants.SetOutputDirectory(output_directory) parser = argparse.ArgumentParser() command_parsers = parser.add_subparsers(title='Apk operations', dest='command') subp = command_parsers.add_parser('install', help='Install the apk.') _AddCommonOptions(subp) subp = command_parsers.add_parser('uninstall', help='Uninstall the apk.') _AddCommonOptions(subp) subp = command_parsers.add_parser('launch', help='Launches the apk with the given ' 'command-line flags, and optionally the ' 'given URL') _AddCommonOptions(subp) _AddLaunchOptions(subp) _AddArgsOptions(subp) subp = command_parsers.add_parser('run', help='Install and launch.') _AddCommonOptions(subp) _AddLaunchOptions(subp) _AddArgsOptions(subp) subp = command_parsers.add_parser('stop', help='Stop apks on all devices') _AddCommonOptions(subp) subp = command_parsers.add_parser( 'clear-data', help='Clear states for the given package') _AddCommonOptions(subp) subp = command_parsers.add_parser( 'argv', help='Display and update flags on devices.') _AddCommonOptions(subp) _AddArgsOptions(subp) subp = command_parsers.add_parser('gdb', help='Run build/android/adb_gdb script.') _AddCommonOptions(subp) _AddArgsOptions(subp) subp = command_parsers.add_parser( 'logcat', help='Run the shell command "adb logcat".') _AddCommonOptions(subp) args = parser.parse_args() run_tests_helper.SetLogLevel(args.verbose_count) command = args.command # Enable caching unless executing a helper script (where we won't get a chance # to update the cache afterwards). use_cache = command not in {'gdb', 'logcat'} devil_chromium.Initialize() devices = device_utils.DeviceUtils.HealthyDevices( device_arg=args.devices, enable_device_files_cache=use_cache, default_retries=0) devices_obj = device_utils.DeviceUtils.parallel(devices) if command in {'gdb', 'logcat'} and len(devices) > 1: raise device_errors.MultipleDevicesError(devices) if command in {'argv', 'stop', 'clear-data'} or len(args.devices) > 0: args.all = True if len(devices) > 1 and not args.all: raise Exception(_GenerateMissingAllFlagMessage(devices, devices_obj)) apk_name = os.path.basename(apk_path) apk_path, incremental_install_json_path = _SelectApk( apk_path, incremental_install_json_path, parser, args) install_dict = None if incremental_install_json_path: with open(incremental_install_json_path) as f: install_dict = json.load(f) apk = apk_helper.ToHelper( os.path.join(output_directory, install_dict['apk_path'])) else: apk = apk_helper.ToHelper(apk_path) apk_package = apk.GetPackageName() if use_cache: _LoadDeviceCaches(devices) if command == 'install': _InstallApk(apk, install_dict, devices_obj) elif command == 'uninstall': _UninstallApk(install_dict, devices_obj, apk_package) elif command == 'launch': _LaunchUrl(devices_obj, args.args, command_line_flags_file, args.url, apk) elif command == 'run': logging.warning('Installing...') _InstallApk(apk, install_dict, devices_obj) logging.warning('Sending launch intent...') _LaunchUrl(devices_obj, args.args, command_line_flags_file, args.url, apk) elif command == 'stop': devices_obj.ForceStop(apk_package) elif command == 'clear-data': devices_obj.ClearApplicationState(apk_package) elif command == 'argv': _ChangeFlags(devices, devices_obj, args.args, command_line_flags_file) elif command == 'gdb': gdb_script_path = os.path.dirname(__file__) + '/adb_gdb' program_name = '--program-name=%s' % os.path.splitext(apk_name)[0] package_name = '--package-name=%s' % apk_package output_dir = '--output-directory=%s' % output_directory adb_path = '--adb=%s' % adb_wrapper.AdbWrapper.GetAdbPath() device = '--device=%s' % devices[0].adb.GetDeviceSerial() # Use one lib dir per device so that changing between devices does require # refetching the device libs. libs_dir = '--pull-libs-dir=/tmp/adb-gdb-libs-%s' % ( devices[0].adb.GetDeviceSerial()) flags = [ gdb_script_path, program_name, package_name, output_dir, device, adb_path, libs_dir ] if args.args: flags += shlex.split(args.args) # Enable verbose output of adb_gdb if it's set for this script. if args.verbose_count > 0: flags.append('--verbose') logging.warning('Running: %s', ' '.join(pipes.quote(f) for f in flags)) logging.warning('All subsequent output is from adb_gdb script.') os.execv(gdb_script_path, flags) elif command == 'logcat': adb_path = adb_wrapper.AdbWrapper.GetAdbPath() flags = [adb_path, '-s', devices[0].adb.GetDeviceSerial(), 'logcat'] os.execv(adb_path, flags) # Save back to the cache. if use_cache: _SaveDeviceCaches(devices)
def testToHelperBundleScript(self): apk = apk_helper.ToHelper('abc_bundle') self.assertTrue(isinstance(apk, apk_helper.BundleScriptHelper))
def testGetSplitsApkModulesException(self): apk = apk_helper.ToHelper('abc.apk') with self.assertRaises(apk_helper.ApkHelperError): apk.GetApkPaths(None, modules=['a'])
def testGetSplitsApk(self): apk = apk_helper.ToHelper('abc.apk') with apk.GetApkPaths(_MockDeviceUtils()) as apk_paths: self.assertEquals(apk_paths, ['abc.apk'])
def testToHelperSplitException(self): with self.assertRaises(apk_helper.ApkHelperError): apk_helper.ToSplitHelper(apk_helper.ToHelper('abc.apk'), ['a.apk', 'b.apk'])