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 22 matching lines...) Expand all Loading... |
33 ] | 33 ] |
34 | 34 |
35 DEFAULT_SKY_COMMAND_PORT = 7777 | 35 DEFAULT_SKY_COMMAND_PORT = 7777 |
36 GDB_PORT = 8888 | 36 GDB_PORT = 8888 |
37 SKY_SERVER_PORT = 9999 | 37 SKY_SERVER_PORT = 9999 |
38 PID_FILE_PATH = "/tmp/skydb.pids" | 38 PID_FILE_PATH = "/tmp/skydb.pids" |
39 DEFAULT_URL = "https://raw.githubusercontent.com/domokit/mojo/master/sky/example
s/home.sky" | 39 DEFAULT_URL = "https://raw.githubusercontent.com/domokit/mojo/master/sky/example
s/home.sky" |
40 | 40 |
41 ANDROID_PACKAGE = "org.chromium.mojo.shell" | 41 ANDROID_PACKAGE = "org.chromium.mojo.shell" |
42 ANDROID_ACTIVITY = "%s/.MojoShellActivity" % ANDROID_PACKAGE | 42 ANDROID_ACTIVITY = "%s/.MojoShellActivity" % ANDROID_PACKAGE |
| 43 ANDROID_APK_NAME = 'MojoShell.apk' |
43 CACHE_LINKS_PATH = '/tmp/mojo_cache_links' | 44 CACHE_LINKS_PATH = '/tmp/mojo_cache_links' |
44 SYSTEM_LIBS_ROOT_PATH = '/tmp/device_libs' | 45 SYSTEM_LIBS_ROOT_PATH = '/tmp/device_libs' |
45 | 46 |
46 | 47 |
47 # FIXME: Move this into mopy.config | 48 # FIXME: Move this into mopy.config |
48 def gn_args_from_build_dir(build_dir): | 49 def gn_args_from_build_dir(build_dir): |
49 gn_cmd = [ | 50 gn_cmd = [ |
50 'gn', 'args', | 51 'gn', 'args', |
51 build_dir, | 52 build_dir, |
52 '--list', '--short' | 53 '--list', '--short' |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
188 self.pids['sky_server_port'] = sky_server.port | 189 self.pids['sky_server_port'] = sky_server.port |
189 self.pids['sky_server_root'] = sky_server.root | 190 self.pids['sky_server_root'] = sky_server.root |
190 | 191 |
191 self.pids['build_dir'] = self.paths.build_dir | 192 self.pids['build_dir'] = self.paths.build_dir |
192 self.pids['sky_command_port'] = args.command_port | 193 self.pids['sky_command_port'] = args.command_port |
193 | 194 |
194 if is_android: | 195 if is_android: |
195 # Pray to the build/android gods in their misspelled tongue. | 196 # Pray to the build/android gods in their misspelled tongue. |
196 constants.SetOutputDirectort(self.paths.build_dir) | 197 constants.SetOutputDirectort(self.paths.build_dir) |
197 | 198 |
| 199 # We could make installing conditional on an argument. |
| 200 apk_path = os.path.join(self.paths.build_dir, 'apks', |
| 201 ANDROID_APK_NAME) |
| 202 subprocess.check_call(['adb', 'install', '-r', apk_path]) |
| 203 |
198 device = self._connect_to_device() | 204 device = self._connect_to_device() |
199 self.pids['device_serial'] = device.GetDevice() | 205 self.pids['device_serial'] = device.GetDevice() |
200 | 206 |
201 forwarder.Forwarder.Map([(0, sky_server.port)], device) | 207 forwarder.Forwarder.Map([(0, sky_server.port)], device) |
202 device_http_port = forwarder.Forwarder.DevicePortForHostPort( | 208 device_http_port = forwarder.Forwarder.DevicePortForHostPort( |
203 sky_server.port) | 209 sky_server.port) |
204 self.pids['remote_sky_server_port'] = device_http_port | 210 self.pids['remote_sky_server_port'] = device_http_port |
205 | 211 |
206 port_string = 'tcp:%s' % args.command_port | 212 port_string = 'tcp:%s' % args.command_port |
207 subprocess.check_call([ | 213 subprocess.check_call([ |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
304 self._kill_if_exists('mojo_shell_pid', 'mojo_shell') | 310 self._kill_if_exists('mojo_shell_pid', 'mojo_shell') |
305 | 311 |
306 if 'remote_gdbserver_port' in self.pids: | 312 if 'remote_gdbserver_port' in self.pids: |
307 self._kill_if_exists('adb_shell_gdbserver_pid', | 313 self._kill_if_exists('adb_shell_gdbserver_pid', |
308 'adb shell gdbserver') | 314 'adb shell gdbserver') |
309 | 315 |
310 port_string = 'tcp:%s' % self.pids['remote_gdbserver_port'] | 316 port_string = 'tcp:%s' % self.pids['remote_gdbserver_port'] |
311 subprocess.call(['adb', 'forward', '--remove', port_string]) | 317 subprocess.call(['adb', 'forward', '--remove', port_string]) |
312 self.pids = {} # Clear out our pid file. | 318 self.pids = {} # Clear out our pid file. |
313 | 319 |
314 self._kill_if_exists('mojo_cache_linker_pid', 'mojo cache linker') | |
315 | |
316 def load_command(self, args): | 320 def load_command(self, args): |
317 if not urlparse.urlparse(args.url_or_path).scheme: | 321 if not urlparse.urlparse(args.url_or_path).scheme: |
318 # The load happens on the remote device, use the remote port. | 322 # The load happens on the remote device, use the remote port. |
319 remote_sky_server_port = self.pids.get('remote_sky_server_port', | 323 remote_sky_server_port = self.pids.get('remote_sky_server_port', |
320 self.pids['sky_server_port']) | 324 self.pids['sky_server_port']) |
321 url = SkyServer.url_for_path(remote_sky_server_port, | 325 url = SkyServer.url_for_path(remote_sky_server_port, |
322 self.pids['sky_server_root'], args.url_or_path) | 326 self.pids['sky_server_root'], args.url_or_path) |
323 else: | 327 else: |
324 url = args.url_or_path | 328 url = args.url_or_path |
325 self._send_command_to_sky('/load', url) | 329 self._send_command_to_sky('/load', url) |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
418 def logcat_command(self, args): | 422 def logcat_command(self, args): |
419 TAGS = [ | 423 TAGS = [ |
420 'AndroidHandler', | 424 'AndroidHandler', |
421 'MojoMain', | 425 'MojoMain', |
422 'MojoShellActivity', | 426 'MojoShellActivity', |
423 'MojoShellApplication', | 427 'MojoShellApplication', |
424 'chromium', | 428 'chromium', |
425 ] | 429 ] |
426 subprocess.call(['adb', 'logcat', '-d', '-s'] + TAGS) | 430 subprocess.call(['adb', 'logcat', '-d', '-s'] + TAGS) |
427 | 431 |
428 def _start_mojo_cache_linker(self, links_path): | |
429 self._kill_if_exists('mojo_cache_linker_pid', 'mojo cache linker') | |
430 | |
431 if not os.path.exists(links_path): | |
432 os.makedirs(links_path) | |
433 shell_link_path = os.path.join(links_path, 'libmojo_shell.so') | |
434 if os.path.lexists(shell_link_path): | |
435 os.unlink(shell_link_path) | |
436 os.symlink(self.paths.mojo_shell_path, shell_link_path) | |
437 | |
438 logcat_cmd = ['adb', 'logcat'] | |
439 logcat = subprocess.Popen(logcat_cmd, stdout=subprocess.PIPE) | |
440 | |
441 mojo_cache_linker_path = os.path.join( | |
442 self.paths.sky_tools_directory, 'mojo_cache_linker.py') | |
443 cache_linker_cmd = [ | |
444 mojo_cache_linker_path, | |
445 links_path, | |
446 self.pids['build_dir'], | |
447 'http://localhost:%s' % self.pids['remote_sky_server_port'] | |
448 ] | |
449 return subprocess.Popen(cache_linker_cmd, stdin=logcat.stdout).pid | |
450 | |
451 def _pull_system_libraries(self, system_libs_root): | 432 def _pull_system_libraries(self, system_libs_root): |
452 # Pull down the system libraries this pid has already mapped in. | 433 # Pull down the system libraries this pid has already mapped in. |
453 # TODO(eseidel): This does not handle dynamic loads. | 434 # TODO(eseidel): This does not handle dynamic loads. |
454 library_cacher_path = os.path.join( | 435 library_cacher_path = os.path.join( |
455 self.paths.sky_tools_directory, 'android_library_cacher.py') | 436 self.paths.sky_tools_directory, 'android_library_cacher.py') |
456 subprocess.call([ | 437 subprocess.call([ |
457 library_cacher_path, system_libs_root, self.pids['mojo_shell_pid'] | 438 library_cacher_path, system_libs_root, self.pids['mojo_shell_pid'] |
458 ]) | 439 ]) |
459 | 440 |
460 # TODO(eseidel): adb_gdb does, this, unclear why solib-absolute-prefix | 441 # TODO(eseidel): adb_gdb does, this, unclear why solib-absolute-prefix |
461 # doesn't make this explicit listing not necessary? | 442 # doesn't make this explicit listing not necessary? |
462 return subprocess.check_output([ | 443 return subprocess.check_output([ |
463 'find', system_libs_root, | 444 'find', system_libs_root, |
464 '-mindepth', '1', | 445 '-mindepth', '1', |
465 '-maxdepth', '4', | 446 '-maxdepth', '4', |
466 '-type', 'd', | 447 '-type', 'd', |
467 ]).strip().split('\n') | 448 ]).strip().split('\n') |
468 | 449 |
| 450 def _add_android_library_links(self, links_path): |
| 451 # TODO(eseidel): This might not match mojo_shell on the device? |
| 452 # TODO(eseidel): Should we pass libmojo_shell.so as 'file' to gdb? |
| 453 shell_link_path = os.path.join(links_path, 'libmojo_shell.so') |
| 454 if os.path.lexists(shell_link_path): |
| 455 os.unlink(shell_link_path) |
| 456 os.symlink(self.paths.mojo_shell_path, shell_link_path) |
469 | 457 |
470 def gdb_attach_command(self, args): | 458 def gdb_attach_command(self, args): |
471 self.paths = self._create_paths_for_build_dir(self.pids['build_dir']) | 459 self.paths = self._create_paths_for_build_dir(self.pids['build_dir']) |
472 | 460 |
473 symbol_search_paths = [self.pids['build_dir']] | 461 if not os.path.exists(CACHE_LINKS_PATH): |
| 462 os.makedirs(CACHE_LINKS_PATH) |
| 463 cache_linker_path = os.path.join( |
| 464 self.paths.sky_tools_directory, 'mojo_cache_linker.py') |
| 465 subprocess.check_call([ |
| 466 cache_linker_path, CACHE_LINKS_PATH, self.paths.build_dir]) |
| 467 |
| 468 symbol_search_paths = [ |
| 469 self.pids['build_dir'], |
| 470 CACHE_LINKS_PATH, |
| 471 ] |
474 gdb_path = '/usr/bin/gdb' | 472 gdb_path = '/usr/bin/gdb' |
475 | 473 |
476 init_commands = [ | 474 eval_commands = [ |
| 475 'directory %s' % self.paths.src_root, |
477 'file %s' % self.paths.mojo_shell_path, | 476 'file %s' % self.paths.mojo_shell_path, |
478 'directory %s' % self.paths.src_root, | |
479 'target remote localhost:%s' % GDB_PORT, | 477 'target remote localhost:%s' % GDB_PORT, |
480 ] | 478 ] |
481 | 479 |
482 # A bunch of extra work is needed for android: | 480 # A bunch of extra work is needed for android: |
483 if 'remote_sky_server_port' in self.pids: | 481 if 'remote_sky_server_port' in self.pids: |
484 pid = self._start_mojo_cache_linker(CACHE_LINKS_PATH) | 482 self._add_android_library_links(CACHE_LINKS_PATH) |
485 self.pids['mojo_cache_linker_pid'] = pid | |
486 | 483 |
487 system_lib_dirs = self._pull_system_libraries(SYSTEM_LIBS_ROOT_PATH) | 484 system_lib_dirs = self._pull_system_libraries(SYSTEM_LIBS_ROOT_PATH) |
488 init_commands.append( | 485 eval_commands.append( |
489 'set solib-absolute-prefix %s' % SYSTEM_LIBS_ROOT_PATH) | 486 'set solib-absolute-prefix %s' % SYSTEM_LIBS_ROOT_PATH) |
490 | 487 |
491 symbol_search_paths = system_lib_dirs + symbol_search_paths | 488 symbol_search_paths = system_lib_dirs + symbol_search_paths |
492 symbol_search_paths.append(CACHE_LINKS_PATH) | |
493 | 489 |
494 # TODO(eseidel): We need to look up the toolchain somehow? | 490 # TODO(eseidel): We need to look up the toolchain somehow? |
495 gdb_path = os.path.join(SRC_ROOT, 'third_party/android_tools/ndk/' | 491 gdb_path = os.path.join(SRC_ROOT, 'third_party/android_tools/ndk/' |
496 'toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/' | 492 'toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/' |
497 'bin/arm-linux-androideabi-gdb') | 493 'bin/arm-linux-androideabi-gdb') |
498 | 494 |
499 # Set solib-search-path after letting android modify symbol_search_paths | 495 # Set solib-search-path after letting android modify symbol_search_paths |
500 init_commands.append( | 496 eval_commands.append( |
501 'set solib-search-path %s' % ':'.join(symbol_search_paths)) | 497 'set solib-search-path %s' % ':'.join(symbol_search_paths)) |
502 | 498 |
503 exec_command = [gdb_path] | 499 exec_command = ['/usr/bin/strace', '-o', 'trace.txt', gdb_path] |
504 for command in init_commands: | 500 for command in eval_commands: |
505 exec_command += ['--eval-command', command] | 501 exec_command += ['--eval-command', command] |
| 502 |
506 print " ".join(exec_command) | 503 print " ".join(exec_command) |
507 | 504 |
508 # Write out our pid file before we exec ourselves. | 505 # Write out our pid file before we exec ourselves. |
509 self._write_pid_file(PID_FILE_PATH, self.pids) | 506 self._write_pid_file(PID_FILE_PATH, self.pids) |
510 | 507 |
511 # Exec gdb directly to avoid python intercepting symbols, etc. | 508 # Exec gdb directly to avoid python intercepting symbols, etc. |
512 os.execv(exec_command[0], exec_command) | 509 os.execv(exec_command[0], exec_command) |
513 | 510 |
514 def print_crash_command(self, args): | 511 def print_crash_command(self, args): |
515 logcat_cmd = ['adb', 'logcat', '-d'] | 512 logcat_cmd = ['adb', 'logcat', '-d'] |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
586 load_parser.set_defaults(func=self.load_command) | 583 load_parser.set_defaults(func=self.load_command) |
587 | 584 |
588 args = parser.parse_args() | 585 args = parser.parse_args() |
589 args.func(args) | 586 args.func(args) |
590 | 587 |
591 self._write_pid_file(PID_FILE_PATH, self.pids) | 588 self._write_pid_file(PID_FILE_PATH, self.pids) |
592 | 589 |
593 | 590 |
594 if __name__ == '__main__': | 591 if __name__ == '__main__': |
595 SkyDebugger().main() | 592 SkyDebugger().main() |
OLD | NEW |