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."""
16 from devil
.android
import apk_helper
17 from devil
.android
import device_utils
18 from devil
.android
import device_errors
19 from devil
.utils
import reraiser_thread
20 from pylib
import constants
21 from pylib
.utils
import run_tests_helper
25 start_time
= time
.time()
26 parser
= argparse
.ArgumentParser()
27 parser
.add_argument('apk_path',
28 help='The path to the APK to install.')
29 parser
.add_argument('--split',
32 help='A glob matching the apk splits. '
33 'Can be specified multiple times.')
34 parser
.add_argument('--lib-dir',
35 help='Path to native libraries directory.')
36 parser
.add_argument('-d', '--device', dest
='device',
37 help='Target device for apk to install on.')
38 parser
.add_argument('--uninstall',
41 help='Remove the app and all side-loaded files.')
42 parser
.add_argument('--no-threading',
45 help='Do not install and push concurrently')
46 parser
.add_argument('-v',
51 help='Verbose level (multiple times for more)')
53 args
= parser
.parse_args()
55 logging
.basicConfig(format
='%(asctime)s (%(thread)d) %(message)s')
56 run_tests_helper
.SetLogLevel(args
.verbose_count
)
57 constants
.SetBuildType('Debug')
60 # Retries are annoying when commands fail for legitimate reasons. Might want
61 # to enable them if this is ever used on bots though.
62 device
= device_utils
.DeviceUtils(args
.device
, default_retries
=0)
64 devices
= device_utils
.DeviceUtils
.HealthyDevices(default_retries
=0)
66 raise device_errors
.NoDevicesError()
67 elif len(devices
) == 1:
70 all_devices
= device_utils
.DeviceUtils
.parallel(devices
)
71 msg
= ('More than one device available.\n'
72 'Use --device=SERIAL to select a device.\n'
73 'Available devices:\n')
74 descriptions
= all_devices
.pMap(lambda d
: d
.build_description
).pGet(None)
75 for d
, desc
in zip(devices
, descriptions
):
76 msg
+= ' %s (%s)\n' % (d
, desc
)
79 apk_package
= apk_helper
.ApkHelper(args
.apk_path
).GetPackageName()
80 device_incremental_dir
= '/data/local/tmp/incremental-app-%s' % apk_package
83 logging
.info('Uninstalling .apk')
84 device
.Uninstall(apk_package
)
85 logging
.info('Removing side-loaded files')
86 device
.RunShellCommand(['rm', '-rf', device_incremental_dir
],
90 # Install .apk(s) if any of them have changed.
94 for split_glob
in args
.splits
:
95 splits
.extend((f
for f
in glob
.glob(split_glob
)))
96 device
.InstallSplitApk(args
.apk_path
, splits
, reinstall
=True,
97 allow_cached_props
=True)
99 device
.Install(args
.apk_path
, reinstall
=True)
100 logging
.info('Finished installing .apk')
102 # Push .so files to the device (if they have changed).
105 device_lib_dir
= posixpath
.join(device_incremental_dir
, 'lib')
106 device
.PushChangedFiles([(args
.lib_dir
, device_lib_dir
)],
107 delete_device_stale
=True)
108 logging
.info('Finished pushing native libs')
110 # Concurrency here speeds things up quite a bit, but DeviceUtils hasn't
111 # been designed for multi-threading. Enabling only because this is a
112 # developer-only tool.
113 if args
.no_threading
:
117 reraiser_thread
.RunAsync((do_install
, do_push_libs
))
118 logging
.info('Took %s seconds', round(time
.time() - start_time
, 1))
121 if __name__
== '__main__':