| OLD | NEW |
| 1 # Copyright 2014 The Chromium Authors. All rights reserved. | 1 # Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 import atexit | 5 import atexit |
| 6 import datetime | 6 import datetime |
| 7 import email.utils | 7 import email.utils |
| 8 import hashlib | 8 import hashlib |
| 9 import itertools | 9 import itertools |
| 10 import json | 10 import json |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 184 class AndroidShell(object): | 184 class AndroidShell(object): |
| 185 """ Allows to set up and run a given mojo shell binary on an Android device. | 185 """ Allows to set up and run a given mojo shell binary on an Android device. |
| 186 | 186 |
| 187 Args: | 187 Args: |
| 188 shell_apk_path: path to the shell Android binary | 188 shell_apk_path: path to the shell Android binary |
| 189 local_dir: directory where locally build Mojo apps will be served, optional | 189 local_dir: directory where locally build Mojo apps will be served, optional |
| 190 adb_path: path to adb, optional if adb is in PATH | 190 adb_path: path to adb, optional if adb is in PATH |
| 191 target_device: device to run on, if multiple devices are connected | 191 target_device: device to run on, if multiple devices are connected |
| 192 """ | 192 """ |
| 193 def __init__( | 193 def __init__( |
| 194 self, shell_apk_path, local_dir=None, adb_path="adb", target_device=None): | 194 self, shell_apk_path, local_dir=None, adb_path="adb", target_device=None, |
| 195 target_package=MOJO_SHELL_PACKAGE_NAME): |
| 195 self.shell_apk_path = shell_apk_path | 196 self.shell_apk_path = shell_apk_path |
| 196 self.adb_path = adb_path | 197 self.adb_path = adb_path |
| 197 self.local_dir = local_dir | 198 self.local_dir = local_dir |
| 198 self.target_device = target_device | 199 self.target_device = target_device |
| 200 self.target_package = target_package |
| 199 | 201 |
| 200 def _CreateADBCommand(self, args): | 202 def _CreateADBCommand(self, args): |
| 201 adb_command = [self.adb_path] | 203 adb_command = [self.adb_path] |
| 202 if self.target_device: | 204 if self.target_device: |
| 203 adb_command.extend(['-s', self.target_device]) | 205 adb_command.extend(['-s', self.target_device]) |
| 204 adb_command.extend(args) | 206 adb_command.extend(args) |
| 205 return adb_command | 207 return adb_command |
| 206 | 208 |
| 207 def _ReadFifo(self, fifo_path, pipe, on_fifo_closed, max_attempts=5): | 209 def _ReadFifo(self, fifo_path, pipe, on_fifo_closed, max_attempts=5): |
| 208 """ | 210 """ |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 318 """ Prepares for StartShell: runs adb as root and installs the apk. If no | 320 """ Prepares for StartShell: runs adb as root and installs the apk. If no |
| 319 --origin is specified, local http server will be set up to serve files from | 321 --origin is specified, local http server will be set up to serve files from |
| 320 the build directory along with port forwarding. | 322 the build directory along with port forwarding. |
| 321 | 323 |
| 322 Returns arguments that should be appended to shell argument list.""" | 324 Returns arguments that should be appended to shell argument list.""" |
| 323 if 'cannot run as root' in subprocess.check_output( | 325 if 'cannot run as root' in subprocess.check_output( |
| 324 self._CreateADBCommand(['root'])): | 326 self._CreateADBCommand(['root'])): |
| 325 raise Exception("Unable to run adb as root.") | 327 raise Exception("Unable to run adb as root.") |
| 326 subprocess.check_call( | 328 subprocess.check_call( |
| 327 self._CreateADBCommand(['install', '-r', self.shell_apk_path, '-i', | 329 self._CreateADBCommand(['install', '-r', self.shell_apk_path, '-i', |
| 328 MOJO_SHELL_PACKAGE_NAME])) | 330 self.target_package])) |
| 329 atexit.register(self.StopShell) | 331 atexit.register(self.StopShell) |
| 330 | 332 |
| 331 extra_shell_args = [] | 333 extra_shell_args = [] |
| 332 origin_url = origin if origin else self._StartHttpServerForDirectory( | 334 if origin: |
| 333 self.local_dir, DEFAULT_BASE_PORT if fixed_port else 0) | 335 origin_url = origin if origin else self._StartHttpServerForDirectory( |
| 334 extra_shell_args.append("--origin=" + origin_url) | 336 self.local_dir, DEFAULT_BASE_PORT if fixed_port else 0) |
| 337 extra_shell_args.append("--origin=" + origin_url) |
| 335 | 338 |
| 336 return extra_shell_args | 339 return extra_shell_args |
| 337 | 340 |
| 338 def StartShell(self, | 341 def StartShell(self, |
| 339 arguments, | 342 arguments, |
| 340 stdout=None, | 343 stdout=None, |
| 341 on_application_stop=None, | 344 on_application_stop=None, |
| 342 fixed_port=True): | 345 fixed_port=True): |
| 343 """ | 346 """ |
| 344 Starts the mojo shell, passing it the given arguments. | 347 Starts the mojo shell, passing it the given arguments. |
| 345 | 348 |
| 346 The |arguments| list must contain the "--origin=" arg from PrepareShellRun. | 349 The |arguments| list must contain the "--origin=" arg from PrepareShellRun. |
| 347 If |stdout| is not None, it should be a valid argument for subprocess.Popen. | 350 If |stdout| is not None, it should be a valid argument for subprocess.Popen. |
| 348 """ | 351 """ |
| 349 STDOUT_PIPE = "/data/data/%s/stdout.fifo" % MOJO_SHELL_PACKAGE_NAME | 352 STDOUT_PIPE = "/data/data/%s/stdout.fifo" % self.target_package |
| 350 | 353 |
| 351 cmd = self._CreateADBCommand([ | 354 cmd = self._CreateADBCommand([ |
| 352 'shell', | 355 'shell', |
| 353 'am', | 356 'am', |
| 354 'start', | 357 'start', |
| 355 '-S', | 358 '-S', |
| 356 '-a', 'android.intent.action.VIEW', | 359 '-a', 'android.intent.action.VIEW', |
| 357 '-n', '%s/.MojoShellActivity' % MOJO_SHELL_PACKAGE_NAME]) | 360 '-n', '%s/%s.MojoShellActivity' % (self.target_package, |
| 361 MOJO_SHELL_PACKAGE_NAME)]) |
| 358 | 362 |
| 359 parameters = [] | 363 parameters = [] |
| 360 if stdout or on_application_stop: | 364 if stdout or on_application_stop: |
| 361 subprocess.check_call(self._CreateADBCommand( | 365 subprocess.check_call(self._CreateADBCommand( |
| 362 ['shell', 'rm', STDOUT_PIPE])) | 366 ['shell', 'rm', '-f', STDOUT_PIPE])) |
| 363 parameters.append('--fifo-path=%s' % STDOUT_PIPE) | 367 parameters.append('--fifo-path=%s' % STDOUT_PIPE) |
| 364 self._ReadFifo(STDOUT_PIPE, stdout, on_application_stop) | 368 self._ReadFifo(STDOUT_PIPE, stdout, on_application_stop) |
| 365 # The origin has to be specified whether it's local or external. | |
| 366 assert any("--origin=" in arg for arg in arguments) | |
| 367 | 369 |
| 368 # Extract map-origin arguments. | 370 # Extract map-origin arguments. |
| 369 map_parameters, other_parameters = _Split(arguments, _IsMapOrigin) | 371 map_parameters, other_parameters = _Split(arguments, _IsMapOrigin) |
| 370 parameters += other_parameters | 372 parameters += other_parameters |
| 371 parameters += self._StartHttpServerForOriginMappings(map_parameters, | 373 parameters += self._StartHttpServerForOriginMappings(map_parameters, |
| 372 fixed_port) | 374 fixed_port) |
| 373 | 375 |
| 374 if parameters: | 376 if parameters: |
| 375 encodedParameters = json.dumps(parameters) | 377 encodedParameters = json.dumps(parameters) |
| 376 cmd += ['--es', 'encodedParameters', encodedParameters] | 378 cmd += ['--es', 'encodedParameters', encodedParameters] |
| 377 | 379 |
| 378 with open(os.devnull, 'w') as devnull: | 380 with open(os.devnull, 'w') as devnull: |
| 379 subprocess.Popen(cmd, stdout=devnull).wait() | 381 subprocess.Popen(cmd, stdout=devnull).wait() |
| 380 | 382 |
| 381 def StopShell(self): | 383 def StopShell(self): |
| 382 """ | 384 """ |
| 383 Stops the mojo shell. | 385 Stops the mojo shell. |
| 384 """ | 386 """ |
| 385 subprocess.check_call(self._CreateADBCommand(['shell', | 387 subprocess.check_call(self._CreateADBCommand(['shell', |
| 386 'am', | 388 'am', |
| 387 'force-stop', | 389 'force-stop', |
| 388 MOJO_SHELL_PACKAGE_NAME])) | 390 self.target_package])) |
| 389 | 391 |
| 390 def CleanLogs(self): | 392 def CleanLogs(self): |
| 391 """ | 393 """ |
| 392 Cleans the logs on the device. | 394 Cleans the logs on the device. |
| 393 """ | 395 """ |
| 394 subprocess.check_call(self._CreateADBCommand(['logcat', '-c'])) | 396 subprocess.check_call(self._CreateADBCommand(['logcat', '-c'])) |
| 395 | 397 |
| 396 def ShowLogs(self): | 398 def ShowLogs(self): |
| 397 """ | 399 """ |
| 398 Displays the log for the mojo shell. | 400 Displays the log for the mojo shell. |
| 399 | 401 |
| 400 Returns the process responsible for reading the logs. | 402 Returns the process responsible for reading the logs. |
| 401 """ | 403 """ |
| 402 logcat = subprocess.Popen(self._CreateADBCommand([ | 404 logcat = subprocess.Popen(self._CreateADBCommand([ |
| 403 'logcat', | 405 'logcat', |
| 404 '-s', | 406 '-s', |
| 405 ' '.join(LOGCAT_TAGS)]), | 407 ' '.join(LOGCAT_TAGS)]), |
| 406 stdout=sys.stdout) | 408 stdout=sys.stdout) |
| 407 atexit.register(_ExitIfNeeded, logcat) | 409 atexit.register(_ExitIfNeeded, logcat) |
| 408 return logcat | 410 return logcat |
| OLD | NEW |