| 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 |
| 11 import pipes | 11 import pipes |
| 12 import re | 12 import re |
| 13 import requests | 13 import requests |
| 14 import signal | 14 import signal |
| 15 import skypy.paths | 15 import skypy.paths |
| 16 import StringIO | 16 import StringIO |
| 17 import subprocess | 17 import subprocess |
| 18 import sys | 18 import sys |
| 19 import time | 19 import time |
| 20 import urlparse | 20 import urlparse |
| 21 | 21 |
| 22 SRC_ROOT = skypy.paths.Paths('ignored').src_root | |
| 23 sys.path.insert(0, os.path.join(SRC_ROOT, 'build', 'android')) | |
| 24 from pylib import android_commands | |
| 25 from pylib import constants | |
| 26 from pylib import forwarder | |
| 27 | |
| 28 | |
| 29 SUPPORTED_MIME_TYPES = [ | 22 SUPPORTED_MIME_TYPES = [ |
| 30 'text/html', | 23 'text/html', |
| 31 'text/sky', | 24 'text/sky', |
| 32 'text/plain', | 25 'text/plain', |
| 33 ] | 26 ] |
| 34 | 27 |
| 35 DEFAULT_SKY_COMMAND_PORT = 7777 | 28 DEFAULT_SKY_COMMAND_PORT = 7777 |
| 36 GDB_PORT = 8888 | 29 GDB_PORT = 8888 |
| 37 SKY_SERVER_PORT = 9999 | 30 SKY_SERVER_PORT = 9999 |
| 38 PID_FILE_PATH = "/tmp/skydb.pids" | |
| 39 DEFAULT_URL = "https://raw.githubusercontent.com/domokit/mojo/master/sky/example
s/home.sky" | 31 DEFAULT_URL = "https://raw.githubusercontent.com/domokit/mojo/master/sky/example
s/home.sky" |
| 40 | 32 |
| 41 ANDROID_PACKAGE = "org.chromium.mojo.shell" | 33 ANDROID_PACKAGE = "org.chromium.mojo.shell" |
| 42 ANDROID_ACTIVITY = "%s/.MojoShellActivity" % ANDROID_PACKAGE | 34 ANDROID_ACTIVITY = "%s/.MojoShellActivity" % ANDROID_PACKAGE |
| 43 ANDROID_APK_NAME = 'MojoShell.apk' | 35 ANDROID_APK_NAME = 'MojoShell.apk' |
| 36 |
| 37 PID_FILE_PATH = "/tmp/skydb.pids" |
| 44 CACHE_LINKS_PATH = '/tmp/mojo_cache_links' | 38 CACHE_LINKS_PATH = '/tmp/mojo_cache_links' |
| 45 SYSTEM_LIBS_ROOT_PATH = '/tmp/device_libs' | 39 SYSTEM_LIBS_ROOT_PATH = '/tmp/device_libs' |
| 46 | 40 |
| 41 SRC_ROOT = skypy.paths.Paths('ignored').src_root |
| 42 ADB_PATH = os.path.join(SRC_ROOT, |
| 43 'third_party/android_tools/sdk/platform-tools/adb') |
| 44 |
| 47 | 45 |
| 48 # FIXME: Move this into mopy.config | 46 # FIXME: Move this into mopy.config |
| 49 def gn_args_from_build_dir(build_dir): | 47 def gn_args_from_build_dir(build_dir): |
| 50 gn_cmd = [ | 48 gn_cmd = [ |
| 51 'gn', 'args', | 49 'gn', 'args', |
| 52 build_dir, | 50 build_dir, |
| 53 '--list', '--short' | 51 '--list', '--short' |
| 54 ] | 52 ] |
| 55 config = {} | 53 config = {} |
| 56 for line in subprocess.check_output(gn_cmd).strip().split('\n'): | 54 for line in subprocess.check_output(gn_cmd).strip().split('\n'): |
| (...skipping 21 matching lines...) Expand all Loading... |
| 78 | 76 |
| 79 def _in_chromoting(self): | 77 def _in_chromoting(self): |
| 80 return os.environ.get('CHROME_REMOTE_DESKTOP_SESSION', False) | 78 return os.environ.get('CHROME_REMOTE_DESKTOP_SESSION', False) |
| 81 | 79 |
| 82 def _wrap_for_android(self, shell_args): | 80 def _wrap_for_android(self, shell_args): |
| 83 # am shell --esa: (someone shoot me now) | 81 # am shell --esa: (someone shoot me now) |
| 84 # [--esa <EXTRA_KEY> <EXTRA_STRING_VALUE>[,<EXTRA_STRING_VALUE...]] | 82 # [--esa <EXTRA_KEY> <EXTRA_STRING_VALUE>[,<EXTRA_STRING_VALUE...]] |
| 85 # (to embed a comma into a string escape it using "\,") | 83 # (to embed a comma into a string escape it using "\,") |
| 86 escaped_args = map(lambda arg: arg.replace(',', '\\,'), shell_args) | 84 escaped_args = map(lambda arg: arg.replace(',', '\\,'), shell_args) |
| 87 return [ | 85 return [ |
| 88 'adb', 'shell', | 86 ADB_PATH, 'shell', |
| 89 'am', 'start', | 87 'am', 'start', |
| 90 '-W', | 88 '-W', |
| 91 '-S', | 89 '-S', |
| 92 '-a', 'android.intent.action.VIEW', | 90 '-a', 'android.intent.action.VIEW', |
| 93 '-n', ANDROID_ACTIVITY, | 91 '-n', ANDROID_ACTIVITY, |
| 94 # FIXME: This quoting is very error-prone. Perhaps we should read | 92 # FIXME: This quoting is very error-prone. Perhaps we should read |
| 95 # our args from a file instead? | 93 # our args from a file instead? |
| 96 '--esa', 'parameters', ','.join(escaped_args), | 94 '--esa', 'parameters', ','.join(escaped_args), |
| 97 ] | 95 ] |
| 98 | 96 |
| 99 def _build_mojo_shell_command(self, args, is_android): | 97 def _build_mojo_shell_command(self, args, is_android): |
| 100 content_handlers = ['%s,%s' % (mime_type, 'mojo:sky_viewer') | 98 content_handlers = ['%s,%s' % (mime_type, 'mojo:sky_viewer') |
| 101 for mime_type in SUPPORTED_MIME_TYPES] | 99 for mime_type in SUPPORTED_MIME_TYPES] |
| 102 | 100 |
| 103 remote_command_port = self.pids.get('remote_sky_command_port', self.pids
['sky_command_port']) | 101 remote_command_port = self.pids.get('remote_sky_command_port', self.pids
['sky_command_port']) |
| 104 remote_server_port = self.pids.get('remote_sky_server_port', self.pids['
sky_server_port']) | 102 remote_server_port = self.pids.get('remote_sky_server_port', self.pids['
sky_server_port']) |
| 105 | 103 |
| 106 shell_args = [ | 104 shell_args = [ |
| 107 '--v=1', | 105 '--v=1', |
| 108 '--content-handlers=%s' % ','.join(content_handlers), | 106 '--content-handlers=%s' % ','.join(content_handlers), |
| 109 '--url-mappings=mojo:window_manager=mojo:sky_debugger', | 107 '--url-mappings=mojo:window_manager=mojo:sky_debugger', |
| 110 '--args-for=mojo:sky_debugger_prompt %d' % remote_command_port, | 108 '--args-for=mojo:sky_debugger_prompt %d' % remote_command_port, |
| 111 'mojo:window_manager', | 109 'mojo:window_manager', |
| 112 ] | 110 ] |
| 113 | 111 |
| 112 if args.url_or_path: |
| 113 shell_args.append( |
| 114 '--args-for=mojo:window_manager %s' % self._url_from_args(args)) |
| 115 |
| 114 # Map all mojo: urls to http: urls using the --origin command. | 116 # Map all mojo: urls to http: urls using the --origin command. |
| 115 build_dir_url = SkyServer.url_for_path( | 117 build_dir_url = SkyServer.url_for_path( |
| 116 remote_server_port, | 118 remote_server_port, |
| 117 self.pids['sky_server_root'], | 119 self.pids['sky_server_root'], |
| 118 self.pids['build_dir']) | 120 self.pids['build_dir']) |
| 119 shell_args += ['--origin=%s' % build_dir_url] | 121 shell_args += ['--origin=%s' % build_dir_url] |
| 120 | 122 |
| 121 # Desktop-only work-around for mojo crashing under chromoting. | 123 # Desktop-only work-around for mojo crashing under chromoting. |
| 122 if not is_android and args.use_osmesa: | 124 if not is_android and args.use_osmesa: |
| 123 shell_args.append( | 125 shell_args.append( |
| 124 '--args-for=mojo:native_viewport_service --use-osmesa') | 126 '--args-for=mojo:native_viewport_service --use-osmesa') |
| 125 | 127 |
| 126 if is_android and args.gdb: | 128 if is_android and args.gdb: |
| 127 shell_args.append('--wait_for_debugger') | 129 shell_args.append('--wait_for_debugger') |
| 128 | 130 |
| 129 if 'remote_sky_server_port' in self.pids: | 131 if 'remote_sky_server_port' in self.pids: |
| 130 shell_command = self._wrap_for_android(shell_args) | 132 shell_command = self._wrap_for_android(shell_args) |
| 131 else: | 133 else: |
| 132 shell_command = [self.paths.mojo_shell_path] + shell_args | 134 shell_command = [self.paths.mojo_shell_path] + shell_args |
| 133 | 135 |
| 134 return shell_command | 136 return shell_command |
| 135 | 137 |
| 136 def _connect_to_device(self): | |
| 137 device = android_commands.AndroidCommands( | |
| 138 android_commands.GetAttachedDevices()[0]) | |
| 139 device.EnableAdbRoot() | |
| 140 return device | |
| 141 | |
| 142 def sky_server_for_args(self, args): | 138 def sky_server_for_args(self, args): |
| 143 # FIXME: This is a hack. sky_server should just take a build_dir | 139 # FIXME: This is a hack. sky_server should just take a build_dir |
| 144 # not a magical "configuration" name. | 140 # not a magical "configuration" name. |
| 145 configuration = os.path.basename(os.path.normpath(self.paths.build_dir)) | 141 configuration = os.path.basename(os.path.normpath(self.paths.build_dir)) |
| 146 server_root = self._server_root_for_url(args.url_or_path) | 142 server_root = self._server_root_for_url(args.url_or_path) |
| 147 sky_server = SkyServer(self.paths, SKY_SERVER_PORT, | 143 sky_server = SkyServer(self.paths, SKY_SERVER_PORT, |
| 148 configuration, server_root) | 144 configuration, server_root) |
| 149 return sky_server | 145 return sky_server |
| 150 | 146 |
| 151 def _create_paths_for_build_dir(self, build_dir): | 147 def _create_paths_for_build_dir(self, build_dir): |
| 152 # skypy.paths.Paths takes a root-relative build_dir argument. :( | 148 # skypy.paths.Paths takes a root-relative build_dir argument. :( |
| 153 abs_build_dir = os.path.abspath(build_dir) | 149 abs_build_dir = os.path.abspath(build_dir) |
| 154 root_relative_build_dir = os.path.relpath(abs_build_dir, SRC_ROOT) | 150 root_relative_build_dir = os.path.relpath(abs_build_dir, SRC_ROOT) |
| 155 return skypy.paths.Paths(root_relative_build_dir) | 151 return skypy.paths.Paths(root_relative_build_dir) |
| 156 | 152 |
| 157 def _find_remote_pid_for_package(self, package): | 153 def _find_remote_pid_for_package(self, package): |
| 158 ps_output = subprocess.check_output(['adb', 'shell', 'ps']) | 154 ps_output = subprocess.check_output([ADB_PATH, 'shell', 'ps']) |
| 159 for line in ps_output.split('\n'): | 155 for line in ps_output.split('\n'): |
| 160 fields = line.split() | 156 fields = line.split() |
| 161 if fields and fields[-1] == package: | 157 if fields and fields[-1] == package: |
| 162 return fields[1] | 158 return fields[1] |
| 163 return None | 159 return None |
| 164 | 160 |
| 165 def _find_install_location_for_package(self, package): | 161 def _find_install_location_for_package(self, package): |
| 166 pm_command = ['adb', 'shell', 'pm', 'path', package] | 162 pm_command = [ADB_PATH, 'shell', 'pm', 'path', package] |
| 167 pm_output = subprocess.check_output(pm_command) | 163 pm_output = subprocess.check_output(pm_command) |
| 168 # e.g. package:/data/app/org.chromium.mojo.shell-1/base.apk | 164 # e.g. package:/data/app/org.chromium.mojo.shell-1/base.apk |
| 169 return pm_output.split(':')[-1] | 165 return pm_output.split(':')[-1] |
| 170 | 166 |
| 171 def start_command(self, args): | 167 def start_command(self, args): |
| 172 # FIXME: Lame that we use self for a command-specific variable. | 168 # FIXME: Lame that we use self for a command-specific variable. |
| 173 self.paths = self._create_paths_for_build_dir(args.build_dir) | 169 self.paths = self._create_paths_for_build_dir(args.build_dir) |
| 174 self.stop_command(None) # Quit any existing process. | 170 self.stop_command(None) # Quit any existing process. |
| 175 | 171 |
| 176 if not os.path.exists(self.paths.mojo_shell_path): | 172 if not os.path.exists(self.paths.mojo_shell_path): |
| 177 print "mojo_shell not found in build_dir '%s'" % args.build_dir | 173 print "mojo_shell not found in build_dir '%s'" % args.build_dir |
| 178 print "Are you sure you sure that's a valid build_dir location?" | 174 print "Are you sure you sure that's a valid build_dir location?" |
| 179 print "See skydb start --help for more info" | 175 print "See skydb start --help for more info" |
| 180 sys.exit(2) | 176 sys.exit(2) |
| 181 | 177 |
| 182 # FIXME: This is probably not the right way to compute is_android | 178 # FIXME: This is probably not the right way to compute is_android |
| 183 # from the build directory? | 179 # from the build directory? |
| 184 gn_args = gn_args_from_build_dir(self.paths.build_dir) | 180 gn_args = gn_args_from_build_dir(self.paths.build_dir) |
| 185 is_android = 'android_sdk_version' in gn_args | 181 is_android = 'android_sdk_version' in gn_args |
| 186 | 182 |
| 187 sky_server = self.sky_server_for_args(args) | 183 sky_server = self.sky_server_for_args(args) |
| 188 self.pids['sky_server_pid'] = sky_server.start() | 184 self.pids['sky_server_pid'] = sky_server.start() |
| 189 self.pids['sky_server_port'] = sky_server.port | 185 self.pids['sky_server_port'] = sky_server.port |
| 190 self.pids['sky_server_root'] = sky_server.root | 186 self.pids['sky_server_root'] = sky_server.root |
| 191 | 187 |
| 192 self.pids['build_dir'] = self.paths.build_dir | 188 self.pids['build_dir'] = self.paths.build_dir |
| 193 self.pids['sky_command_port'] = args.command_port | 189 self.pids['sky_command_port'] = args.command_port |
| 194 | 190 |
| 195 if is_android: | 191 if is_android: |
| 196 # Pray to the build/android gods in their misspelled tongue. | |
| 197 constants.SetOutputDirectort(self.paths.build_dir) | |
| 198 | |
| 199 # We could make installing conditional on an argument. | 192 # We could make installing conditional on an argument. |
| 200 apk_path = os.path.join(self.paths.build_dir, 'apks', | 193 apk_path = os.path.join(self.paths.build_dir, 'apks', |
| 201 ANDROID_APK_NAME) | 194 ANDROID_APK_NAME) |
| 202 subprocess.check_call(['adb', 'install', '-r', apk_path]) | 195 subprocess.check_call([ADB_PATH, 'install', '-r', apk_path]) |
| 203 | 196 |
| 204 device = self._connect_to_device() | 197 port_string = 'tcp:%s' % sky_server.port |
| 205 self.pids['device_serial'] = device.GetDevice() | 198 subprocess.check_call([ |
| 206 | 199 ADB_PATH, 'reverse', port_string, port_string |
| 207 forwarder.Forwarder.Map([(0, sky_server.port)], device) | 200 ]) |
| 208 device_http_port = forwarder.Forwarder.DevicePortForHostPort( | 201 self.pids['remote_sky_server_port'] = sky_server.port |
| 209 sky_server.port) | |
| 210 self.pids['remote_sky_server_port'] = device_http_port | |
| 211 | 202 |
| 212 port_string = 'tcp:%s' % args.command_port | 203 port_string = 'tcp:%s' % args.command_port |
| 213 subprocess.check_call([ | 204 subprocess.check_call([ |
| 214 'adb', 'forward', port_string, port_string | 205 ADB_PATH, 'forward', port_string, port_string |
| 215 ]) | 206 ]) |
| 216 self.pids['remote_sky_command_port'] = args.command_port | 207 self.pids['remote_sky_command_port'] = args.command_port |
| 217 | 208 |
| 218 shell_command = self._build_mojo_shell_command(args, is_android) | 209 shell_command = self._build_mojo_shell_command(args, is_android) |
| 219 | 210 |
| 220 # On android we can't launch inside gdb, but rather have to attach. | 211 # On android we can't launch inside gdb, but rather have to attach. |
| 221 if not is_android and args.gdb: | 212 if not is_android and args.gdb: |
| 222 shell_command = ['gdbserver', ':%d' % GDB_PORT] + shell_command | 213 shell_command = ['gdbserver', ':%d' % GDB_PORT] + shell_command |
| 223 | 214 |
| 224 print ' '.join(map(pipes.quote, shell_command)) | 215 print ' '.join(map(pipes.quote, shell_command)) |
| (...skipping 19 matching lines...) Expand all Loading... |
| 244 self.pids['mojo_shell_pid'] = start_command_pid | 235 self.pids['mojo_shell_pid'] = start_command_pid |
| 245 | 236 |
| 246 if args.gdb and is_android: | 237 if args.gdb and is_android: |
| 247 # We push our own copy of gdbserver with the package since | 238 # We push our own copy of gdbserver with the package since |
| 248 # the default gdbserver is a different version from our gdb. | 239 # the default gdbserver is a different version from our gdb. |
| 249 package_path = \ | 240 package_path = \ |
| 250 self._find_install_location_for_package(ANDROID_PACKAGE) | 241 self._find_install_location_for_package(ANDROID_PACKAGE) |
| 251 gdb_server_path = os.path.join( | 242 gdb_server_path = os.path.join( |
| 252 os.path.dirname(package_path), 'lib/arm/gdbserver') | 243 os.path.dirname(package_path), 'lib/arm/gdbserver') |
| 253 gdbserver_cmd = [ | 244 gdbserver_cmd = [ |
| 254 'adb', 'shell', | 245 ADB_PATH, 'shell', |
| 255 gdb_server_path, '--attach', | 246 gdb_server_path, '--attach', |
| 256 ':%d' % GDB_PORT, | 247 ':%d' % GDB_PORT, |
| 257 str(self.pids['mojo_shell_pid']) | 248 str(self.pids['mojo_shell_pid']) |
| 258 ] | 249 ] |
| 259 print ' '.join(map(pipes.quote, gdbserver_cmd)) | 250 print ' '.join(map(pipes.quote, gdbserver_cmd)) |
| 260 self.pids['adb_shell_gdbserver_pid'] = \ | 251 self.pids['adb_shell_gdbserver_pid'] = \ |
| 261 subprocess.Popen(gdbserver_cmd).pid | 252 subprocess.Popen(gdbserver_cmd).pid |
| 262 | 253 |
| 263 port_string = 'tcp:%d' % GDB_PORT | 254 port_string = 'tcp:%d' % GDB_PORT |
| 264 subprocess.check_call([ | 255 subprocess.check_call([ |
| 265 'adb', 'forward', port_string, port_string | 256 ADB_PATH, 'forward', port_string, port_string |
| 266 ]) | 257 ]) |
| 267 self.pids['remote_gdbserver_port'] = GDB_PORT | 258 self.pids['remote_gdbserver_port'] = GDB_PORT |
| 268 | 259 |
| 269 if not args.gdb: | 260 if not args.gdb: |
| 270 if not self._wait_for_sky_command_port(): | 261 if not self._wait_for_sky_command_port(): |
| 271 logging.error('Failed to start sky') | 262 logging.error('Failed to start sky') |
| 272 self.stop_command(None) | 263 self.stop_command(None) |
| 273 else: | |
| 274 self.load_command(args) | |
| 275 else: | 264 else: |
| 276 print 'No load issued, connect with gdb first and then run load.' | 265 # We could just run gdb_attach_command here, but when I do that |
| 266 # it auto-suspends in my zsh. Unclear why. |
| 267 # self.gdb_attach_command(args) |
| 268 print "Run skydb gdb_attach to attach." |
| 277 | 269 |
| 278 def _kill_if_exists(self, key, name): | 270 def _kill_if_exists(self, key, name): |
| 279 pid = self.pids.pop(key, None) | 271 pid = self.pids.pop(key, None) |
| 280 if not pid: | 272 if not pid: |
| 281 logging.info('No pid for %s, nothing to do.' % name) | 273 logging.info('No pid for %s, nothing to do.' % name) |
| 282 return | 274 return |
| 283 logging.info('Killing %s (%d).' % (name, pid)) | 275 logging.info('Killing %s (%d).' % (name, pid)) |
| 284 try: | 276 try: |
| 285 os.kill(pid, signal.SIGTERM) | 277 os.kill(pid, signal.SIGTERM) |
| 286 except OSError: | 278 except OSError: |
| 287 logging.info('%s (%d) already gone.' % (name, pid)) | 279 logging.info('%s (%d) already gone.' % (name, pid)) |
| 288 | 280 |
| 289 def stop_command(self, args): | 281 def stop_command(self, args): |
| 290 # TODO(eseidel): mojo_shell crashes when attempting graceful shutdown. | 282 # TODO(eseidel): mojo_shell crashes when attempting graceful shutdown. |
| 291 # self._run_basic_command('/quit') | 283 # self._run_basic_command('/quit') |
| 292 | 284 |
| 293 self._kill_if_exists('sky_server_pid', 'sky_server') | 285 self._kill_if_exists('sky_server_pid', 'sky_server') |
| 294 | 286 |
| 295 # We could be much more surgical here: | |
| 296 if 'remote_sky_server_port' in self.pids: | 287 if 'remote_sky_server_port' in self.pids: |
| 297 device = android_commands.AndroidCommands( | 288 port_string = 'tcp:%s' % self.pids['remote_sky_server_port'] |
| 298 self.pids['device_serial']) | 289 subprocess.call([ADB_PATH, 'reverse', '--remove', port_string]) |
| 299 forwarder.Forwarder.UnmapAllDevicePorts(device) | |
| 300 | 290 |
| 301 if 'remote_sky_command_port' in self.pids: | 291 if 'remote_sky_command_port' in self.pids: |
| 302 # adb forward --remove takes the *host* port, not the remote port. | 292 # adb forward --remove takes the *host* port, not the remote port. |
| 303 port_string = 'tcp:%s' % self.pids['sky_command_port'] | 293 port_string = 'tcp:%s' % self.pids['sky_command_port'] |
| 304 subprocess.call(['adb', 'forward', '--remove', port_string]) | 294 subprocess.call([ADB_PATH, 'forward', '--remove', port_string]) |
| 305 | 295 |
| 306 subprocess.call([ | 296 subprocess.call([ |
| 307 'adb', 'shell', 'am', 'force-stop', ANDROID_PACKAGE]) | 297 ADB_PATH, 'shell', 'am', 'force-stop', ANDROID_PACKAGE]) |
| 308 else: | 298 else: |
| 309 # Only try to kill mojo_shell if it's running locally. | 299 # Only try to kill mojo_shell if it's running locally. |
| 310 self._kill_if_exists('mojo_shell_pid', 'mojo_shell') | 300 self._kill_if_exists('mojo_shell_pid', 'mojo_shell') |
| 311 | 301 |
| 312 if 'remote_gdbserver_port' in self.pids: | 302 if 'remote_gdbserver_port' in self.pids: |
| 313 self._kill_if_exists('adb_shell_gdbserver_pid', | 303 self._kill_if_exists('adb_shell_gdbserver_pid', |
| 314 'adb shell gdbserver') | 304 'adb shell gdbserver') |
| 315 | 305 |
| 316 port_string = 'tcp:%s' % self.pids['remote_gdbserver_port'] | 306 port_string = 'tcp:%s' % self.pids['remote_gdbserver_port'] |
| 317 subprocess.call(['adb', 'forward', '--remove', port_string]) | 307 subprocess.call([ADB_PATH, 'forward', '--remove', port_string]) |
| 318 self.pids = {} # Clear out our pid file. | 308 self.pids = {} # Clear out our pid file. |
| 319 | 309 |
| 310 def _url_from_args(self, args): |
| 311 if urlparse.urlparse(args.url_or_path).scheme: |
| 312 return args.url_or_path |
| 313 # The load happens on the remote device, use the remote port. |
| 314 remote_sky_server_port = self.pids.get('remote_sky_server_port', |
| 315 self.pids['sky_server_port']) |
| 316 return SkyServer.url_for_path(remote_sky_server_port, |
| 317 self.pids['sky_server_root'], args.url_or_path) |
| 318 |
| 320 def load_command(self, args): | 319 def load_command(self, args): |
| 321 if not urlparse.urlparse(args.url_or_path).scheme: | 320 self._run_basic_command('/load', self._url_from_args(args)) |
| 322 # The load happens on the remote device, use the remote port. | |
| 323 remote_sky_server_port = self.pids.get('remote_sky_server_port', | |
| 324 self.pids['sky_server_port']) | |
| 325 url = SkyServer.url_for_path(remote_sky_server_port, | |
| 326 self.pids['sky_server_root'], args.url_or_path) | |
| 327 else: | |
| 328 url = args.url_or_path | |
| 329 self._run_basic_command('/load', url) | |
| 330 | 321 |
| 331 def _read_mojo_map(self): | 322 def _read_mojo_map(self): |
| 332 # TODO(eseidel): Does not work for android. | 323 # TODO(eseidel): Does not work for android. |
| 333 mojo_map_path = "/tmp/mojo_shell.%d.maps" % self.pids['mojo_shell_pid'] | 324 mojo_map_path = "/tmp/mojo_shell.%d.maps" % self.pids['mojo_shell_pid'] |
| 334 with open(mojo_map_path, 'r') as maps_file: | 325 with open(mojo_map_path, 'r') as maps_file: |
| 335 lines = maps_file.read().strip().split('\n') | 326 lines = maps_file.read().strip().split('\n') |
| 336 return dict(map(lambda line: line.split(' '), lines)) | 327 return dict(map(lambda line: line.split(' '), lines)) |
| 337 | 328 |
| 338 def stop_tracing_command(self, args): | 329 def stop_tracing_command(self, args): |
| 339 file_name = args.file_name | 330 file_name = args.file_name |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 430 time.sleep(1) | 421 time.sleep(1) |
| 431 | 422 |
| 432 def logcat_command(self, args): | 423 def logcat_command(self, args): |
| 433 TAGS = [ | 424 TAGS = [ |
| 434 'AndroidHandler', | 425 'AndroidHandler', |
| 435 'MojoMain', | 426 'MojoMain', |
| 436 'MojoShellActivity', | 427 'MojoShellActivity', |
| 437 'MojoShellApplication', | 428 'MojoShellApplication', |
| 438 'chromium', | 429 'chromium', |
| 439 ] | 430 ] |
| 440 subprocess.call(['adb', 'logcat', '-d', '-s'] + TAGS) | 431 subprocess.call([ADB_PATH, 'logcat', '-d', '-s'] + TAGS) |
| 441 | 432 |
| 442 def _pull_system_libraries(self, system_libs_root): | 433 def _pull_system_libraries(self, system_libs_root): |
| 443 # Pull down the system libraries this pid has already mapped in. | 434 # Pull down the system libraries this pid has already mapped in. |
| 444 # TODO(eseidel): This does not handle dynamic loads. | 435 # TODO(eseidel): This does not handle dynamic loads. |
| 445 library_cacher_path = os.path.join( | 436 library_cacher_path = os.path.join( |
| 446 self.paths.sky_tools_directory, 'android_library_cacher.py') | 437 self.paths.sky_tools_directory, 'android_library_cacher.py') |
| 447 subprocess.call([ | 438 subprocess.call([ |
| 448 library_cacher_path, system_libs_root, self.pids['mojo_shell_pid'] | 439 library_cacher_path, system_libs_root, self.pids['mojo_shell_pid'] |
| 449 ]) | 440 ]) |
| 450 | 441 |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 499 | 490 |
| 500 # TODO(eseidel): We need to look up the toolchain somehow? | 491 # TODO(eseidel): We need to look up the toolchain somehow? |
| 501 gdb_path = os.path.join(SRC_ROOT, 'third_party/android_tools/ndk/' | 492 gdb_path = os.path.join(SRC_ROOT, 'third_party/android_tools/ndk/' |
| 502 'toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/' | 493 'toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/' |
| 503 'bin/arm-linux-androideabi-gdb') | 494 'bin/arm-linux-androideabi-gdb') |
| 504 | 495 |
| 505 # Set solib-search-path after letting android modify symbol_search_paths | 496 # Set solib-search-path after letting android modify symbol_search_paths |
| 506 eval_commands.append( | 497 eval_commands.append( |
| 507 'set solib-search-path %s' % ':'.join(symbol_search_paths)) | 498 'set solib-search-path %s' % ':'.join(symbol_search_paths)) |
| 508 | 499 |
| 509 exec_command = ['/usr/bin/strace', '-o', 'trace.txt', gdb_path] | 500 exec_command = [gdb_path] |
| 510 for command in eval_commands: | 501 for command in eval_commands: |
| 511 exec_command += ['--eval-command', command] | 502 exec_command += ['--eval-command', command] |
| 512 | 503 |
| 513 print " ".join(exec_command) | 504 print " ".join(exec_command) |
| 514 | 505 |
| 515 # Write out our pid file before we exec ourselves. | 506 # Write out our pid file before we exec ourselves. |
| 516 self._write_pid_file(PID_FILE_PATH, self.pids) | 507 self._write_pid_file(PID_FILE_PATH, self.pids) |
| 517 | 508 |
| 518 # Exec gdb directly to avoid python intercepting symbols, etc. | 509 # Exec gdb directly to avoid python intercepting symbols, etc. |
| 519 os.execv(exec_command[0], exec_command) | 510 os.execv(exec_command[0], exec_command) |
| 520 | 511 |
| 521 def print_crash_command(self, args): | 512 def print_crash_command(self, args): |
| 522 logcat_cmd = ['adb', 'logcat', '-d'] | 513 logcat_cmd = [ADB_PATH, 'logcat', '-d'] |
| 523 logcat = subprocess.Popen(logcat_cmd, stdout=subprocess.PIPE) | 514 logcat = subprocess.Popen(logcat_cmd, stdout=subprocess.PIPE) |
| 524 | 515 |
| 525 stack_path = os.path.join(SRC_ROOT, | 516 stack_path = os.path.join(SRC_ROOT, |
| 526 'tools', 'android_stack_parser', 'stack') | 517 'tools', 'android_stack_parser', 'stack') |
| 527 stack = subprocess.Popen([stack_path, '-'], stdin=logcat.stdout) | 518 stack = subprocess.Popen([stack_path, '-'], stdin=logcat.stdout) |
| 528 logcat.wait() | 519 logcat.wait() |
| 529 stack.wait() | 520 stack.wait() |
| 530 | 521 |
| 531 def pids_command(self, args): | 522 def pids_command(self, args): |
| 532 print json.dumps(self.pids, indent=1) | 523 print json.dumps(self.pids, indent=1) |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 598 load_parser.set_defaults(func=self.load_command) | 589 load_parser.set_defaults(func=self.load_command) |
| 599 | 590 |
| 600 args = parser.parse_args() | 591 args = parser.parse_args() |
| 601 args.func(args) | 592 args.func(args) |
| 602 | 593 |
| 603 self._write_pid_file(PID_FILE_PATH, self.pids) | 594 self._write_pid_file(PID_FILE_PATH, self.pids) |
| 604 | 595 |
| 605 | 596 |
| 606 if __name__ == '__main__': | 597 if __name__ == '__main__': |
| 607 SkyDebugger().main() | 598 SkyDebugger().main() |
| OLD | NEW |