Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright 2014 The Chromium Authors. All rights reserved. | 2 # Copyright 2014 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 from skypy.skyserver import SkyServer | 6 from skypy.skyserver import SkyServer |
| 7 import argparse | 7 import argparse |
| 8 import json | 8 import json |
| 9 import logging | 9 import logging |
| 10 import os | 10 import os |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 72 server_root = os.path.dirname(path) | 72 server_root = os.path.dirname(path) |
| 73 logging.warn( | 73 logging.warn( |
| 74 '%s is outside of mojo root, using %s as server root' % | 74 '%s is outside of mojo root, using %s as server root' % |
| 75 (path, server_root)) | 75 (path, server_root)) |
| 76 return server_root | 76 return server_root |
| 77 | 77 |
| 78 def _in_chromoting(self): | 78 def _in_chromoting(self): |
| 79 return os.environ.get('CHROME_REMOTE_DESKTOP_SESSION', False) | 79 return os.environ.get('CHROME_REMOTE_DESKTOP_SESSION', False) |
| 80 | 80 |
| 81 def _wrap_for_android(self, shell_args): | 81 def _wrap_for_android(self, shell_args): |
| 82 build_dir_url = SkyServer.url_for_path( | |
| 83 self.pids['remote_sky_server_port'], | |
| 84 self.pids['sky_server_root'], | |
| 85 self.pids['build_dir']) | |
| 86 shell_args += ['--origin=%s' % build_dir_url] | |
| 87 | |
| 88 # am shell --esa: (someone shoot me now) | 82 # am shell --esa: (someone shoot me now) |
| 89 # [--esa <EXTRA_KEY> <EXTRA_STRING_VALUE>[,<EXTRA_STRING_VALUE...]] | 83 # [--esa <EXTRA_KEY> <EXTRA_STRING_VALUE>[,<EXTRA_STRING_VALUE...]] |
| 90 # (to embed a comma into a string escape it using "\,") | 84 # (to embed a comma into a string escape it using "\,") |
| 91 escaped_args = map(lambda arg: arg.replace(',', '\\,'), shell_args) | 85 escaped_args = map(lambda arg: arg.replace(',', '\\,'), shell_args) |
| 92 return [ | 86 return [ |
| 93 'adb', 'shell', | 87 'adb', 'shell', |
| 94 'am', 'start', | 88 'am', 'start', |
| 95 '-W', | 89 '-W', |
| 96 '-S', | 90 '-S', |
| 97 '-a', 'android.intent.action.VIEW', | 91 '-a', 'android.intent.action.VIEW', |
| 98 '-n', ANDROID_ACTIVITY, | 92 '-n', ANDROID_ACTIVITY, |
| 99 # FIXME: This quoting is very error-prone. Perhaps we should read | 93 # FIXME: This quoting is very error-prone. Perhaps we should read |
| 100 # our args from a file instead? | 94 # our args from a file instead? |
| 101 '--esa', 'parameters', ','.join(escaped_args), | 95 '--esa', 'parameters', ','.join(escaped_args), |
| 102 ] | 96 ] |
| 103 | 97 |
| 104 def _build_mojo_shell_command(self, args, is_android): | 98 def _build_mojo_shell_command(self, args, is_android): |
| 105 content_handlers = ['%s,%s' % (mime_type, 'mojo:sky_viewer') | 99 content_handlers = ['%s,%s' % (mime_type, 'mojo:sky_viewer') |
| 106 for mime_type in SUPPORTED_MIME_TYPES] | 100 for mime_type in SUPPORTED_MIME_TYPES] |
| 107 | 101 |
| 108 remote_command_port = self.pids.get('remote_sky_command_port', self.pids ['sky_command_port']) | 102 remote_command_port = self.pids.get('remote_sky_command_port', self.pids ['sky_command_port']) |
| 103 remote_server_port = self.pids.get('remote_sky_server_port', self.pids[' sky_server_port']) | |
| 109 | 104 |
| 110 shell_args = [ | 105 shell_args = [ |
| 111 '--v=1', | 106 '--v=1', |
| 112 '--content-handlers=%s' % ','.join(content_handlers), | 107 '--content-handlers=%s' % ','.join(content_handlers), |
| 113 '--url-mappings=mojo:window_manager=mojo:sky_debugger', | 108 '--url-mappings=mojo:window_manager=mojo:sky_debugger', |
| 114 '--args-for=mojo:sky_debugger_prompt %d' % remote_command_port, | 109 '--args-for=mojo:sky_debugger_prompt %d' % remote_command_port, |
| 115 'mojo:window_manager', | 110 'mojo:window_manager', |
| 116 ] | 111 ] |
| 117 | 112 |
| 113 # Map all mojo: urls to http: urls using the --origin command. | |
| 114 build_dir_url = SkyServer.url_for_path( | |
| 115 remote_server_port, | |
| 116 self.pids['sky_server_root'], | |
| 117 self.pids['build_dir']) | |
| 118 shell_args += ['--origin=%s' % build_dir_url] | |
| 119 | |
| 118 # Desktop-only work-around for mojo crashing under chromoting. | 120 # Desktop-only work-around for mojo crashing under chromoting. |
| 119 if not is_android and args.use_osmesa: | 121 if not is_android and args.use_osmesa: |
| 120 shell_args.append( | 122 shell_args.append( |
| 121 '--args-for=mojo:native_viewport_service --use-osmesa') | 123 '--args-for=mojo:native_viewport_service --use-osmesa') |
| 122 | 124 |
| 123 if is_android and args.gdb: | 125 if is_android and args.gdb: |
| 124 shell_args.append('--wait_for_debugger') | 126 shell_args.append('--wait_for_debugger') |
| 125 | 127 |
| 126 if 'remote_sky_server_port' in self.pids: | 128 if 'remote_sky_server_port' in self.pids: |
| 127 shell_command = self._wrap_for_android(shell_args) | 129 shell_command = self._wrap_for_android(shell_args) |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 315 if not urlparse.urlparse(args.url_or_path).scheme: | 317 if not urlparse.urlparse(args.url_or_path).scheme: |
| 316 # The load happens on the remote device, use the remote port. | 318 # The load happens on the remote device, use the remote port. |
| 317 remote_sky_server_port = self.pids.get('remote_sky_server_port', | 319 remote_sky_server_port = self.pids.get('remote_sky_server_port', |
| 318 self.pids['sky_server_port']) | 320 self.pids['sky_server_port']) |
| 319 url = SkyServer.url_for_path(remote_sky_server_port, | 321 url = SkyServer.url_for_path(remote_sky_server_port, |
| 320 self.pids['sky_server_root'], args.url_or_path) | 322 self.pids['sky_server_root'], args.url_or_path) |
| 321 else: | 323 else: |
| 322 url = args.url_or_path | 324 url = args.url_or_path |
| 323 self._send_command_to_sky('/load', url) | 325 self._send_command_to_sky('/load', url) |
| 324 | 326 |
| 327 def _read_mojo_map(self): | |
| 328 # TODO(eseidel): Does not work for android. | |
| 329 mojo_map_path = "/tmp/mojo_shell.%d.maps" % self.pids['mojo_shell_pid'] | |
| 330 with open(mojo_map_path, 'r') as maps_file: | |
| 331 lines = maps_file.read().strip().split('\n') | |
| 332 return dict(map(lambda line: line.split(' '), lines)) | |
| 333 | |
| 325 def stop_profiling_command(self, args): | 334 def stop_profiling_command(self, args): |
| 326 self._send_command_to_sky('/stop_profiling') | 335 self._send_command_to_sky('/stop_profiling') |
| 336 mojo_map = self._read_mojo_map() | |
| 337 | |
| 338 # TODO(eseidel): We should have a helper for resolving urls, etc. | |
| 339 remote_server_port = self.pids.get('remote_sky_server_port', self.pids[' sky_server_port']) | |
| 340 build_dir_url = SkyServer.url_for_path( | |
| 341 remote_server_port, | |
| 342 self.pids['sky_server_root'], | |
| 343 self.pids['build_dir']) | |
| 344 | |
| 327 # We need to munge the profile to replace foo.mojo with libfoo.so so | 345 # We need to munge the profile to replace foo.mojo with libfoo.so so |
| 328 # that pprof knows this represents an SO. | 346 # that pprof knows this represents an SO. |
| 329 with open("sky_viewer.pprof", "r+") as profile_file: | 347 def map_to_local_paths(match): |
| 330 data = profile_file.read() | 348 path = match.group('mojo_path') |
| 349 url = mojo_map.get(path) | |
| 350 if url and url.startswith(build_dir_url): | |
| 351 return url.replace(build_dir_url, self.pids['build_dir']) | |
| 352 return match.group(0) | |
| 353 | |
| 354 MOJO_PATH_RE = re.compile(r'(?P<mojo_path>\S+\.mojo)') | |
| 355 MOJO_NAME_RE = re.compile(r'(?P<mojo_name>\w+)\.mojo') | |
| 356 | |
| 357 with open("sky_viewer.pprof", "rb+") as profile_file: | |
| 358 as_string = profile_file.read().decode('iso-8859-1') | |
|
abarth-chromium
2015/01/21 22:18:49
You should comment on why this encoding
eseidel
2015/01/21 22:44:43
Done.
| |
| 359 # Using the mojo_shell.PID.maps file tmp paths to build_dir paths. | |
| 360 as_string = MOJO_PATH_RE.sub(map_to_local_paths, as_string) | |
| 361 # In android release builds only the lib* variants have symbols: | |
| 362 as_string = MOJO_NAME_RE.sub(r'lib\1_library.so', as_string) | |
| 331 profile_file.seek(0) | 363 profile_file.seek(0) |
| 332 profile_file.write(re.sub(r'(\w+)\.mojo', r'lib\1_library.so', data) ) | 364 profile_file.write(as_string.encode('iso-8859-1')) |
| 333 profile_file.truncate() | 365 profile_file.truncate() |
| 334 | 366 |
| 335 def _command_base_url(self): | 367 def _command_base_url(self): |
| 336 return 'http://localhost:%s' % self.pids['sky_command_port'] | 368 return 'http://localhost:%s' % self.pids['sky_command_port'] |
| 337 | 369 |
| 338 def _send_command_to_sky(self, command_path, payload=None): | 370 def _send_command_to_sky(self, command_path, payload=None): |
| 339 url = 'http://localhost:%s%s' % ( | 371 url = 'http://localhost:%s%s' % ( |
| 340 self.pids['sky_command_port'], command_path) | 372 self.pids['sky_command_port'], command_path) |
| 341 if payload: | 373 if payload: |
| 342 response = requests.post(url, payload) | 374 response = requests.post(url, payload) |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 480 def print_crash_command(self, args): | 512 def print_crash_command(self, args): |
| 481 logcat_cmd = ['adb', 'logcat', '-d'] | 513 logcat_cmd = ['adb', 'logcat', '-d'] |
| 482 logcat = subprocess.Popen(logcat_cmd, stdout=subprocess.PIPE) | 514 logcat = subprocess.Popen(logcat_cmd, stdout=subprocess.PIPE) |
| 483 | 515 |
| 484 stack_path = os.path.join(SRC_ROOT, | 516 stack_path = os.path.join(SRC_ROOT, |
| 485 'tools', 'android_stack_parser', 'stack') | 517 'tools', 'android_stack_parser', 'stack') |
| 486 stack = subprocess.Popen([stack_path, '-'], stdin=logcat.stdout) | 518 stack = subprocess.Popen([stack_path, '-'], stdin=logcat.stdout) |
| 487 logcat.wait() | 519 logcat.wait() |
| 488 stack.wait() | 520 stack.wait() |
| 489 | 521 |
| 522 def pids_command(self, args): | |
| 523 print json.dumps(self.pids, indent=1) | |
| 524 | |
| 490 def main(self): | 525 def main(self): |
| 491 logging.basicConfig(level=logging.WARNING) | 526 logging.basicConfig(level=logging.WARNING) |
| 492 logging.getLogger("requests").setLevel(logging.WARNING) | 527 logging.getLogger("requests").setLevel(logging.WARNING) |
| 493 | 528 |
| 494 self.pids = self._load_pid_file(PID_FILE_PATH) | 529 self.pids = self._load_pid_file(PID_FILE_PATH) |
| 495 | 530 |
| 496 parser = argparse.ArgumentParser(description='Sky launcher/debugger') | 531 parser = argparse.ArgumentParser(description='Sky launcher/debugger') |
| 497 subparsers = parser.add_subparsers(help='sub-command help') | 532 subparsers = parser.add_subparsers(help='sub-command help') |
| 498 | 533 |
| 499 start_parser = subparsers.add_parser('start', | 534 start_parser = subparsers.add_parser('start', |
| 500 help='launch a new mojo_shell with sky') | 535 help='launch a new mojo_shell with sky') |
| 501 start_parser.add_argument('--gdb', action='store_true') | 536 start_parser.add_argument('--gdb', action='store_true') |
| 502 start_parser.add_argument('--command-port', type=int, | 537 start_parser.add_argument('--command-port', type=int, |
| 503 default=DEFAULT_SKY_COMMAND_PORT) | 538 default=DEFAULT_SKY_COMMAND_PORT) |
| 504 start_parser.add_argument('--use-osmesa', action='store_true', | 539 start_parser.add_argument('--use-osmesa', action='store_true', |
| 505 default=self._in_chromoting()) | 540 default=self._in_chromoting()) |
| 506 start_parser.add_argument('build_dir', type=str) | 541 start_parser.add_argument('build_dir', type=str) |
| 507 start_parser.add_argument('url_or_path', nargs='?', type=str, | 542 start_parser.add_argument('url_or_path', nargs='?', type=str, |
| 508 default=DEFAULT_URL) | 543 default=DEFAULT_URL) |
| 509 start_parser.add_argument('--show-command', action='store_true', | 544 start_parser.add_argument('--show-command', action='store_true', |
| 510 help='Display the shell command and exit') | 545 help='Display the shell command and exit') |
| 511 start_parser.set_defaults(func=self.start_command) | 546 start_parser.set_defaults(func=self.start_command) |
| 512 | 547 |
| 513 stop_parser = subparsers.add_parser('stop', | 548 stop_parser = subparsers.add_parser('stop', |
| 514 help=('stop sky (as listed in %s)' % PID_FILE_PATH)) | 549 help=('stop sky (as listed in %s)' % PID_FILE_PATH)) |
| 515 stop_parser.set_defaults(func=self.stop_command) | 550 stop_parser.set_defaults(func=self.stop_command) |
| 516 | 551 |
| 552 pids_parser = subparsers.add_parser('pids', | |
| 553 help='dump the current skydb pids file') | |
| 554 pids_parser.set_defaults(func=self.pids_command) | |
| 555 | |
| 517 logcat_parser = subparsers.add_parser('logcat', | 556 logcat_parser = subparsers.add_parser('logcat', |
| 518 help=('dump sky-related logs from device')) | 557 help=('dump sky-related logs from device')) |
| 519 logcat_parser.set_defaults(func=self.logcat_command) | 558 logcat_parser.set_defaults(func=self.logcat_command) |
| 520 | 559 |
| 521 print_crash_parser = subparsers.add_parser('print_crash', | 560 print_crash_parser = subparsers.add_parser('print_crash', |
| 522 help=('dump (and symbolicate) recent crash-stacks')) | 561 help=('dump (and symbolicate) recent crash-stacks')) |
| 523 print_crash_parser.set_defaults(func=self.print_crash_command) | 562 print_crash_parser.set_defaults(func=self.print_crash_command) |
| 524 | 563 |
| 525 gdb_attach_parser = subparsers.add_parser('gdb_attach', | 564 gdb_attach_parser = subparsers.add_parser('gdb_attach', |
| 526 help='launch gdb and attach to gdbserver launched from start --gdb') | 565 help='launch gdb and attach to gdbserver launched from start --gdb') |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 545 load_parser.set_defaults(func=self.load_command) | 584 load_parser.set_defaults(func=self.load_command) |
| 546 | 585 |
| 547 args = parser.parse_args() | 586 args = parser.parse_args() |
| 548 args.func(args) | 587 args.func(args) |
| 549 | 588 |
| 550 self._write_pid_file(PID_FILE_PATH, self.pids) | 589 self._write_pid_file(PID_FILE_PATH, self.pids) |
| 551 | 590 |
| 552 | 591 |
| 553 if __name__ == '__main__': | 592 if __name__ == '__main__': |
| 554 SkyDebugger().main() | 593 SkyDebugger().main() |
| OLD | NEW |