3 # Copyright 2015 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.
7 """Install *_incremental.apk targets as well as their dependent files."""
17 from devil
.android
import apk_helper
18 from devil
.android
import device_utils
19 from devil
.android
import device_errors
20 from devil
.utils
import reraiser_thread
21 from pylib
import constants
25 start_time
= time
.time()
26 logging
.basicConfig(level
=logging
.INFO
,
27 format
='%(asctime)s (%(thread)d) %(message)s')
29 parser
= argparse
.ArgumentParser()
30 parser
.add_argument('apk_path',
31 help='The path to the APK to install.')
32 parser
.add_argument('--split',
35 help='A glob matching the apk splits. '
36 'Can be specified multiple times.')
37 parser
.add_argument('--lib-dir',
38 help='Path to native libraries directory.')
39 parser
.add_argument('-d', '--device', dest
='device',
40 help='Target device for apk to install on.')
41 parser
.add_argument('--uninstall',
44 help='Remove the app and all side-loaded files.')
45 parser
.add_argument('--no-threading',
48 help='Do not install and push concurrently')
50 args
= parser
.parse_args()
52 constants
.SetBuildType('Debug')
55 # Retries are annoying when commands fail for legitimate reasons. Might want
56 # to enable them if this is ever used on bots though.
57 device
= device_utils
.DeviceUtils(args
.device
, default_retries
=0)
59 devices
= device_utils
.DeviceUtils
.HealthyDevices(default_retries
=0)
61 raise device_errors
.NoDevicesError()
62 elif len(devices
) == 1:
65 all_devices
= device_utils
.DeviceUtils
.parallel(devices
)
66 msg
= ('More than one device available.\n'
67 'Use --device=SERIAL to select a device.\n'
68 'Available devices:\n')
69 descriptions
= all_devices
.pMap(lambda d
: d
.build_description
).pGet(None)
70 for d
, desc
in zip(devices
, descriptions
):
71 msg
+= ' %s (%s)\n' % (d
, desc
)
74 apk_package
= apk_helper
.ApkHelper(args
.apk_path
).GetPackageName()
75 device_incremental_dir
= '/data/local/tmp/incremental-app-%s' % apk_package
78 logging
.info('Uninstalling .apk')
79 device
.Uninstall(apk_package
)
80 logging
.info('Removing side-loaded files')
81 device
.RunShellCommand(['rm', '-rf', device_incremental_dir
],
85 # Install .apk(s) if any of them have changed.
89 for split_glob
in args
.splits
:
90 splits
.extend((f
for f
in glob
.glob(split_glob
)))
91 device
.InstallSplitApk(args
.apk_path
, splits
, reinstall
=True,
92 allow_cached_props
=True)
94 device
.Install(args
.apk_path
, reinstall
=True)
96 # Push .so files to the device (if they have changed).
99 device_lib_dir
= posixpath
.join(device_incremental_dir
, 'lib')
100 device
.PushChangedFiles([(args
.lib_dir
, device_lib_dir
)],
101 delete_device_stale
=True)
102 # Concurrency here speeds things up quite a bit, but DeviceUtils hasn't
103 # been designed for multi-threading. Enabling only because this is a
104 # developer-only tool.
105 if args
.no_threading
:
109 reraiser_thread
.RunAsync((do_install
, do_push_libs
))
110 logging
.info('Took %s seconds' % round(time
.time() - start_time
, 1))
113 if __name__
== '__main__':