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 |