blob: 834c6313e7430c834a38468c8cbefa5732a71f03 [file] [log] [blame]
[email protected]12f36c82013-03-29 06:21:131#!/usr/bin/env python
2#
3# Copyright (c) 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"""Provisions Android devices with settings required for bots.
8
9Usage:
10 ./provision_devices.py [-d <device serial number>]
11"""
12
[email protected]552df572014-02-26 20:31:3513import logging
[email protected]12f36c82013-03-29 06:21:1314import optparse
15import os
16import re
17import subprocess
18import sys
19import time
20
21from pylib import android_commands
22from pylib import constants
[email protected]552df572014-02-26 20:31:3523from pylib import device_settings
[email protected]ee7bf012014-03-24 18:04:5724from pylib.cmd_helper import GetCmdOutput
[email protected]044d79b2014-04-10 19:37:3025from pylib.device import device_utils
[email protected]12f36c82013-03-29 06:21:1326
[email protected]11ef9c02014-05-22 11:13:4027sys.path.append(os.path.join(constants.DIR_SOURCE_ROOT,
28 'third_party', 'android_testrunner'))
29import errors
30
[email protected]7849a332013-07-12 01:40:0931def KillHostHeartbeat():
[email protected]12f36c82013-03-29 06:21:1332 ps = subprocess.Popen(['ps', 'aux'], stdout = subprocess.PIPE)
33 stdout, _ = ps.communicate()
34 matches = re.findall('\\n.*host_heartbeat.*', stdout)
35 for match in matches:
[email protected]7849a332013-07-12 01:40:0936 print 'An instance of host heart beart running... will kill'
[email protected]12f36c82013-03-29 06:21:1337 pid = re.findall('(\d+)', match)[1]
38 subprocess.call(['kill', str(pid)])
[email protected]7849a332013-07-12 01:40:0939
40
41def LaunchHostHeartbeat():
42 # Kill if existing host_heartbeat
43 KillHostHeartbeat()
[email protected]12f36c82013-03-29 06:21:1344 # Launch a new host_heartbeat
[email protected]c89aae02013-04-06 00:25:1945 print 'Spawning host heartbeat...'
[email protected]b3c0d4a2013-06-05 23:28:0946 subprocess.Popen([os.path.join(constants.DIR_SOURCE_ROOT,
[email protected]12f36c82013-03-29 06:21:1347 'build/android/host_heartbeat.py')])
48
49
[email protected]c89aae02013-04-06 00:25:1950def PushAndLaunchAdbReboot(devices, target):
51 """Pushes and launches the adb_reboot binary on the device.
52
53 Arguments:
54 devices: The list of serial numbers of the device to which the
55 adb_reboot binary should be pushed.
56 target : The build target (example, Debug or Release) which helps in
57 locating the adb_reboot binary.
58 """
[email protected]044d79b2014-04-10 19:37:3059 for device_serial in devices:
60 print 'Will push and launch adb_reboot on %s' % device_serial
61 device = device_utils.DeviceUtils(device_serial)
[email protected]c89aae02013-04-06 00:25:1962 # Kill if adb_reboot is already running.
[email protected]044d79b2014-04-10 19:37:3063 device.old_interface.KillAllBlocking('adb_reboot', 2)
[email protected]c89aae02013-04-06 00:25:1964 # Push adb_reboot
65 print ' Pushing adb_reboot ...'
[email protected]b3c0d4a2013-06-05 23:28:0966 adb_reboot = os.path.join(constants.DIR_SOURCE_ROOT,
[email protected]c89aae02013-04-06 00:25:1967 'out/%s/adb_reboot' % target)
[email protected]044d79b2014-04-10 19:37:3068 device.old_interface.PushIfNeeded(adb_reboot, '/data/local/tmp/')
[email protected]c89aae02013-04-06 00:25:1969 # Launch adb_reboot
70 print ' Launching adb_reboot ...'
[email protected]7d2b7cf2014-05-14 15:15:1971 device.old_interface.GetAndroidToolStatusAndOutput(
72 '/data/local/tmp/adb_reboot')
[email protected]c89aae02013-04-06 00:25:1973 LaunchHostHeartbeat()
74
75
[email protected]044d79b2014-04-10 19:37:3076def _ConfigureLocalProperties(device):
[email protected]552df572014-02-26 20:31:3577 """Set standard readonly testing device properties prior to reboot."""
78 local_props = [
79 'ro.monkey=1',
80 'ro.test_harness=1',
81 'ro.audio.silent=1',
82 'ro.setupwizard.mode=DISABLED',
83 ]
[email protected]044d79b2014-04-10 19:37:3084 device.old_interface.SetProtectedFileContents(
85 constants.DEVICE_LOCAL_PROPERTIES_PATH,
86 '\n'.join(local_props))
[email protected]552df572014-02-26 20:31:3587 # Android will not respect the local props file if it is world writable.
[email protected]044d79b2014-04-10 19:37:3088 device.old_interface.RunShellCommandWithSU(
89 'chmod 644 %s' % constants.DEVICE_LOCAL_PROPERTIES_PATH)
90
91 # LOCAL_PROPERTIES_PATH = '/data/local.prop'
[email protected]552df572014-02-26 20:31:3592
93
[email protected]ee7bf012014-03-24 18:04:5794def WipeDeviceData(device):
95 """Wipes data from device, keeping only the adb_keys for authorization.
96
97 After wiping data on a device that has been authorized, adb can still
98 communicate with the device, but after reboot the device will need to be
99 re-authorized because the adb keys file is stored in /data/misc/adb/.
[email protected]2eeae0b02014-05-09 21:27:16100 Thus, adb_keys file is rewritten so the device does not need to be
101 re-authorized.
[email protected]ee7bf012014-03-24 18:04:57102
103 Arguments:
104 device: the device to wipe
105 """
[email protected]044d79b2014-04-10 19:37:30106 device_authorized = device.old_interface.FileExistsOnDevice(
107 constants.ADB_KEYS_FILE)
[email protected]ee7bf012014-03-24 18:04:57108 if device_authorized:
[email protected]044d79b2014-04-10 19:37:30109 adb_keys = device.old_interface.RunShellCommandWithSU(
[email protected]2eeae0b02014-05-09 21:27:16110 'cat %s' % constants.ADB_KEYS_FILE)
[email protected]044d79b2014-04-10 19:37:30111 device.old_interface.RunShellCommandWithSU('wipe data')
[email protected]ee7bf012014-03-24 18:04:57112 if device_authorized:
113 path_list = constants.ADB_KEYS_FILE.split('/')
114 dir_path = '/'.join(path_list[:len(path_list)-1])
[email protected]044d79b2014-04-10 19:37:30115 device.old_interface.RunShellCommandWithSU('mkdir -p %s' % dir_path)
[email protected]2eeae0b02014-05-09 21:27:16116 device.old_interface.RunShellCommand('echo %s > %s' %
117 (adb_keys[0], constants.ADB_KEYS_FILE))
118 for adb_key in adb_keys[1:]:
119 device.old_interface.RunShellCommand(
120 'echo %s >> %s' % (adb_key, constants.ADB_KEYS_FILE))
[email protected]ee7bf012014-03-24 18:04:57121
122
[email protected]12f36c82013-03-29 06:21:13123def ProvisionDevices(options):
124 if options.device is not None:
125 devices = [options.device]
126 else:
127 devices = android_commands.GetAttachedDevices()
[email protected]044d79b2014-04-10 19:37:30128 for device_serial in devices:
129 device = device_utils.DeviceUtils(device_serial)
[email protected]1f636d32014-04-26 02:29:41130 device.old_interface.EnableAdbRoot()
[email protected]ee7bf012014-03-24 18:04:57131 install_output = GetCmdOutput(
132 ['%s/build/android/adb_install_apk.py' % constants.DIR_SOURCE_ROOT,
133 '--apk',
134 '%s/build/android/CheckInstallApk-debug.apk' % constants.DIR_SOURCE_ROOT
135 ])
136 failure_string = 'Failure [INSTALL_FAILED_INSUFFICIENT_STORAGE]'
137 if failure_string in install_output:
138 WipeDeviceData(device)
[email protected]044d79b2014-04-10 19:37:30139 _ConfigureLocalProperties(device)
[email protected]552df572014-02-26 20:31:35140 device_settings.ConfigureContentSettingsDict(
[email protected]044d79b2014-04-10 19:37:30141 device, device_settings.DETERMINISTIC_DEVICE_SETTINGS)
[email protected]552df572014-02-26 20:31:35142 # TODO(tonyg): We eventually want network on. However, currently radios
143 # can cause perfbots to drain faster than they charge.
144 if 'perf' in os.environ.get('BUILDBOT_BUILDERNAME', '').lower():
145 device_settings.ConfigureContentSettingsDict(
[email protected]044d79b2014-04-10 19:37:30146 device, device_settings.NETWORK_DISABLED_SETTINGS)
147 device.old_interface.RunShellCommandWithSU('date -u %f' % time.time())
[email protected]a019dd872014-04-28 05:54:08148 (_, props) = device.old_interface.GetShellCommandStatusAndOutput('getprop')
149 for prop in props:
150 print prop
[email protected]c89aae02013-04-06 00:25:19151 if options.auto_reconnect:
152 PushAndLaunchAdbReboot(devices, options.target)
[email protected]12f36c82013-03-29 06:21:13153
154
155def main(argv):
[email protected]552df572014-02-26 20:31:35156 logging.basicConfig(level=logging.INFO)
157
[email protected]12f36c82013-03-29 06:21:13158 parser = optparse.OptionParser()
[email protected]2eeae0b02014-05-09 21:27:16159 parser.add_option('-w', '--wipe', action='store_true',
160 help='Wipe device data from all attached devices.')
[email protected]12f36c82013-03-29 06:21:13161 parser.add_option('-d', '--device',
162 help='The serial number of the device to be provisioned')
[email protected]c89aae02013-04-06 00:25:19163 parser.add_option('-t', '--target', default='Debug', help='The build target')
164 parser.add_option(
165 '-r', '--auto-reconnect', action='store_true',
166 help='Push binary which will reboot the device on adb disconnections.')
[email protected]12f36c82013-03-29 06:21:13167 options, args = parser.parse_args(argv[1:])
[email protected]fae5c5b2013-09-10 18:29:03168 constants.SetBuildType(options.target)
[email protected]12f36c82013-03-29 06:21:13169
170 if args:
171 print >> sys.stderr, 'Unused args %s' % args
172 return 1
173
[email protected]2eeae0b02014-05-09 21:27:16174 if options.wipe:
175 devices = android_commands.GetAttachedDevices()
176 for device_serial in devices:
177 device = device_utils.DeviceUtils(device_serial)
178 WipeDeviceData(device)
[email protected]11ef9c02014-05-22 11:13:40179 try:
180 (device_utils.DeviceUtils.parallel(devices)
181 .old_interface.Reboot(True).pFinish(None))
182 except errors.DeviceUnresponsiveError:
183 pass
[email protected]2eeae0b02014-05-09 21:27:16184 else:
185 ProvisionDevices(options)
[email protected]12f36c82013-03-29 06:21:13186
187
188if __name__ == '__main__':
189 sys.exit(main(sys.argv))