1 #!/usr/bin/env python 2 # 3 # Copyright 2013 The Chromium Authors. All rights reserved. 4 # Use of this source code is governed by a BSD-style license that can be 5 # found in the LICENSE file. 6 7 """Installs an APK. 8 9 """ 10 11 import optparse 12 import os 13 import re 14 import sys 15 16 from util import build_device 17 from util import build_utils 18 from util import md5_check 19 20 BUILD_ANDROID_DIR = os.path.join(os.path.dirname(__file__), '..') 21 sys.path.append(BUILD_ANDROID_DIR) 22 23 from pylib import constants 24 from pylib.utils import apk_helper 25 26 def GetNewMetadata(device, apk_package): 27 """Gets the metadata on the device for the apk_package apk.""" 28 output = device.RunShellCommand('ls -l /data/app/') 29 # Matches lines like: 30 # -rw-r--r-- system system 7376582 2013-04-19 16:34 \ 31 # org.chromium.chrome.shell.apk 32 # -rw-r--r-- system system 7376582 2013-04-19 16:34 \ 33 # org.chromium.chrome.shell-1.apk 34 apk_matcher = lambda s: re.match('.*%s(-[0-9]*)?(.apk)?$' % apk_package, s) 35 matches = filter(apk_matcher, output) 36 return matches[0] if matches else None 37 38 def HasInstallMetadataChanged(device, apk_package, metadata_path): 39 """Checks if the metadata on the device for apk_package has changed.""" 40 if not os.path.exists(metadata_path): 41 return True 42 43 with open(metadata_path, 'r') as expected_file: 44 return expected_file.read() != device.GetInstallMetadata(apk_package) 45 46 47 def RecordInstallMetadata(device, apk_package, metadata_path): 48 """Records the metadata from the device for apk_package.""" 49 metadata = GetNewMetadata(device, apk_package) 50 if not metadata: 51 raise Exception('APK install failed unexpectedly.') 52 53 with open(metadata_path, 'w') as outfile: 54 outfile.write(metadata) 55 56 57 def main(): 58 parser = optparse.OptionParser() 59 parser.add_option('--apk-path', 60 help='Path to .apk to install.') 61 parser.add_option('--install-record', 62 help='Path to install record (touched only when APK is installed).') 63 parser.add_option('--build-device-configuration', 64 help='Path to build device configuration.') 65 parser.add_option('--stamp', 66 help='Path to touch on success.') 67 parser.add_option('--configuration-name', 68 help='The build CONFIGURATION_NAME') 69 options, _ = parser.parse_args() 70 71 device = build_device.GetBuildDeviceFromPath( 72 options.build_device_configuration) 73 if not device: 74 return 75 76 constants.SetBuildType(options.configuration_name) 77 78 serial_number = device.GetSerialNumber() 79 apk_package = apk_helper.GetPackageName(options.apk_path) 80 81 metadata_path = '%s.%s.device.time.stamp' % (options.apk_path, serial_number) 82 83 # If the APK on the device does not match the one that was last installed by 84 # the build, then the APK has to be installed (regardless of the md5 record). 85 force_install = HasInstallMetadataChanged(device, apk_package, metadata_path) 86 87 def Install(): 88 device.Install(options.apk_path, reinstall=True) 89 RecordInstallMetadata(device, apk_package, metadata_path) 90 build_utils.Touch(options.install_record) 91 92 93 record_path = '%s.%s.md5.stamp' % (options.apk_path, serial_number) 94 md5_check.CallAndRecordIfStale( 95 Install, 96 record_path=record_path, 97 input_paths=[options.apk_path], 98 force=force_install) 99 100 if options.stamp: 101 build_utils.Touch(options.stamp) 102 103 104 if __name__ == '__main__': 105 sys.exit(main()) 106