diff options
author | mikecase <mikecase@chromium.org> | 2015-06-19 13:43:39 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-06-19 20:44:05 +0000 |
commit | 89d5ad7274ce871af5f4cd3f9f0a09b9ff90cf02 (patch) | |
tree | 287501ed37d8126356d48f06b29d7d87abcaefaa /build | |
parent | 7e337bc2da8af6b1921d80d0e7581b2f12575792 (diff) | |
download | chromium_src-89d5ad7274ce871af5f4cd3f9f0a09b9ff90cf02.zip chromium_src-89d5ad7274ce871af5f4cd3f9f0a09b9ff90cf02.tar.gz chromium_src-89d5ad7274ce871af5f4cd3f9f0a09b9ff90cf02.tar.bz2 |
Add InstallSplitApk function to device utils.
Adding a InstallSplitApk function to device utils so that our
test runner will be able to support install/testing split
apks.
BUG=
Review URL: https://codereview.chromium.org/1166113002
Cr-Commit-Position: refs/heads/master@{#335336}
Diffstat (limited to 'build')
-rwxr-xr-x | build/android/gyp/apk_install.py | 48 | ||||
-rw-r--r-- | build/android/gyp/util/build_device.py | 3 | ||||
-rw-r--r-- | build/android/pylib/device/device_utils.py | 119 | ||||
-rwxr-xr-x | build/android/pylib/device/device_utils_test.py | 108 | ||||
-rw-r--r-- | build/android/pylib/sdk/split_select.py | 66 | ||||
-rwxr-xr-x | build/android/update_verification.py | 2 |
6 files changed, 246 insertions, 100 deletions
diff --git a/build/android/gyp/apk_install.py b/build/android/gyp/apk_install.py index c909867..a512e50 100755 --- a/build/android/gyp/apk_install.py +++ b/build/android/gyp/apk_install.py @@ -23,28 +23,6 @@ sys.path.append(BUILD_ANDROID_DIR) from pylib import constants from pylib.utils import apk_helper -_DPI_TO_DENSITY = { - 120: 'ldpi', - 160: 'mdpi', - 240: 'hdpi', - 320: 'xhdpi', - 480: 'xxhdpi', - } - - -def RetrieveDeviceConfig(device): - """Probes the given device for its split-select config. - - For example: en-rUS-xhdpi:armeabi-v7a - Run "split-select --help" for more info about the format. - """ - language = device.GetProp('persist.sys.language') - country = device.GetProp('persist.sys.country') - density_dpi = int(device.GetProp('ro.sf.lcd_density')) - density = _DPI_TO_DENSITY.get(density_dpi, 'tvdpi') - abi = device.product_cpu_abi - return '%s-r%s-%s:%s' % (language, country, density, abi) - def GetNewMetadata(device, apk_package): """Gets the metadata on the device for the apk_package apk.""" @@ -114,34 +92,10 @@ def main(): # the build, then the APK has to be installed (regardless of the md5 record). force_install = HasInstallMetadataChanged(device, apk_package, metadata_path) - def SelectSplits(target_config, base_apk, split_apks, android_sdk_tools): - cmd = [os.path.join(android_sdk_tools, 'split-select'), - '--target', target_config, - '--base', base_apk, - ] - for split in split_apks: - cmd.extend(('--split', split)) - - # split-select outputs one path per line and a blank line at the end. - output = build_utils.CheckOutput(cmd) - return [x for x in output.split('\n') if x] def Install(): if options.split_apk_path: - requiredSdkVersion = constants.ANDROID_SDK_VERSION_CODES.LOLLIPOP - actualSdkVersion = device.device.build_version_sdk - if actualSdkVersion < requiredSdkVersion: - raise Exception(('--split-apk-path requires sdk version %s. Device has ' - 'version %s') % (requiredSdkVersion, actualSdkVersion)) - device_config = RetrieveDeviceConfig(device.device) - active_splits = SelectSplits( - device_config, - options.apk_path, - options.split_apk_path, - options.android_sdk_tools) - - all_apks = [options.apk_path] + active_splits - device.device.adb.InstallMultiple(all_apks, reinstall=True) + device.InstallSplitApk(options.apk_path, options.split_apk_path) else: device.Install(options.apk_path, reinstall=True) diff --git a/build/android/gyp/util/build_device.py b/build/android/gyp/util/build_device.py index 7e0d57b..8ab1112 100644 --- a/build/android/gyp/util/build_device.py +++ b/build/android/gyp/util/build_device.py @@ -42,6 +42,9 @@ class BuildDevice(object): def Install(self, *args, **kwargs): return self.device.Install(*args, **kwargs) + def InstallSplitApk(self, *args, **kwargs): + return self.device.InstallSplitApk(*args, **kwargs) + def GetInstallMetadata(self, apk_package): """Gets the metadata on the device for the apk_package apk.""" # Matches lines like: diff --git a/build/android/pylib/device/device_utils.py b/build/android/pylib/device/device_utils.py index 7420068..558461f 100644 --- a/build/android/pylib/device/device_utils.py +++ b/build/android/pylib/device/device_utils.py @@ -33,6 +33,7 @@ from pylib.device import device_errors from pylib.device import intent from pylib.device import logcat_monitor from pylib.device.commands import install_commands +from pylib.sdk import split_select from pylib.utils import apk_helper from pylib.utils import base_error from pylib.utils import device_temp_file @@ -339,14 +340,14 @@ class DeviceUtils(object): return value @decorators.WithTimeoutAndRetriesFromInstance() - def GetApplicationPath(self, package, timeout=None, retries=None): - """Get the path of the installed apk on the device for the given package. + def GetApplicationPaths(self, package, timeout=None, retries=None): + """Get the paths of the installed apks on the device for the given package. Args: package: Name of the package. Returns: - Path to the apk on the device if it exists, None otherwise. + List of paths to the apks on the device for the given package. """ # 'pm path' is liable to incorrectly exit with a nonzero number starting # in Lollipop. @@ -354,14 +355,15 @@ class DeviceUtils(object): # released to put an upper bound on this. should_check_return = (self.build_version_sdk < constants.ANDROID_SDK_VERSION_CODES.LOLLIPOP) - output = self.RunShellCommand(['pm', 'path', package], single_line=True, - check_return=should_check_return) - if not output: - return None - if not output.startswith('package:'): - raise device_errors.CommandFailedError('pm path returned: %r' % output, - str(self)) - return output[len('package:'):] + output = self.RunShellCommand( + ['pm', 'path', package], check_return=should_check_return) + apks = [] + for line in output: + if not line.startswith('package:'): + raise device_errors.CommandFailedError( + 'pm path returned: %r' % '\n'.join(output), str(self)) + apks.append(line[len('package:'):]) + return apks @decorators.WithTimeoutAndRetriesFromInstance() def GetApplicationDataDirectory(self, package, timeout=None, retries=None): @@ -413,7 +415,7 @@ class DeviceUtils(object): def pm_ready(): try: - return self.GetApplicationPath('android') + return self.GetApplicationPaths('android') except device_errors.CommandFailedError: return False @@ -483,10 +485,14 @@ class DeviceUtils(object): DeviceUnreachableError on missing device. """ package_name = apk_helper.GetPackageName(apk_path) - device_path = self.GetApplicationPath(package_name) - if device_path is not None: + device_paths = self.GetApplicationPaths(package_name) + if device_paths: + if len(device_paths) > 1: + logging.warning( + 'Installing single APK (%s) when split APKs (%s) are currently ' + 'installed.', apk_path, ' '.join(device_paths)) (files_to_push, _) = self._GetChangedAndStaleFiles( - apk_path, device_path) + apk_path, device_paths[0]) should_install = bool(files_to_push) if should_install and not reinstall: self.adb.Uninstall(package_name) @@ -495,6 +501,62 @@ class DeviceUtils(object): if should_install: self.adb.Install(apk_path, reinstall=reinstall) + @decorators.WithTimeoutAndRetriesDefaults( + INSTALL_DEFAULT_TIMEOUT, + INSTALL_DEFAULT_RETRIES) + def InstallSplitApk(self, base_apk, split_apks, reinstall=False, + timeout=None, retries=None): + """Install a split APK. + + Noop if all of the APK splits are already installed. + + Args: + base_apk: A string of the path to the base APK. + split_apks: A list of strings of paths of all of the APK splits. + reinstall: A boolean indicating if we should keep any existing app data. + timeout: timeout in seconds + retries: number of retries + + Raises: + CommandFailedError if the installation fails. + CommandTimeoutError if the installation times out. + DeviceUnreachableError on missing device. + DeviceVersionError if device SDK is less than Android L. + """ + self._CheckSdkLevel(constants.ANDROID_SDK_VERSION_CODES.LOLLIPOP) + + all_apks = [base_apk] + split_select.SelectSplits( + self, base_apk, split_apks) + package_name = apk_helper.GetPackageName(base_apk) + device_apk_paths = self.GetApplicationPaths(package_name) + + if device_apk_paths: + partial_install_package = package_name + device_checksums = md5sum.CalculateDeviceMd5Sums(device_apk_paths, self) + host_checksums = md5sum.CalculateHostMd5Sums(all_apks) + apks_to_install = [k for (k, v) in host_checksums.iteritems() + if v not in device_checksums.values()] + if apks_to_install and not reinstall: + self.adb.Uninstall(package_name) + partial_install_package = None + apks_to_install = all_apks + else: + partial_install_package = None + apks_to_install = all_apks + if apks_to_install: + self.adb.InstallMultiple( + apks_to_install, partial=partial_install_package, reinstall=reinstall) + + def _CheckSdkLevel(self, required_sdk_level): + """Raises an exception if the device does not have the required SDK level. + """ + if self.build_version_sdk < required_sdk_level: + raise device_errors.DeviceVersionError( + ('Requires SDK level %s, device is SDK level %s' % + (required_sdk_level, self.build_version_sdk)), + device_serial=self.adb.GetDeviceSerial()) + + @decorators.WithTimeoutAndRetriesFromInstance() def RunShellCommand(self, cmd, check_return=False, cwd=None, env=None, as_root=False, single_line=False, large_output=False, @@ -806,7 +868,7 @@ class DeviceUtils(object): # may never return. if ((self.build_version_sdk >= constants.ANDROID_SDK_VERSION_CODES.JELLY_BEAN_MR2) - or self.GetApplicationPath(package)): + or self.GetApplicationPaths(package)): self.RunShellCommand(['pm', 'clear', package], check_return=True) @decorators.WithTimeoutAndRetriesFromInstance() @@ -1293,6 +1355,28 @@ class DeviceUtils(object): else: return False + @property + def language(self): + """Returns the language setting on the device.""" + return self.GetProp('persist.sys.language', cache=False) + + @property + def country(self): + """Returns the country setting on the device.""" + return self.GetProp('persist.sys.country', cache=False) + + @property + def screen_density(self): + """Returns the screen density of the device.""" + DPI_TO_DENSITY = { + 120: 'ldpi', + 160: 'mdpi', + 240: 'hdpi', + 320: 'xhdpi', + 480: 'xxhdpi', + } + dpi = int(self.GetProp('ro.sf.lcd_density', cache=True)) + return DPI_TO_DENSITY.get(dpi, 'tvdpi') @property def build_description(self): @@ -1633,5 +1717,4 @@ class DeviceUtils(object): return False return [cls(adb) for adb in adb_wrapper.AdbWrapper.Devices() - if not blacklisted(adb)] - + if not blacklisted(adb)]
\ No newline at end of file diff --git a/build/android/pylib/device/device_utils_test.py b/build/android/pylib/device/device_utils_test.py index 2517f66..8cb4e3c 100755 --- a/build/android/pylib/device/device_utils_test.py +++ b/build/android/pylib/device/device_utils_test.py @@ -27,6 +27,7 @@ from pylib.device import adb_wrapper from pylib.device import device_errors from pylib.device import device_utils from pylib.device import intent +from pylib.sdk import split_select from pylib.utils import mock_calls # RunCommand from third_party/android_testrunner/run_command.py is mocked @@ -310,30 +311,30 @@ class DeviceUtilsGetExternalStoragePathTest(DeviceUtilsTest): self.device.GetExternalStoragePath() -class DeviceUtilsGetApplicationPathTest(DeviceUtilsTest): +class DeviceUtilsGetApplicationPathsTest(DeviceUtilsTest): - def testGetApplicationPath_exists(self): + def testGetApplicationPaths_exists(self): with self.assertCalls( (self.call.adb.Shell('getprop ro.build.version.sdk'), '19\n'), (self.call.adb.Shell('pm path android'), 'package:/path/to/android.apk\n')): - self.assertEquals('/path/to/android.apk', - self.device.GetApplicationPath('android')) + self.assertEquals(['/path/to/android.apk'], + self.device.GetApplicationPaths('android')) - def testGetApplicationPath_notExists(self): + def testGetApplicationPaths_notExists(self): with self.assertCalls( (self.call.adb.Shell('getprop ro.build.version.sdk'), '19\n'), (self.call.adb.Shell('pm path not.installed.app'), '')): - self.assertEquals(None, - self.device.GetApplicationPath('not.installed.app')) + self.assertEquals([], + self.device.GetApplicationPaths('not.installed.app')) - def testGetApplicationPath_fails(self): + def testGetApplicationPaths_fails(self): with self.assertCalls( (self.call.adb.Shell('getprop ro.build.version.sdk'), '19\n'), (self.call.adb.Shell('pm path android'), self.CommandError('ERROR. Is package manager running?\n'))): with self.assertRaises(device_errors.CommandFailedError): - self.device.GetApplicationPath('android') + self.device.GetApplicationPaths('android') class DeviceUtilsGetApplicationDataDirectoryTest(DeviceUtilsTest): @@ -365,8 +366,8 @@ class DeviceUtilsWaitUntilFullyBootedTest(DeviceUtilsTest): (self.call.device.GetExternalStoragePath(), '/fake/storage/path'), (self.call.adb.Shell('test -d /fake/storage/path'), ''), # pm_ready - (self.call.device.GetApplicationPath('android'), - 'package:/some/fake/path'), + (self.call.device.GetApplicationPaths('android'), + ['package:/some/fake/path']), # boot_completed (self.call.device.GetProp('sys.boot_completed'), '1')): self.device.WaitUntilFullyBooted(wifi=False) @@ -378,8 +379,8 @@ class DeviceUtilsWaitUntilFullyBootedTest(DeviceUtilsTest): (self.call.device.GetExternalStoragePath(), '/fake/storage/path'), (self.call.adb.Shell('test -d /fake/storage/path'), ''), # pm_ready - (self.call.device.GetApplicationPath('android'), - 'package:/some/fake/path'), + (self.call.device.GetApplicationPaths('android'), + ['package:/some/fake/path']), # boot_completed (self.call.device.GetProp('sys.boot_completed'), '1'), # wifi_enabled @@ -402,8 +403,8 @@ class DeviceUtilsWaitUntilFullyBootedTest(DeviceUtilsTest): (self.call.device.GetExternalStoragePath(), '/fake/storage/path'), (self.call.adb.Shell('test -d /fake/storage/path'), ''), # pm_ready - (self.call.device.GetApplicationPath('android'), - 'package:/some/fake/path'), + (self.call.device.GetApplicationPaths('android'), + ['package:/some/fake/path']), # boot_completed (self.call.device.GetProp('sys.boot_completed'), '1')): self.device.WaitUntilFullyBooted(wifi=False) @@ -439,11 +440,11 @@ class DeviceUtilsWaitUntilFullyBootedTest(DeviceUtilsTest): (self.call.device.GetExternalStoragePath(), '/fake/storage/path'), (self.call.adb.Shell('test -d /fake/storage/path'), ''), # pm_ready - (self.call.device.GetApplicationPath('android'), self.CommandError()), + (self.call.device.GetApplicationPaths('android'), self.CommandError()), # pm_ready - (self.call.device.GetApplicationPath('android'), self.CommandError()), + (self.call.device.GetApplicationPaths('android'), self.CommandError()), # pm_ready - (self.call.device.GetApplicationPath('android'), self.TimeoutError())): + (self.call.device.GetApplicationPaths('android'), self.TimeoutError())): with self.assertRaises(device_errors.CommandTimeoutError): self.device.WaitUntilFullyBooted(wifi=False) @@ -454,8 +455,8 @@ class DeviceUtilsWaitUntilFullyBootedTest(DeviceUtilsTest): (self.call.device.GetExternalStoragePath(), '/fake/storage/path'), (self.call.adb.Shell('test -d /fake/storage/path'), ''), # pm_ready - (self.call.device.GetApplicationPath('android'), - 'package:/some/fake/path'), + (self.call.device.GetApplicationPaths('android'), + ['package:/some/fake/path']), # boot_completed (self.call.device.GetProp('sys.boot_completed'), '0'), # boot_completed @@ -472,8 +473,8 @@ class DeviceUtilsWaitUntilFullyBootedTest(DeviceUtilsTest): (self.call.device.GetExternalStoragePath(), '/fake/storage/path'), (self.call.adb.Shell('test -d /fake/storage/path'), ''), # pm_ready - (self.call.device.GetApplicationPath('android'), - 'package:/some/fake/path'), + (self.call.device.GetApplicationPaths('android'), + ['package:/some/fake/path']), # boot_completed (self.call.device.GetProp('sys.boot_completed'), '1'), # wifi_enabled @@ -519,7 +520,7 @@ class DeviceUtilsInstallTest(DeviceUtilsTest): with self.assertCalls( (mock.call.pylib.utils.apk_helper.GetPackageName('/fake/test/app.apk'), 'this.is.a.test.package'), - (self.call.device.GetApplicationPath('this.is.a.test.package'), None), + (self.call.device.GetApplicationPaths('this.is.a.test.package'), []), self.call.adb.Install('/fake/test/app.apk', reinstall=False)): self.device.Install('/fake/test/app.apk', retries=0) @@ -527,8 +528,8 @@ class DeviceUtilsInstallTest(DeviceUtilsTest): with self.assertCalls( (mock.call.pylib.utils.apk_helper.GetPackageName('/fake/test/app.apk'), 'this.is.a.test.package'), - (self.call.device.GetApplicationPath('this.is.a.test.package'), - '/fake/data/app/this.is.a.test.package.apk'), + (self.call.device.GetApplicationPaths('this.is.a.test.package'), + ['/fake/data/app/this.is.a.test.package.apk']), (self.call.device._GetChangedAndStaleFiles( '/fake/test/app.apk', '/fake/data/app/this.is.a.test.package.apk'), ([('/fake/test/app.apk', '/fake/data/app/this.is.a.test.package.apk')], @@ -541,8 +542,8 @@ class DeviceUtilsInstallTest(DeviceUtilsTest): with self.assertCalls( (mock.call.pylib.utils.apk_helper.GetPackageName('/fake/test/app.apk'), 'this.is.a.test.package'), - (self.call.device.GetApplicationPath('this.is.a.test.package'), - '/fake/data/app/this.is.a.test.package.apk'), + (self.call.device.GetApplicationPaths('this.is.a.test.package'), + ['/fake/data/app/this.is.a.test.package.apk']), (self.call.device._GetChangedAndStaleFiles( '/fake/test/app.apk', '/fake/data/app/this.is.a.test.package.apk'), ([('/fake/test/app.apk', '/fake/data/app/this.is.a.test.package.apk')], @@ -554,8 +555,8 @@ class DeviceUtilsInstallTest(DeviceUtilsTest): with self.assertCalls( (mock.call.pylib.utils.apk_helper.GetPackageName('/fake/test/app.apk'), 'this.is.a.test.package'), - (self.call.device.GetApplicationPath('this.is.a.test.package'), - '/fake/data/app/this.is.a.test.package.apk'), + (self.call.device.GetApplicationPaths('this.is.a.test.package'), + ['/fake/data/app/this.is.a.test.package.apk']), (self.call.device._GetChangedAndStaleFiles( '/fake/test/app.apk', '/fake/data/app/this.is.a.test.package.apk'), ([], []))): @@ -565,12 +566,51 @@ class DeviceUtilsInstallTest(DeviceUtilsTest): with self.assertCalls( (mock.call.pylib.utils.apk_helper.GetPackageName('/fake/test/app.apk'), 'this.is.a.test.package'), - (self.call.device.GetApplicationPath('this.is.a.test.package'), None), + (self.call.device.GetApplicationPaths('this.is.a.test.package'), []), (self.call.adb.Install('/fake/test/app.apk', reinstall=False), self.CommandError('Failure\r\n'))): with self.assertRaises(device_errors.CommandFailedError): self.device.Install('/fake/test/app.apk', retries=0) +class DeviceUtilsInstallSplitApkTest(DeviceUtilsTest): + + def testInstallSplitApk_noPriorInstall(self): + with self.assertCalls( + (self.call.device._CheckSdkLevel(21)), + (mock.call.pylib.sdk.split_select.SelectSplits( + self.device, 'base.apk', + ['split1.apk', 'split2.apk', 'split3.apk']), + ['split2.apk']), + (mock.call.pylib.utils.apk_helper.GetPackageName('base.apk'), + 'this.is.a.test.package'), + (self.call.device.GetApplicationPaths('this.is.a.test.package'), []), + (self.call.adb.InstallMultiple( + ['base.apk', 'split2.apk'], partial=None, reinstall=False))): + self.device.InstallSplitApk('base.apk', + ['split1.apk', 'split2.apk', 'split3.apk'], retries=0) + + def testInstallSplitApk_partialInstall(self): + with self.assertCalls( + (self.call.device._CheckSdkLevel(21)), + (mock.call.pylib.sdk.split_select.SelectSplits( + self.device, 'base.apk', + ['split1.apk', 'split2.apk', 'split3.apk']), + ['split2.apk']), + (mock.call.pylib.utils.apk_helper.GetPackageName('base.apk'), + 'test.package'), + (self.call.device.GetApplicationPaths('test.package'), + ['base-on-device.apk', 'split2-on-device.apk']), + (mock.call.pylib.utils.md5sum.CalculateDeviceMd5Sums( + ['base-on-device.apk', 'split2-on-device.apk'], self.device), + {'base-on-device.apk': 'AAA', 'split2-on-device.apk': 'BBB'}), + (mock.call.pylib.utils.md5sum.CalculateHostMd5Sums( + ['base.apk', 'split2.apk']), + {'base.apk': 'AAA', 'split2.apk': 'CCC'}), + (self.call.adb.InstallMultiple( + ['split2.apk'], partial='test.package', reinstall=True))): + self.device.InstallSplitApk('base.apk', + ['split1.apk', 'split2.apk', 'split3.apk'], reinstall=True, retries=0) + class DeviceUtilsRunShellCommandTest(DeviceUtilsTest): @@ -1081,8 +1121,8 @@ class DeviceUtilsClearApplicationStateTest(DeviceUtilsTest): def testClearApplicationState_packageDoesntExist(self): with self.assertCalls( (self.call.adb.Shell('getprop ro.build.version.sdk'), '17\n'), - (self.call.device.GetApplicationPath('this.package.does.not.exist'), - None)): + (self.call.device.GetApplicationPaths('this.package.does.not.exist'), + [])): self.device.ClearApplicationState('this.package.does.not.exist') def testClearApplicationState_packageDoesntExistOnAndroidJBMR2OrAbove(self): @@ -1095,8 +1135,8 @@ class DeviceUtilsClearApplicationStateTest(DeviceUtilsTest): def testClearApplicationState_packageExists(self): with self.assertCalls( (self.call.adb.Shell('getprop ro.build.version.sdk'), '17\n'), - (self.call.device.GetApplicationPath('this.package.exists'), - '/data/app/this.package.exists.apk'), + (self.call.device.GetApplicationPaths('this.package.exists'), + ['/data/app/this.package.exists.apk']), (self.call.adb.Shell('pm clear this.package.exists'), 'Success\r\n')): self.device.ClearApplicationState('this.package.exists') diff --git a/build/android/pylib/sdk/split_select.py b/build/android/pylib/sdk/split_select.py new file mode 100644 index 0000000..8752129 --- /dev/null +++ b/build/android/pylib/sdk/split_select.py @@ -0,0 +1,66 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""This module wraps Android's split-select tool.""" +# pylint: disable=unused-argument + +import os + +from pylib import cmd_helper +from pylib import constants +from pylib.utils import timeout_retry + +_SPLIT_SELECT_PATH = os.path.join(constants.ANDROID_SDK_TOOLS, 'split-select') +_DEFAULT_TIMEOUT = 30 +_DEFAULT_RETRIES = 2 + +def _RunSplitSelectCmd(args, timeout=None, retries=None): + """Runs a split-select command. + + Args: + args: A list of arguments for split-select. + timeout: Timeout in seconds. + retries: Number of retries. + + Returns: + The output of the command. + """ + cmd = [_SPLIT_SELECT_PATH] + args + status, output = cmd_helper.GetCmdStatusAndOutputWithTimeout( + cmd, timeout_retry.CurrentTimeoutThread().GetRemainingTime()) + if status != 0: + raise Exception('Failed running command %s' % str(cmd)) + return output + +def _SplitConfig(device): + """Returns a config specifying which APK splits are required by the device. + + Args: + device: A DeviceUtils object. + """ + return ('%s-r%s-%s:%s' % + (device.language, + device.country, + device.screen_density, + device.product_cpu_abi)) + +def SelectSplits(device, base_apk, split_apks, + timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES): + """Determines which APK splits the device requires. + + Args: + device: A DeviceUtils object. + base_apk: The path of the base APK. + split_apks: A list of paths of APK splits. + timeout: Timeout in seconds. + retries: Number of retries. + + Returns: + The list of APK splits that the device requires. + """ + config = _SplitConfig(device) + args = ['--target', config, '--base', base_apk] + for split in split_apks: + args.extend(['--split', split]) + return _RunSplitSelectCmd(args, timeout=timeout, retries=retries).splitlines()
\ No newline at end of file diff --git a/build/android/update_verification.py b/build/android/update_verification.py index 06cd2d6..05d083b 100755 --- a/build/android/update_verification.py +++ b/build/android/update_verification.py @@ -49,7 +49,7 @@ def TestUpdate(device, old_apk, new_apk, app_data, package_name): # Restore command is not synchronous raw_input('Select "Restore my data" on the device. Then press enter to ' 'continue.') - device_path = device.GetApplicationPath(package_name) + device_path = device.GetApplicationPaths(package_name) if not device_path: raise Exception('Expected package %s to already be installed. ' 'Package name might have changed!' % package_name) |