| 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 |