Index: sky/tools/skydb |
diff --git a/sky/tools/skydb b/sky/tools/skydb |
index abdbbd4094bb814663499a337dc614ccf9828681..79044a75561b6bd0686d9817d9e353800911d69a 100755 |
--- a/sky/tools/skydb |
+++ b/sky/tools/skydb |
@@ -17,6 +17,7 @@ import subprocess |
import sys |
import time |
import urlparse |
+import re |
qsr
2015/01/16 19:22:46
Alphabetize.
|
SRC_ROOT = skypy.paths.Paths('ignored').src_root |
sys.path.insert(0, os.path.join(SRC_ROOT, 'build', 'android')) |
@@ -40,6 +41,7 @@ DEFAULT_URL = "https://raw.githubusercontent.com/domokit/mojo/master/sky/example |
ANDROID_PACKAGE = "org.chromium.mojo.shell" |
ANDROID_ACTIVITY = "%s/.MojoShellActivity" % ANDROID_PACKAGE |
+ |
# FIXME: Move this into mopy.config |
def gn_args_from_build_dir(build_dir): |
gn_cmd = [ |
@@ -97,7 +99,7 @@ class SkyDebugger(object): |
'--esa', 'parameters', ','.join(escaped_args), |
] |
- def _build_mojo_shell_command(self, args): |
+ def _build_mojo_shell_command(self, args, is_android): |
content_handlers = ['%s,%s' % (mime_type, 'mojo:sky_viewer') |
for mime_type in SUPPORTED_MIME_TYPES] |
@@ -111,6 +113,14 @@ class SkyDebugger(object): |
'mojo:window_manager', |
] |
+ # Desktop-only work-around for mojo crashing under chromoting. |
+ if not is_android and args.use_osmesa: |
+ shell_args.append( |
+ '--args-for=mojo:native_viewport_service --use-osmesa') |
+ |
+ if is_android and args.gdb: |
+ shell_args.append('--wait_for_debugger') |
+ |
if 'remote_sky_server_port' in self.pids: |
shell_command = self._wrap_for_android(shell_args) |
else: |
@@ -139,6 +149,20 @@ class SkyDebugger(object): |
root_relative_build_dir = os.path.relpath(abs_build_dir, SRC_ROOT) |
return skypy.paths.Paths(root_relative_build_dir) |
+ def _find_remote_pid_for_package(self, package): |
+ ps_output = subprocess.check_output(['adb', 'shell', 'ps']) |
+ for line in ps_output.split('\n'): |
+ fields = line.split() |
+ if fields and fields[-1] == package: |
+ return fields[1] |
+ return None |
+ |
+ def _find_install_location_for_package(self, package): |
+ pm_command = ['adb', 'shell', 'pm', 'path', package] |
+ pm_output = subprocess.check_output(pm_command) |
+ # e.g. package:/data/app/org.chromium.mojo.shell-1/base.apk |
+ return pm_output.split(':')[-1] |
+ |
def start_command(self, args): |
# FIXME: Lame that we use self for a command-specific variable. |
self.paths = self._create_paths_for_build_dir(args.build_dir) |
@@ -181,26 +205,52 @@ class SkyDebugger(object): |
]) |
self.pids['remote_sky_command_port'] = args.command_port |
- shell_command = self._build_mojo_shell_command(args) |
- |
- if not is_android: |
- # Desktop-only work-around for mojo crashing under chromoting. |
- if args.use_osmesa: |
- shell_command.append( |
- '--args-for=mojo:native_viewport_service --use-osmesa') |
+ shell_command = self._build_mojo_shell_command(args, is_android) |
- # On android we can't launch inside gdb, but rather have to attach. |
- if args.gdb: |
- shell_command = ['gdbserver', ':%s' % GDB_PORT] + shell_command |
+ # On android we can't launch inside gdb, but rather have to attach. |
+ if not is_android and args.gdb: |
+ shell_command = ['gdbserver', ':%d' % GDB_PORT] + shell_command |
print ' '.join(map(pipes.quote, shell_command)) |
- self.pids['mojo_shell_pid'] = subprocess.Popen(shell_command).pid |
+ # This pid is meaningless on android (it's the adb shell pid) |
+ start_command_pid = subprocess.Popen(shell_command).pid |
- if args.gdb and is_android: |
- gdbserver_cmd = ['gdbserver', '--attach', ':%s' % GDB_PORT] |
- self.pids['remote_gdbserver_pid'] = subprocess.Popen(shell_command).pid |
+ if is_android: |
+ # TODO(eseidel): am start -W does not seem to work? |
+ pid_tries = 0 |
+ while True: |
+ pid = self._find_remote_pid_for_package(ANDROID_PACKAGE) |
+ if pid or pid_tries > 3: |
+ break |
+ logging.debug('No pid for %s yet, waiting' % ANDROID_PACKAGE) |
+ time.sleep(5) |
+ pid_tries += 1 |
+ |
+ if not pid: |
+ logging.error('Failed to find mojo_shell pid on device!') |
+ return |
+ self.pids['mojo_shell_pid'] = pid |
+ else: |
+ self.pids['mojo_shell_pid'] = start_command_pid |
- port_string = 'tcp:%s' % GDB_PORT |
+ if args.gdb and is_android: |
+ # We push our own copy of gdbserver with the package since |
+ # the default gdbserver is a different version from our gdb. |
+ package_path = \ |
+ self._find_install_location_for_package(ANDROID_PACKAGE) |
+ gdb_server_path = os.path.join( |
+ os.path.dirname(package_path), 'lib/arm/gdbserver') |
+ gdbserver_cmd = [ |
+ 'adb', 'shell', |
+ gdb_server_path, '--attach', |
+ ':%d' % GDB_PORT, |
+ str(self.pids['mojo_shell_pid']) |
+ ] |
+ print ' '.join(map(pipes.quote, gdbserver_cmd)) |
+ self.pids['adb_shell_gdbserver_pid'] = \ |
+ subprocess.Popen(gdbserver_cmd).pid |
+ |
+ port_string = 'tcp:%d' % GDB_PORT |
subprocess.check_call([ |
'adb', 'forward', port_string, port_string |
]) |
@@ -220,18 +270,18 @@ class SkyDebugger(object): |
if not pid: |
logging.info('No pid for %s, nothing to do.' % name) |
return |
- logging.info('Killing %s (%s).' % (name, pid)) |
+ logging.info('Killing %s (%d).' % (name, pid)) |
try: |
os.kill(pid, signal.SIGTERM) |
except OSError: |
- logging.info('%s (%s) already gone.' % (name, pid)) |
+ logging.info('%s (%d) already gone.' % (name, pid)) |
def stop_command(self, args): |
# TODO(eseidel): mojo_shell crashes when attempting graceful shutdown. |
# self._send_command_to_sky('/quit') |
- self._kill_if_exists('mojo_shell_pid', 'mojo_shell') |
self._kill_if_exists('sky_server_pid', 'sky_server') |
+ |
# We could be much more surgical here: |
if 'remote_sky_server_port' in self.pids: |
device = android_commands.AndroidCommands( |
@@ -245,12 +295,20 @@ class SkyDebugger(object): |
subprocess.call([ |
'adb', 'shell', 'am', 'force-stop', ANDROID_PACKAGE]) |
+ else: |
+ # Only try to kill mojo_shell if it's running locally. |
+ self._kill_if_exists('mojo_shell_pid', 'mojo_shell') |
if 'remote_gdbserver_port' in self.pids: |
+ self._kill_if_exists('adb_shell_gdbserver_pid', |
+ 'adb shell gdbserver') |
+ |
port_string = 'tcp:%s' % self.pids['remote_gdbserver_port'] |
subprocess.call(['adb', 'forward', '--remove', port_string]) |
self.pids = {} # Clear out our pid file. |
+ self._kill_if_exists('mojo_cache_linker_pid', 'mojo cache linker') |
+ |
def load_command(self, args): |
if not urlparse.urlparse(args.url_or_path).scheme: |
# The load happens on the remote device, use the remote port. |
@@ -323,12 +381,53 @@ class SkyDebugger(object): |
def gdb_attach_command(self, args): |
self.paths = self._create_paths_for_build_dir(self.pids['build_dir']) |
+ |
+ self._kill_if_exists('mojo_cache_linker_pid', 'mojo cache linker') |
+ |
+ links_path = '/tmp/mojo_cache_links' |
+ if not os.path.exists(links_path): |
+ os.makedirs(links_path) |
+ shell_link_path = os.path.join(links_path, 'libmojo_shell.so') |
+ if os.path.lexists(shell_link_path): |
+ os.unlink(shell_link_path) |
+ os.symlink(self.paths.mojo_shell_path, shell_link_path) |
+ |
+ logcat_cmd = ['adb', 'logcat'] |
+ logcat = subprocess.Popen(logcat_cmd, stdout=subprocess.PIPE) |
+ |
+ mojo_cache_linker_path = os.path.join( |
+ self.paths.sky_tools_directory, 'mojo_cache_linker.py') |
+ cache_linker_cmd = [ |
+ mojo_cache_linker_path, |
+ links_path, |
+ self.pids['build_dir'], |
+ 'http://localhost:%s' % self.pids['remote_sky_server_port'] |
+ ] |
+ self.pids['mojo_cache_linker_pid'] = \ |
+ subprocess.Popen(cache_linker_cmd, stdin=logcat.stdout).pid |
+ |
+ # Write out our pid file before we exec ourselves. |
+ self._write_pid_file(PID_FILE_PATH, self.pids) |
+ |
+ # TODO(eseidel): Need to sync down system libraries into a directory. |
+ symbol_search_paths = [ |
+ links_path, |
+ self.pids['build_dir'], |
+ ] |
+ # TODO(eseidel): We need to look up the toolchain somehow? |
+ gdb_path = os.path.join(SRC_ROOT, 'third_party/android_tools/ndk/' |
+ 'toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/' |
+ 'bin/arm-linux-androideabi-gdb') |
gdb_command = [ |
- '/usr/bin/gdb', self.paths.mojo_shell_path, |
- '--eval-command', 'target remote localhost:%s' % GDB_PORT |
+ gdb_path, |
+ '--eval-command', 'file %s' % self.paths.mojo_shell_path, |
+ '--eval-command', 'directory %s' % self.paths.src_root, |
+ '--eval-command', 'target remote localhost:%s' % GDB_PORT, |
+ '--eval-command', 'set solib-search-path %s' % |
+ ':'.join(symbol_search_paths), |
] |
print " ".join(gdb_command) |
- # We don't want python listenting for signals or anything, so exec |
+ # We don't want python listening for signals or anything, so exec |
# gdb and let it take the entire process. |
os.execv(gdb_command[0], gdb_command) |
@@ -343,7 +442,7 @@ class SkyDebugger(object): |
stack.wait() |
def main(self): |
- logging.basicConfig(level=logging.INFO) |
+ logging.basicConfig(level=logging.WARNING) |
logging.getLogger("requests").setLevel(logging.WARNING) |
self.pids = self._load_pid_file(PID_FILE_PATH) |