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.
7 """Provisions Android devices with settings required for bots.
10 ./provision_devices.py [-d <device serial number>]
21 from pylib import android_commands
22 from pylib import constants
23 from pylib import device_settings
24 from pylib.cmd_helper import GetCmdOutput
27 def KillHostHeartbeat():
28 ps = subprocess.Popen(['ps', 'aux'], stdout = subprocess.PIPE)
29 stdout, _ = ps.communicate()
30 matches = re.findall('\\n.*host_heartbeat.*', stdout)
32 print 'An instance of host heart beart running... will kill'
33 pid = re.findall('(\d+)', match)[1]
34 subprocess.call(['kill', str(pid)])
37 def LaunchHostHeartbeat():
38 # Kill if existing host_heartbeat
40 # Launch a new host_heartbeat
41 print 'Spawning host heartbeat...'
42 subprocess.Popen([os.path.join(constants.DIR_SOURCE_ROOT,
43 'build/android/host_heartbeat.py')])
46 def PushAndLaunchAdbReboot(devices, target):
47 """Pushes and launches the adb_reboot binary on the device.
50 devices: The list of serial numbers of the device to which the
51 adb_reboot binary should be pushed.
52 target : The build target (example, Debug or Release) which helps in
53 locating the adb_reboot binary.
55 for device in devices:
56 print 'Will push and launch adb_reboot on %s' % device
57 android_cmd = android_commands.AndroidCommands(device)
58 # Kill if adb_reboot is already running.
59 android_cmd.KillAllBlocking('adb_reboot', 2)
61 print ' Pushing adb_reboot ...'
62 adb_reboot = os.path.join(constants.DIR_SOURCE_ROOT,
63 'out/%s/adb_reboot' % target)
64 android_cmd.PushIfNeeded(adb_reboot, '/data/local/tmp/')
66 print ' Launching adb_reboot ...'
67 p = subprocess.Popen(['adb', '-s', device, 'shell'], stdin=subprocess.PIPE)
68 p.communicate('/data/local/tmp/adb_reboot; exit\n')
72 def _ConfigureLocalProperties(adb):
73 """Set standard readonly testing device properties prior to reboot."""
78 'ro.setupwizard.mode=DISABLED',
80 adb.SetProtectedFileContents(android_commands.LOCAL_PROPERTIES_PATH,
81 '\n'.join(local_props))
82 # Android will not respect the local props file if it is world writable.
83 adb.RunShellCommandWithSU('chmod 644 %s' %
84 android_commands.LOCAL_PROPERTIES_PATH)
87 def WipeDeviceData(device):
88 """Wipes data from device, keeping only the adb_keys for authorization.
90 After wiping data on a device that has been authorized, adb can still
91 communicate with the device, but after reboot the device will need to be
92 re-authorized because the adb keys file is stored in /data/misc/adb/.
93 Thus, before reboot the adb_keys file is rewritten so the device does not need
97 device: the device to wipe
99 android_cmd = android_commands.AndroidCommands(device)
100 device_authorized = android_cmd.FileExistsOnDevice(constants.ADB_KEYS_FILE)
101 if device_authorized:
102 adb_keys = android_cmd.RunShellCommandWithSU(
103 'cat %s' % constants.ADB_KEYS_FILE)[0]
104 android_cmd.RunShellCommandWithSU('wipe data')
105 if device_authorized:
106 path_list = constants.ADB_KEYS_FILE.split('/')
107 dir_path = '/'.join(path_list[:len(path_list)-1])
108 android_cmd.RunShellCommandWithSU('mkdir -p %s' % dir_path)
109 adb_keys = android_cmd.RunShellCommand(
110 'echo %s > %s' % (adb_keys, constants.ADB_KEYS_FILE))
114 def ProvisionDevices(options):
115 if options.device is not None:
116 devices = [options.device]
118 devices = android_commands.GetAttachedDevices()
119 for device in devices:
120 android_cmd = android_commands.AndroidCommands(device)
121 install_output = GetCmdOutput(
122 ['%s/build/android/adb_install_apk.py' % constants.DIR_SOURCE_ROOT,
124 '%s/build/android/CheckInstallApk-debug.apk' % constants.DIR_SOURCE_ROOT
126 failure_string = 'Failure [INSTALL_FAILED_INSUFFICIENT_STORAGE]'
127 if failure_string in install_output:
128 WipeDeviceData(device)
129 _ConfigureLocalProperties(android_cmd)
130 device_settings.ConfigureContentSettingsDict(
131 android_cmd, device_settings.DETERMINISTIC_DEVICE_SETTINGS)
132 # TODO(tonyg): We eventually want network on. However, currently radios
133 # can cause perfbots to drain faster than they charge.
134 if 'perf' in os.environ.get('BUILDBOT_BUILDERNAME', '').lower():
135 device_settings.ConfigureContentSettingsDict(
136 android_cmd, device_settings.NETWORK_DISABLED_SETTINGS)
137 android_cmd.RunShellCommandWithSU('date -u %f' % time.time())
138 if options.auto_reconnect:
139 PushAndLaunchAdbReboot(devices, options.target)
143 logging.basicConfig(level=logging.INFO)
145 parser = optparse.OptionParser()
146 parser.add_option('-d', '--device',
147 help='The serial number of the device to be provisioned')
148 parser.add_option('-t', '--target', default='Debug', help='The build target')
150 '-r', '--auto-reconnect', action='store_true',
151 help='Push binary which will reboot the device on adb disconnections.')
152 options, args = parser.parse_args(argv[1:])
153 constants.SetBuildType(options.target)
156 print >> sys.stderr, 'Unused args %s' % args
159 ProvisionDevices(options)
162 if __name__ == '__main__':
163 sys.exit(main(sys.argv))