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.
16 from util
import build_device
17 from util
import build_utils
18 from util
import md5_check
20 BUILD_ANDROID_DIR
= os
.path
.join(os
.path
.dirname(__file__
), '..')
21 sys
.path
.append(BUILD_ANDROID_DIR
)
23 from pylib
import constants
24 from pylib
.utils
import apk_helper
35 def RetrieveDeviceConfig(device
):
36 """Probes the given device for its split-select config.
38 For example: en-rUS-xhdpi:armeabi-v7a
39 Run "split-select --help" for more info about the format.
41 language
= device
.GetProp('persist.sys.language')
42 country
= device
.GetProp('persist.sys.country')
43 density_dpi
= int(device
.GetProp('ro.sf.lcd_density'))
44 density
= _DPI_TO_DENSITY
.get(density_dpi
, 'tvdpi')
45 abi
= device
.product_cpu_abi
46 return '%s-r%s-%s:%s' % (language
, country
, density
, abi
)
49 def GetNewMetadata(device
, apk_package
):
50 """Gets the metadata on the device for the apk_package apk."""
51 output
= device
.RunShellCommand('ls -l /data/app/')
53 # -rw-r--r-- system system 7376582 2013-04-19 16:34 \
54 # org.chromium.chrome.shell.apk
55 # -rw-r--r-- system system 7376582 2013-04-19 16:34 \
56 # org.chromium.chrome.shell-1.apk
57 apk_matcher
= lambda s
: re
.match('.*%s(-[0-9]*)?(.apk)?$' % apk_package
, s
)
58 matches
= filter(apk_matcher
, output
)
59 return matches
[0] if matches
else None
61 def HasInstallMetadataChanged(device
, apk_package
, metadata_path
):
62 """Checks if the metadata on the device for apk_package has changed."""
63 if not os
.path
.exists(metadata_path
):
66 with
open(metadata_path
, 'r') as expected_file
:
67 return expected_file
.read() != device
.GetInstallMetadata(apk_package
)
70 def RecordInstallMetadata(device
, apk_package
, metadata_path
):
71 """Records the metadata from the device for apk_package."""
72 metadata
= GetNewMetadata(device
, apk_package
)
74 raise Exception('APK install failed unexpectedly.')
76 with
open(metadata_path
, 'w') as outfile
:
77 outfile
.write(metadata
)
81 parser
= optparse
.OptionParser()
82 parser
.add_option('--apk-path',
83 help='Path to .apk to install.')
84 parser
.add_option('--split-apk-path',
85 help='Path to .apk splits (can specify multiple times, causes '
86 '--install-multiple to be used.',
88 parser
.add_option('--android-sdk-tools',
89 help='Path to the Android SDK build tools folder. ' +
90 'Required when using --split-apk-path.')
91 parser
.add_option('--install-record',
92 help='Path to install record (touched only when APK is installed).')
93 parser
.add_option('--build-device-configuration',
94 help='Path to build device configuration.')
95 parser
.add_option('--stamp',
96 help='Path to touch on success.')
97 parser
.add_option('--configuration-name',
98 help='The build CONFIGURATION_NAME')
99 options
, _
= parser
.parse_args()
101 device
= build_device
.GetBuildDeviceFromPath(
102 options
.build_device_configuration
)
106 constants
.SetBuildType(options
.configuration_name
)
108 serial_number
= device
.GetSerialNumber()
109 apk_package
= apk_helper
.GetPackageName(options
.apk_path
)
111 metadata_path
= '%s.%s.device.time.stamp' % (options
.apk_path
, serial_number
)
113 # If the APK on the device does not match the one that was last installed by
114 # the build, then the APK has to be installed (regardless of the md5 record).
115 force_install
= HasInstallMetadataChanged(device
, apk_package
, metadata_path
)
117 def SelectSplits(target_config
, base_apk
, split_apks
, android_sdk_tools
):
118 cmd
= [os
.path
.join(android_sdk_tools
, 'split-select'),
119 '--target', target_config
,
122 for split
in split_apks
:
123 cmd
.extend(('--split', split
))
125 # split-select outputs one path per line and a blank line at the end.
126 output
= build_utils
.CheckOutput(cmd
)
127 return [x
for x
in output
.split('\n') if x
]
130 if options
.split_apk_path
:
131 requiredSdkVersion
= constants
.ANDROID_SDK_VERSION_CODES
.LOLLIPOP
132 actualSdkVersion
= device
.device
.build_version_sdk
133 if actualSdkVersion
< requiredSdkVersion
:
134 raise Exception(('--split-apk-path requires sdk version %s. Device has '
135 'version %s') % (requiredSdkVersion
, actualSdkVersion
))
136 device_config
= RetrieveDeviceConfig(device
.device
)
137 active_splits
= SelectSplits(
140 options
.split_apk_path
,
141 options
.android_sdk_tools
)
143 all_apks
= [options
.apk_path
] + active_splits
144 device
.device
.adb
.InstallMultiple(all_apks
, reinstall
=True)
146 device
.Install(options
.apk_path
, reinstall
=True)
148 RecordInstallMetadata(device
, apk_package
, metadata_path
)
149 build_utils
.Touch(options
.install_record
)
152 record_path
= '%s.%s.md5.stamp' % (options
.apk_path
, serial_number
)
153 md5_check
.CallAndRecordIfStale(
155 record_path
=record_path
,
156 input_paths
=[options
.apk_path
],
160 build_utils
.Touch(options
.stamp
)
163 if __name__
== '__main__':