Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(194)

Side by Side Diff: runtime/tools/android_finder.py

Issue 10823209: Add support for building the Dart VM for Android OS. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: build.py learned --os all option to build for both host and android. Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | runtime/tools/create_snapshot_bin.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #!/usr/bin/env python
2
3 # Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
4 # for details. All rights reserved. Use of this source code is governed by a
5 # BSD-style license that can be found in the LICENSE file.
6
7 """
8 Find an Android device with a given ABI
ahe 2012/08/30 10:24:10 Missing period.
jackpal 2012/08/30 18:25:20 Done.
9
10 The name of the Android device is printed to stdout
ahe 2012/08/30 10:24:10 Missing period.
jackpal 2012/08/30 18:25:20 Done.
11
12 Optionally configure and launch an emulator if there's no existing device for a
13 given ABI. Will download and install Android SDK components as needed.
14 """
15
16 import optparse
17 import os
18 import re
19 import sys
20 import traceback
21 import utils
22
23
24 DEBUG = False
25 VERBOSE = False
26
27
28 def BuildOptions():
29 result = optparse.OptionParser()
30 result.add_option(
31 "-a", "--abi",
32 action="store", type="string",
33 help="Desired ABI. armeabi-v7a or x86")
ahe 2012/08/30 10:24:10 Missing period.
jackpal 2012/08/30 18:25:20 Done.
34 result.add_option(
35 "-b", "--bootstrap",
36 help='Bootstrap - create an emulator, installing SDK packages if needed.',
37 default=False, action="store_true")
38 result.add_option(
39 "-d", "--debug",
40 help='Turn on debugging diagnostics.',
41 default=False, action="store_true")
42 result.add_option(
43 "-v", "--verbose",
44 help='Verbose output.',
45 default=False, action="store_true")
46 return result
47
48
49 def ProcessOptions(options):
50 global DEBUG
51 DEBUG = options.debug
52 global VERBOSE
53 VERBOSE = options.verbose
54 if options.abi is None:
55 sys.stderr.write('--abi not specified\n')
ahe 2012/08/30 10:24:10 Missing period.
ahe 2012/08/30 10:24:10 FYI: I just discovered this alternative: print >>
jackpal 2012/08/30 18:25:20 Interesting! I read on stack overflow that one ben
56 return False
57 return True
58
59
60 def ParseAndroidListSdkResult(text):
61 """
62 Parse the output of an 'android list sdk' command.
63
64 Return list of (id-num, id-key, type, description)
ahe 2012/08/30 10:24:10 Missing period.
jackpal 2012/08/30 18:25:20 Done.
65 """
66 header_regex = re.compile(
67 r'Packages available for installation or update: \d+\n')
68 packages = re.split(header_regex, text)
69 if len(packages) != 2:
70 raise Exception("Could not get a list of packages to install")
71 entry_regex = re.compile(
72 r'^id\: (\d+) or "([^"]*)"\n\s*Type\: ([^\n]*)\n\s*Desc\: (.*)')
73 entries = []
74 for entry in packages[1].split('----------\n'):
75 match = entry_regex.match(entry)
76 if match == None:
77 continue
78 entries.append((int(match.group(1)), match.group(2), match.group(3),
79 match.group(4)))
80 return entries
81
82
83 def AndroidListSdk():
84 return ParseAndroidListSdkResult(utils.RunCommand(
85 ["android", "list", "sdk", "-a", "-e"]))
ahe 2012/08/30 10:24:10 I assume you already checked that there is no "mac
jackpal 2012/08/30 18:25:20 Yeah, unfortunately the "android" tool wasn't desi
86
87
88 def AndroidSdkFindPackage(packages, key):
89 """key is (id-key, type, description-prefix)"""
ahe 2012/08/30 10:24:10 If you want symbolic names instead of indexing, I
jackpal 2012/08/30 18:25:20 Done.
90 for package in packages:
ahe 2012/08/30 10:24:10 And here I think you can write this: for (i, t, d
jackpal 2012/08/30 18:25:20 Well, I want to return the package in line 93, so
91 if (package[1] == key[0] and package[2] == key[1]
92 and package[3].find(key[2]) == 0):
93 return package
94 return None
95
96
97 def EnsureSdkPackageInstalled(packages, key):
98 """
99 Makes sure the package with a given key is installed.
100
101 key is (id-key, type, description-prefix)
102
103 Returns True if the package was not already installed.
104 """
105 entry = AndroidSdkFindPackage(packages, key)
106 if entry is None:
107 raise Exception("Could not find a package for key %s" % key)
108 packageId = entry[0]
109 if VERBOSE:
110 sys.stderr.write('Checking Android SDK package %s...\n' % str(entry))
ahe 2012/08/30 10:24:10 Why is verbose output written to stderr?
jackpal 2012/08/30 18:25:20 To avoid polluting stdout, which is where we retur
111 out = utils.RunCommand(
112 ["android", "update", "sdk", "-a", "-u", "--filter", str(packageId)])
113 return out.find('\nInstalling Archives:\n') >= 0
ahe 2012/08/30 10:24:10 return '\nInstalling Archives:\n' in out
jackpal 2012/08/30 18:25:20 Sweet!
114
115
116 def SdkPackagesForAbi(abi):
117 packagesForAbi = {
118 'armeabi-v7a': [
119 # The platform needed to install the armeabi ABI system image:
120 ('android-15', 'Platform', 'Android SDK Platform 4.0.3'),
121 # The armeabi-v7a ABI system image:
122 ('sysimg-15', 'SystemImage', 'Android SDK Platform 4.0.3')
123 ],
124 'x86': [
125 # The platform needed to install the x86 ABI system image:
126 ('android-15', 'Platform', 'Android SDK Platform 4.0.3'),
127 # The x86 ABI system image:
128 ('sysimg-15', 'SystemImage', 'Android SDK Platform 4.0.4')
129 ]
130 }
131
132 if abi not in packagesForAbi:
133 raise Exception('Unsupported abi %s' % abi)
134 return packagesForAbi[abi]
135
136
137 def TargetForAbi(abi):
138 for package in SdkPackagesForAbi(abi):
139 if package[1] == 'Platform':
140 return package[0]
141
ahe 2012/08/30 10:24:10 Missing newline.
jackpal 2012/08/30 18:25:20 Done.
142 def EnsureAndroidSdkPackagesInstalled(abi):
143 """Return true if at least one package was not already installed."""
144 abiPackageList = SdkPackagesForAbi(abi)
145 installedSomething = False
146 packages = AndroidListSdk()
147 for package in abiPackageList:
148 installedSomething |= EnsureSdkPackageInstalled(packages, package)
149 return installedSomething
150
151
152 def ParseAndroidListAvdResult(text):
153 """
154 Parse the output of an 'android list avd' command.
155 Return List of {Name: Path: Target: ABI: Skin: Sdcard:}
156 """
157 text = text.split('Available Android Virtual Devices:\n')[-1]
158 text = text.split(
159 'The following Android Virtual Devices could not be loaded:\n')[0]
160 result = []
161 line_re = re.compile(r'^\s*([^\:]+)\:\s*(.*)$')
162 for chunk in text.split('\n---------\n'):
163 entry = {}
164 for line in chunk.split('\n'):
165 line = line.strip()
166 if len(line) == 0:
167 continue
168 match = line_re.match(line)
169 if match is None:
170 raise Exception('Match failed')
171 entry[match.group(1)] = match.group(2)
172 if len(entry) > 0:
173 result.append(entry)
174 return result
175
176
177 def AndroidListAvd():
178 """Returns a list of available Android Virtual Devices."""
179 return ParseAndroidListAvdResult(utils.RunCommand(["android", "list", "avd"]))
180
181
182 def FindAvd(avds, key):
183 for avd in avds:
184 if avd['Name'] == key:
185 return avd
186 return None
187
188
189 def CreateAvd(avdName, abi):
190 out = utils.RunCommand(["android", "create", "avd", "--name", avdName,
191 "--target", TargetForAbi(abi), '--abi', abi],
192 input="no\n")
193 if out.find('Created AVD ') < 0:
194 if VERBOSE:
195 sys.stderr.write('Could not create AVD:\n%s\n' % out)
196 raise Exception('Could not create AVD')
197
198
199 def AvdExists(avdName):
200 avdList = AndroidListAvd()
201 return FindAvd(avdList, avdName) is not None
202
203
204 def EnsureAvdExists(avdName, abi):
205 if AvdExists(avdName):
206 return
207 if VERBOSE:
208 sys.stderr.write('Checking SDK packages...\n')
209 if EnsureAndroidSdkPackagesInstalled(abi):
210 # Installing a new package could have made a previously invalid AVD valid
211 if AvdExists(avdName):
212 return
213 CreateAvd(avdName, abi)
214
ahe 2012/08/30 10:24:10 Missing newline.
215 def dumpenv(map):
ahe 2012/08/30 10:24:10 Inconsistent name.
jackpal 2012/08/30 18:25:20 Oops! - this is unused debugging code, I'll remove
216 e = map.keys()
217 e.sort()
218 for k in e:
219 sys.stderr.write("%s: %s\n" % (k, map[k]))
220
221
222 def StartEmulator(abi, avdName, pollFn):
223 """
224 Start an emulator for a given abi and svdName.
225
226 Echo the emulator's stderr and stdout output to our stderr.
227
228 Call pollFn repeatedly until it returns False. Leave the emulator running
229 when we return.
230
231 Implementation note: Normally we would call the 'emulator' binary, which
232 is a wrapper that launches the appropriate abi-specific emulator. But there
233 is a bug that causes the emulator to exit immediately with a result code of
234 -11 if run from a ssh shell or a NX Machine shell. (And only if called from
235 three levels of nested python scripts.) Calling the ABI-specific versions
236 of the emulator directly works around this bug.
237 """
238 emulatorName = {'x86' : 'emulator-x86', 'armeabi-v7a': 'emulator-arm'}[abi]
239 command = [emulatorName, '-avd', avdName, '-no-boot-anim', '-no-window']
240 utils.RunCommand(command, pollFn=pollFn, killOnEarlyReturn=False,
241 outStream=sys.stderr, errStream=sys.stderr)
242
243
244 def ParseAndroidDevices(text):
245 """Return Dictionary [name] -> status"""
246 text = text.split('List of devices attached')[-1]
247 lines = [line.strip() for line in text.split('\n')]
248 lines = [line for line in lines if len(line) > 0]
249 devices = {}
250 for line in lines:
251 lineItems = line.split('\t')
252 devices[lineItems[0]] = lineItems[1]
253 return devices
254
255
256 def GetAndroidDevices():
257 return ParseAndroidDevices(utils.RunCommand(["adb", "devices"]))
258
259
260 def FilterOfflineDevices(devices):
261 online = {}
262 for device in devices.keys():
263 status = devices[device]
264 if status != 'offline':
265 online[device] = status
266 return online
267
268
269 def GetOnlineAndroidDevices():
270 return FilterOfflineDevices(GetAndroidDevices())
271
272
273 def GetAndroidDeviceProperty(device, property):
274 return utils.RunCommand(
275 ["adb", "-s", device, "shell", "getprop", property]).strip()
276
277
278 def GetAndroidDeviceAbis(device):
279 abis = []
280 for property in ['ro.product.cpu.abi', 'ro.product.cpu.abi2']:
281 out = GetAndroidDeviceProperty(device, property)
282 if len(out) > 0:
283 abis.append(out)
284 return abis
285
286
287 def FindAndroidRunning(abi):
288 for device in GetOnlineAndroidDevices().keys():
289 if abi in GetAndroidDeviceAbis(device):
290 return device
291 return None
292
293
294 def AddSdkToolsToPath():
295 script_dir = os.path.dirname(sys.argv[0])
296 dart_root = os.path.realpath(os.path.join(script_dir, '..', '..'))
297 third_party_root = os.path.join(dart_root, 'third_party')
298 android_tools = os.path.join(third_party_root, 'android_tools')
299 android_sdk_root = os.path.join(android_tools, 'sdk')
300 android_sdk_tools = os.path.join(android_sdk_root, 'tools')
301 android_sdk_platform_tools = os.path.join(android_sdk_root, 'platform-tools')
302 os.environ['PATH'] = ':'.join([
303 os.environ['PATH'], android_sdk_tools, android_sdk_platform_tools])
304 # Remove any environment variables that would affect our build.
305 for i in ['ANDROID_NDK_ROOT', 'ANDROID_SDK_ROOT', 'ANDROID_TOOLCHAIN',
306 'AR', 'BUILDTYPE', 'CC', 'CXX', 'GYP_DEFINES',
307 'LD_LIBRARY_PATH', 'LINK', 'MAKEFLAGS', 'MAKELEVEL',
308 'MAKEOVERRIDES', 'MFLAGS', 'NM']:
309 if i in os.environ:
310 del os.environ[i]
311
ahe 2012/08/30 10:24:10 Missing newline.
jackpal 2012/08/30 18:25:20 Done.
312 def FindAndroid(abi, bootstrap):
313 if VERBOSE:
314 sys.stderr.write('Looking for an Android device running abi %s...\n' % abi)
315 AddSdkToolsToPath()
316 device = FindAndroidRunning(abi)
317 if device is None:
ahe 2012/08/30 10:24:10 if not device:
jackpal 2012/08/30 18:25:20 Done.
318 if bootstrap:
319 if VERBOSE:
320 sys.stderr.write("No emulator found, try to create one.\n")
321 avdName = 'dart-build-%s' % abi
322 EnsureAvdExists(avdName, abi)
323
324 # It takes a while to start up an emulator.
325 # Provide feedback while we wait.
326 pollResult = [None]
327 def pollFunction():
328 if VERBOSE:
329 sys.stderr.write('.')
330 pollResult[0] = FindAndroidRunning(abi)
331 # Stop polling once we have our result.
332 return pollResult[0] != None
333 StartEmulator(abi, avdName, pollFunction)
334 device = pollResult[0]
335 return device
336
337
338 def Main():
339 # Parse options.
340 parser = BuildOptions()
341 (options, args) = parser.parse_args()
342 if not ProcessOptions(options):
343 parser.print_help()
344 return 1
345
346 # If there are additional arguments, report error and exit.
347 if args:
348 parser.print_help()
349 return 1
350
351 try:
352 device = FindAndroid(options.abi, options.bootstrap)
353 if device != None:
354 sys.stdout.write("%s\n" % device)
355 return 0
356 else:
357 if VERBOSE:
358 sys.stderr.write('Could not find device\n')
359 return 2
360 except Exception as e:
ahe 2012/08/30 10:24:10 I think this is problematic. It also catches, for
jackpal 2012/08/30 18:25:20 Done.
361 sys.stderr.write("error: %s\n" % e)
362 if DEBUG:
363 traceback.print_exc(file=sys.stderr)
364 return -1
365
366
367 if __name__ == '__main__':
368 sys.exit(Main())
OLDNEW
« no previous file with comments | « no previous file | runtime/tools/create_snapshot_bin.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698