53eb373ef8c43aa492bd1677c7b35fbb58c15c20
[platform/framework/web/crosswalk.git] / src / build / android / provision_devices.py
1 #!/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
9 Usage:
10   ./provision_devices.py [-d <device serial number>]
11 """
12
13 import logging
14 import optparse
15 import os
16 import re
17 import subprocess
18 import sys
19 import time
20
21 from pylib import android_commands
22 from pylib import constants
23 from pylib import device_settings
24 from pylib.cmd_helper import GetCmdOutput
25
26
27 def KillHostHeartbeat():
28   ps = subprocess.Popen(['ps', 'aux'], stdout = subprocess.PIPE)
29   stdout, _ = ps.communicate()
30   matches = re.findall('\\n.*host_heartbeat.*', stdout)
31   for match in matches:
32     print 'An instance of host heart beart running... will kill'
33     pid = re.findall('(\d+)', match)[1]
34     subprocess.call(['kill', str(pid)])
35
36
37 def LaunchHostHeartbeat():
38   # Kill if existing host_heartbeat
39   KillHostHeartbeat()
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')])
44
45
46 def PushAndLaunchAdbReboot(devices, target):
47   """Pushes and launches the adb_reboot binary on the device.
48
49   Arguments:
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.
54   """
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)
60     # Push adb_reboot
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/')
65     # Launch adb_reboot
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')
69   LaunchHostHeartbeat()
70
71
72 def _ConfigureLocalProperties(adb):
73   """Set standard readonly testing device properties prior to reboot."""
74   local_props = [
75       'ro.monkey=1',
76       'ro.test_harness=1',
77       'ro.audio.silent=1',
78       'ro.setupwizard.mode=DISABLED',
79       ]
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)
85
86
87 def WipeDeviceData(device):
88   """Wipes data from device, keeping only the adb_keys for authorization.
89
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
94   to be re-authorized.
95
96   Arguments:
97     device: the device to wipe
98   """
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))
111   android_cmd.Reboot()
112
113
114 def ProvisionDevices(options):
115   if options.device is not None:
116     devices = [options.device]
117   else:
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,
123        '--apk',
124        '%s/build/android/CheckInstallApk-debug.apk' % constants.DIR_SOURCE_ROOT
125        ])
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)
140
141
142 def main(argv):
143   logging.basicConfig(level=logging.INFO)
144
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')
149   parser.add_option(
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)
154
155   if args:
156     print >> sys.stderr, 'Unused args %s' % args
157     return 1
158
159   ProvisionDevices(options)
160
161
162 if __name__ == '__main__':
163   sys.exit(main(sys.argv))