Am.java revision fd1ce8d5a7aa1ec6c7324b171f7e7a15a95f8759
1/* 2** 3** Copyright 2007, The Android Open Source Project 4** 5** Licensed under the Apache License, Version 2.0 (the "License"); 6** you may not use this file except in compliance with the License. 7** You may obtain a copy of the License at 8** 9** http://www.apache.org/licenses/LICENSE-2.0 10** 11** Unless required by applicable law or agreed to in writing, software 12** distributed under the License is distributed on an "AS IS" BASIS, 13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14** See the License for the specific language governing permissions and 15** limitations under the License. 16*/ 17 18 19package com.android.commands.am; 20 21import android.app.ActivityManager; 22import android.app.ActivityManager.StackBoxInfo; 23import android.app.ActivityManagerNative; 24import android.app.IActivityController; 25import android.app.IActivityManager; 26import android.app.IInstrumentationWatcher; 27import android.app.Instrumentation; 28import android.app.UiAutomationConnection; 29import android.content.ComponentName; 30import android.content.IIntentReceiver; 31import android.content.Intent; 32import android.content.pm.IPackageManager; 33import android.content.pm.ResolveInfo; 34import android.net.Uri; 35import android.os.Binder; 36import android.os.Bundle; 37import android.os.ParcelFileDescriptor; 38import android.os.RemoteException; 39import android.os.ServiceManager; 40import android.os.SystemProperties; 41import android.os.UserHandle; 42import android.util.AndroidException; 43import android.view.IWindowManager; 44import com.android.internal.os.BaseCommand; 45 46import java.io.BufferedReader; 47import java.io.File; 48import java.io.FileNotFoundException; 49import java.io.IOException; 50import java.io.InputStreamReader; 51import java.io.PrintStream; 52import java.net.URISyntaxException; 53import java.util.HashSet; 54import java.util.List; 55 56public class Am extends BaseCommand { 57 58 private IActivityManager mAm; 59 60 private int mStartFlags = 0; 61 private boolean mWaitOption = false; 62 private boolean mStopOption = false; 63 64 private int mRepeat = 0; 65 private int mUserId; 66 private String mReceiverPermission; 67 68 private String mProfileFile; 69 70 /** 71 * Command-line entry point. 72 * 73 * @param args The command-line arguments 74 */ 75 public static void main(String[] args) { 76 (new Am()).run(args); 77 } 78 79 @Override 80 public void onShowUsage(PrintStream out) { 81 out.println( 82 "usage: am [subcommand] [options]\n" + 83 "usage: am start [-D] [-W] [-P <FILE>] [--start-profiler <FILE>]\n" + 84 " [--R COUNT] [-S] [--opengl-trace]\n" + 85 " [--user <USER_ID> | current] <INTENT>\n" + 86 " am startservice [--user <USER_ID> | current] <INTENT>\n" + 87 " am force-stop [--user <USER_ID> | all | current] <PACKAGE>\n" + 88 " am kill [--user <USER_ID> | all | current] <PACKAGE>\n" + 89 " am kill-all\n" + 90 " am broadcast [--user <USER_ID> | all | current] <INTENT>\n" + 91 " am instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]\n" + 92 " [--user <USER_ID> | current]\n" + 93 " [--no-window-animation] <COMPONENT>\n" + 94 " am profile start [--user <USER_ID> current] <PROCESS> <FILE>\n" + 95 " am profile stop [--user <USER_ID> current] [<PROCESS>]\n" + 96 " am dumpheap [--user <USER_ID> current] [-n] <PROCESS> <FILE>\n" + 97 " am set-debug-app [-w] [--persistent] <PACKAGE>\n" + 98 " am clear-debug-app\n" + 99 " am monitor [--gdb <port>]\n" + 100 " am hang [--allow-restart]\n" + 101 " am screen-compat [on|off] <PACKAGE>\n" + 102 " am to-uri [INTENT]\n" + 103 " am to-intent-uri [INTENT]\n" + 104 " am switch-user <USER_ID>\n" + 105 " am stop-user <USER_ID>\n" + 106 " am stack create <TASK_ID> <RELATIVE_STACK_BOX_ID> <POSITION> <WEIGHT>\n" + 107 " am stack movetask <STACK_ID> <TASK_ID> [true|false]\n" + 108 " am stack resize <STACK_ID> <WEIGHT>\n" + 109 " am stack boxes\n" + 110 " am stack box <STACK_BOX_ID>\n" + 111 "\n" + 112 "am start: start an Activity. Options are:\n" + 113 " -D: enable debugging\n" + 114 " -W: wait for launch to complete\n" + 115 " --start-profiler <FILE>: start profiler and send results to <FILE>\n" + 116 " -P <FILE>: like above, but profiling stops when app goes idle\n" + 117 " -R: repeat the activity launch <COUNT> times. Prior to each repeat,\n" + 118 " the top activity will be finished.\n" + 119 " -S: force stop the target app before starting the activity\n" + 120 " --opengl-trace: enable tracing of OpenGL functions\n" + 121 " --user <USER_ID> | current: Specify which user to run as; if not\n" + 122 " specified then run as the current user.\n" + 123 "\n" + 124 "am startservice: start a Service. Options are:\n" + 125 " --user <USER_ID> | current: Specify which user to run as; if not\n" + 126 " specified then run as the current user.\n" + 127 "\n" + 128 "am force-stop: force stop everything associated with <PACKAGE>.\n" + 129 " --user <USER_ID> | all | current: Specify user to force stop;\n" + 130 " all users if not specified.\n" + 131 "\n" + 132 "am kill: Kill all processes associated with <PACKAGE>. Only kills.\n" + 133 " processes that are safe to kill -- that is, will not impact the user\n" + 134 " experience.\n" + 135 " --user <USER_ID> | all | current: Specify user whose processes to kill;\n" + 136 " all users if not specified.\n" + 137 "\n" + 138 "am kill-all: Kill all background processes.\n" + 139 "\n" + 140 "am broadcast: send a broadcast Intent. Options are:\n" + 141 " --user <USER_ID> | all | current: Specify which user to send to; if not\n" + 142 " specified then send to all users.\n" + 143 " --receiver-permission <PERMISSION>: Require receiver to hold permission.\n" + 144 "\n" + 145 "am instrument: start an Instrumentation. Typically this target <COMPONENT>\n" + 146 " is the form <TEST_PACKAGE>/<RUNNER_CLASS>. Options are:\n" + 147 " -r: print raw results (otherwise decode REPORT_KEY_STREAMRESULT). Use with\n" + 148 " [-e perf true] to generate raw output for performance measurements.\n" + 149 " -e <NAME> <VALUE>: set argument <NAME> to <VALUE>. For test runners a\n" + 150 " common form is [-e <testrunner_flag> <value>[,<value>...]].\n" + 151 " -p <FILE>: write profiling data to <FILE>\n" + 152 " -w: wait for instrumentation to finish before returning. Required for\n" + 153 " test runners.\n" + 154 " --user <USER_ID> | current: Specify user instrumentation runs in;\n" + 155 " current user if not specified.\n" + 156 " --no-window-animation: turn off window animations will running.\n" + 157 "\n" + 158 "am profile: start and stop profiler on a process. The given <PROCESS> argument\n" + 159 " may be either a process name or pid. Options are:\n" + 160 " --user <USER_ID> | current: When supplying a process name,\n" + 161 " specify user of process to profile; uses current user if not specified.\n" + 162 "\n" + 163 "am dumpheap: dump the heap of a process. The given <PROCESS> argument may\n" + 164 " be either a process name or pid. Options are:\n" + 165 " -n: dump native heap instead of managed heap\n" + 166 " --user <USER_ID> | current: When supplying a process name,\n" + 167 " specify user of process to dump; uses current user if not specified.\n" + 168 "\n" + 169 "am set-debug-app: set application <PACKAGE> to debug. Options are:\n" + 170 " -w: wait for debugger when application starts\n" + 171 " --persistent: retain this value\n" + 172 "\n" + 173 "am clear-debug-app: clear the previously set-debug-app.\n" + 174 "\n" + 175 "am bug-report: request bug report generation; will launch UI\n" + 176 " when done to select where it should be delivered.\n" + 177 "\n" + 178 "am monitor: start monitoring for crashes or ANRs.\n" + 179 " --gdb: start gdbserv on the given port at crash/ANR\n" + 180 "\n" + 181 "am hang: hang the system.\n" + 182 " --allow-restart: allow watchdog to perform normal system restart\n" + 183 "\n" + 184 "am screen-compat: control screen compatibility mode of <PACKAGE>.\n" + 185 "\n" + 186 "am to-uri: print the given Intent specification as a URI.\n" + 187 "\n" + 188 "am to-intent-uri: print the given Intent specification as an intent: URI.\n" + 189 "\n" + 190 "am switch-user: switch to put USER_ID in the foreground, starting\n" + 191 " execution of that user if it is currently stopped.\n" + 192 "\n" + 193 "am stop-user: stop execution of USER_ID, not allowing it to run any\n" + 194 " code until a later explicit switch to it.\n" + 195 "\n" + 196 "am stack create: create a new stack relative to an existing one.\n" + 197 " <TASK_ID>: the task to populate the new stack with. Must exist.\n" + 198 " <RELATIVE_STACK_BOX_ID>: existing stack box's id.\n" + 199 " <POSITION>: 0: before <RELATIVE_STACK_BOX_ID>, per RTL/LTR configuration,\n" + 200 " 1: after <RELATIVE_STACK_BOX_ID>, per RTL/LTR configuration,\n" + 201 " 2: to left of <RELATIVE_STACK_BOX_ID>,\n" + 202 " 3: to right of <RELATIVE_STACK_BOX_ID>," + 203 " 4: above <RELATIVE_STACK_BOX_ID>, 5: below <RELATIVE_STACK_BOX_ID>\n" + 204 " <WEIGHT>: float between 0.2 and 0.8 inclusive.\n" + 205 "\n" + 206 "am stack movetask: move <TASK_ID> from its current stack to the top (true) or" + 207 " bottom (false) of <STACK_ID>.\n" + 208 "\n" + 209 "am stack resize: change <STACK_ID> relative size to new <WEIGHT>.\n" + 210 "\n" + 211 "am stack boxes: list the hierarchy of stack boxes and their contents.\n" + 212 "\n" + 213 "am stack box: list the hierarchy of stack boxes rooted at <STACK_BOX_ID>.\n" + 214 "\n" + 215 "<INTENT> specifications include these flags and arguments:\n" + 216 " [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" + 217 " [-c <CATEGORY> [-c <CATEGORY>] ...]\n" + 218 " [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]\n" + 219 " [--esn <EXTRA_KEY> ...]\n" + 220 " [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]\n" + 221 " [--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]\n" + 222 " [--el <EXTRA_KEY> <EXTRA_LONG_VALUE> ...]\n" + 223 " [--ef <EXTRA_KEY> <EXTRA_FLOAT_VALUE> ...]\n" + 224 " [--eu <EXTRA_KEY> <EXTRA_URI_VALUE> ...]\n" + 225 " [--ecn <EXTRA_KEY> <EXTRA_COMPONENT_NAME_VALUE>]\n" + 226 " [--eia <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]]\n" + 227 " [--ela <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]\n" + 228 " [--efa <EXTRA_KEY> <EXTRA_FLOAT_VALUE>[,<EXTRA_FLOAT_VALUE...]]\n" + 229 " [-n <COMPONENT>] [-f <FLAGS>]\n" + 230 " [--grant-read-uri-permission] [--grant-write-uri-permission]\n" + 231 " [--debug-log-resolution] [--exclude-stopped-packages]\n" + 232 " [--include-stopped-packages]\n" + 233 " [--activity-brought-to-front] [--activity-clear-top]\n" + 234 " [--activity-clear-when-task-reset] [--activity-exclude-from-recents]\n" + 235 " [--activity-launched-from-history] [--activity-multiple-task]\n" + 236 " [--activity-no-animation] [--activity-no-history]\n" + 237 " [--activity-no-user-action] [--activity-previous-is-top]\n" + 238 " [--activity-reorder-to-front] [--activity-reset-task-if-needed]\n" + 239 " [--activity-single-top] [--activity-clear-task]\n" + 240 " [--activity-task-on-home]\n" + 241 " [--receiver-registered-only] [--receiver-replace-pending]\n" + 242 " [--selector]\n" + 243 " [<URI> | <PACKAGE> | <COMPONENT>]\n" 244 ); 245 } 246 247 @Override 248 public void onRun() throws Exception { 249 250 mAm = ActivityManagerNative.getDefault(); 251 if (mAm == null) { 252 System.err.println(NO_SYSTEM_ERROR_CODE); 253 throw new AndroidException("Can't connect to activity manager; is the system running?"); 254 } 255 256 String op = nextArgRequired(); 257 258 if (op.equals("start")) { 259 runStart(); 260 } else if (op.equals("startservice")) { 261 runStartService(); 262 } else if (op.equals("force-stop")) { 263 runForceStop(); 264 } else if (op.equals("kill")) { 265 runKill(); 266 } else if (op.equals("kill-all")) { 267 runKillAll(); 268 } else if (op.equals("instrument")) { 269 runInstrument(); 270 } else if (op.equals("broadcast")) { 271 sendBroadcast(); 272 } else if (op.equals("profile")) { 273 runProfile(); 274 } else if (op.equals("dumpheap")) { 275 runDumpHeap(); 276 } else if (op.equals("set-debug-app")) { 277 runSetDebugApp(); 278 } else if (op.equals("clear-debug-app")) { 279 runClearDebugApp(); 280 } else if (op.equals("bug-report")) { 281 runBugReport(); 282 } else if (op.equals("monitor")) { 283 runMonitor(); 284 } else if (op.equals("hang")) { 285 runHang(); 286 } else if (op.equals("screen-compat")) { 287 runScreenCompat(); 288 } else if (op.equals("to-uri")) { 289 runToUri(false); 290 } else if (op.equals("to-intent-uri")) { 291 runToUri(true); 292 } else if (op.equals("switch-user")) { 293 runSwitchUser(); 294 } else if (op.equals("stop-user")) { 295 runStopUser(); 296 } else if (op.equals("stack")) { 297 runStack(); 298 } else { 299 showError("Error: unknown command '" + op + "'"); 300 } 301 } 302 303 int parseUserArg(String arg) { 304 int userId; 305 if ("all".equals(arg)) { 306 userId = UserHandle.USER_ALL; 307 } else if ("current".equals(arg) || "cur".equals(arg)) { 308 userId = UserHandle.USER_CURRENT; 309 } else { 310 userId = Integer.parseInt(arg); 311 } 312 return userId; 313 } 314 315 private Intent makeIntent(int defUser) throws URISyntaxException { 316 Intent intent = new Intent(); 317 Intent baseIntent = intent; 318 boolean hasIntentInfo = false; 319 320 mStartFlags = 0; 321 mWaitOption = false; 322 mStopOption = false; 323 mRepeat = 0; 324 mProfileFile = null; 325 mUserId = defUser; 326 Uri data = null; 327 String type = null; 328 329 String opt; 330 while ((opt=nextOption()) != null) { 331 if (opt.equals("-a")) { 332 intent.setAction(nextArgRequired()); 333 if (intent == baseIntent) { 334 hasIntentInfo = true; 335 } 336 } else if (opt.equals("-d")) { 337 data = Uri.parse(nextArgRequired()); 338 if (intent == baseIntent) { 339 hasIntentInfo = true; 340 } 341 } else if (opt.equals("-t")) { 342 type = nextArgRequired(); 343 if (intent == baseIntent) { 344 hasIntentInfo = true; 345 } 346 } else if (opt.equals("-c")) { 347 intent.addCategory(nextArgRequired()); 348 if (intent == baseIntent) { 349 hasIntentInfo = true; 350 } 351 } else if (opt.equals("-e") || opt.equals("--es")) { 352 String key = nextArgRequired(); 353 String value = nextArgRequired(); 354 intent.putExtra(key, value); 355 } else if (opt.equals("--esn")) { 356 String key = nextArgRequired(); 357 intent.putExtra(key, (String) null); 358 } else if (opt.equals("--ei")) { 359 String key = nextArgRequired(); 360 String value = nextArgRequired(); 361 intent.putExtra(key, Integer.valueOf(value)); 362 } else if (opt.equals("--eu")) { 363 String key = nextArgRequired(); 364 String value = nextArgRequired(); 365 intent.putExtra(key, Uri.parse(value)); 366 } else if (opt.equals("--ecn")) { 367 String key = nextArgRequired(); 368 String value = nextArgRequired(); 369 ComponentName cn = ComponentName.unflattenFromString(value); 370 if (cn == null) throw new IllegalArgumentException("Bad component name: " + value); 371 intent.putExtra(key, cn); 372 } else if (opt.equals("--eia")) { 373 String key = nextArgRequired(); 374 String value = nextArgRequired(); 375 String[] strings = value.split(","); 376 int[] list = new int[strings.length]; 377 for (int i = 0; i < strings.length; i++) { 378 list[i] = Integer.valueOf(strings[i]); 379 } 380 intent.putExtra(key, list); 381 } else if (opt.equals("--el")) { 382 String key = nextArgRequired(); 383 String value = nextArgRequired(); 384 intent.putExtra(key, Long.valueOf(value)); 385 } else if (opt.equals("--ela")) { 386 String key = nextArgRequired(); 387 String value = nextArgRequired(); 388 String[] strings = value.split(","); 389 long[] list = new long[strings.length]; 390 for (int i = 0; i < strings.length; i++) { 391 list[i] = Long.valueOf(strings[i]); 392 } 393 intent.putExtra(key, list); 394 hasIntentInfo = true; 395 } else if (opt.equals("--ef")) { 396 String key = nextArgRequired(); 397 String value = nextArgRequired(); 398 intent.putExtra(key, Float.valueOf(value)); 399 hasIntentInfo = true; 400 } else if (opt.equals("--efa")) { 401 String key = nextArgRequired(); 402 String value = nextArgRequired(); 403 String[] strings = value.split(","); 404 float[] list = new float[strings.length]; 405 for (int i = 0; i < strings.length; i++) { 406 list[i] = Float.valueOf(strings[i]); 407 } 408 intent.putExtra(key, list); 409 hasIntentInfo = true; 410 } else if (opt.equals("--ez")) { 411 String key = nextArgRequired(); 412 String value = nextArgRequired(); 413 intent.putExtra(key, Boolean.valueOf(value)); 414 } else if (opt.equals("-n")) { 415 String str = nextArgRequired(); 416 ComponentName cn = ComponentName.unflattenFromString(str); 417 if (cn == null) throw new IllegalArgumentException("Bad component name: " + str); 418 intent.setComponent(cn); 419 if (intent == baseIntent) { 420 hasIntentInfo = true; 421 } 422 } else if (opt.equals("-f")) { 423 String str = nextArgRequired(); 424 intent.setFlags(Integer.decode(str).intValue()); 425 } else if (opt.equals("--grant-read-uri-permission")) { 426 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 427 } else if (opt.equals("--grant-write-uri-permission")) { 428 intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); 429 } else if (opt.equals("--exclude-stopped-packages")) { 430 intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES); 431 } else if (opt.equals("--include-stopped-packages")) { 432 intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); 433 } else if (opt.equals("--debug-log-resolution")) { 434 intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION); 435 } else if (opt.equals("--activity-brought-to-front")) { 436 intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT); 437 } else if (opt.equals("--activity-clear-top")) { 438 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 439 } else if (opt.equals("--activity-clear-when-task-reset")) { 440 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); 441 } else if (opt.equals("--activity-exclude-from-recents")) { 442 intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); 443 } else if (opt.equals("--activity-launched-from-history")) { 444 intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY); 445 } else if (opt.equals("--activity-multiple-task")) { 446 intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); 447 } else if (opt.equals("--activity-no-animation")) { 448 intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); 449 } else if (opt.equals("--activity-no-history")) { 450 intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); 451 } else if (opt.equals("--activity-no-user-action")) { 452 intent.addFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION); 453 } else if (opt.equals("--activity-previous-is-top")) { 454 intent.addFlags(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP); 455 } else if (opt.equals("--activity-reorder-to-front")) { 456 intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); 457 } else if (opt.equals("--activity-reset-task-if-needed")) { 458 intent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); 459 } else if (opt.equals("--activity-single-top")) { 460 intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); 461 } else if (opt.equals("--activity-clear-task")) { 462 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); 463 } else if (opt.equals("--activity-task-on-home")) { 464 intent.addFlags(Intent.FLAG_ACTIVITY_TASK_ON_HOME); 465 } else if (opt.equals("--receiver-registered-only")) { 466 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); 467 } else if (opt.equals("--receiver-replace-pending")) { 468 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); 469 } else if (opt.equals("--selector")) { 470 intent.setDataAndType(data, type); 471 intent = new Intent(); 472 } else if (opt.equals("-D")) { 473 mStartFlags |= ActivityManager.START_FLAG_DEBUG; 474 } else if (opt.equals("-W")) { 475 mWaitOption = true; 476 } else if (opt.equals("-P")) { 477 mProfileFile = nextArgRequired(); 478 mStartFlags |= ActivityManager.START_FLAG_AUTO_STOP_PROFILER; 479 } else if (opt.equals("--start-profiler")) { 480 mProfileFile = nextArgRequired(); 481 mStartFlags &= ~ActivityManager.START_FLAG_AUTO_STOP_PROFILER; 482 } else if (opt.equals("-R")) { 483 mRepeat = Integer.parseInt(nextArgRequired()); 484 } else if (opt.equals("-S")) { 485 mStopOption = true; 486 } else if (opt.equals("--opengl-trace")) { 487 mStartFlags |= ActivityManager.START_FLAG_OPENGL_TRACES; 488 } else if (opt.equals("--user")) { 489 mUserId = parseUserArg(nextArgRequired()); 490 } else if (opt.equals("--receiver-permission")) { 491 mReceiverPermission = nextArgRequired(); 492 } else { 493 System.err.println("Error: Unknown option: " + opt); 494 return null; 495 } 496 } 497 intent.setDataAndType(data, type); 498 499 final boolean hasSelector = intent != baseIntent; 500 if (hasSelector) { 501 // A selector was specified; fix up. 502 baseIntent.setSelector(intent); 503 intent = baseIntent; 504 } 505 506 String arg = nextArg(); 507 baseIntent = null; 508 if (arg == null) { 509 if (hasSelector) { 510 // If a selector has been specified, and no arguments 511 // have been supplied for the main Intent, then we can 512 // assume it is ACTION_MAIN CATEGORY_LAUNCHER; we don't 513 // need to have a component name specified yet, the 514 // selector will take care of that. 515 baseIntent = new Intent(Intent.ACTION_MAIN); 516 baseIntent.addCategory(Intent.CATEGORY_LAUNCHER); 517 } 518 } else if (arg.indexOf(':') >= 0) { 519 // The argument is a URI. Fully parse it, and use that result 520 // to fill in any data not specified so far. 521 baseIntent = Intent.parseUri(arg, Intent.URI_INTENT_SCHEME); 522 } else if (arg.indexOf('/') >= 0) { 523 // The argument is a component name. Build an Intent to launch 524 // it. 525 baseIntent = new Intent(Intent.ACTION_MAIN); 526 baseIntent.addCategory(Intent.CATEGORY_LAUNCHER); 527 baseIntent.setComponent(ComponentName.unflattenFromString(arg)); 528 } else { 529 // Assume the argument is a package name. 530 baseIntent = new Intent(Intent.ACTION_MAIN); 531 baseIntent.addCategory(Intent.CATEGORY_LAUNCHER); 532 baseIntent.setPackage(arg); 533 } 534 if (baseIntent != null) { 535 Bundle extras = intent.getExtras(); 536 intent.replaceExtras((Bundle)null); 537 Bundle uriExtras = baseIntent.getExtras(); 538 baseIntent.replaceExtras((Bundle)null); 539 if (intent.getAction() != null && baseIntent.getCategories() != null) { 540 HashSet<String> cats = new HashSet<String>(baseIntent.getCategories()); 541 for (String c : cats) { 542 baseIntent.removeCategory(c); 543 } 544 } 545 intent.fillIn(baseIntent, Intent.FILL_IN_COMPONENT | Intent.FILL_IN_SELECTOR); 546 if (extras == null) { 547 extras = uriExtras; 548 } else if (uriExtras != null) { 549 uriExtras.putAll(extras); 550 extras = uriExtras; 551 } 552 intent.replaceExtras(extras); 553 hasIntentInfo = true; 554 } 555 556 if (!hasIntentInfo) throw new IllegalArgumentException("No intent supplied"); 557 return intent; 558 } 559 560 private void runStartService() throws Exception { 561 Intent intent = makeIntent(UserHandle.USER_CURRENT); 562 if (mUserId == UserHandle.USER_ALL) { 563 System.err.println("Error: Can't start activity with user 'all'"); 564 return; 565 } 566 System.out.println("Starting service: " + intent); 567 ComponentName cn = mAm.startService(null, intent, intent.getType(), mUserId); 568 if (cn == null) { 569 System.err.println("Error: Not found; no service started."); 570 } else if (cn.getPackageName().equals("!")) { 571 System.err.println("Error: Requires permission " + cn.getClassName()); 572 } else if (cn.getPackageName().equals("!!")) { 573 System.err.println("Error: " + cn.getClassName()); 574 } 575 } 576 577 private void runStart() throws Exception { 578 Intent intent = makeIntent(UserHandle.USER_CURRENT); 579 580 if (mUserId == UserHandle.USER_ALL) { 581 System.err.println("Error: Can't start service with user 'all'"); 582 return; 583 } 584 585 String mimeType = intent.getType(); 586 if (mimeType == null && intent.getData() != null 587 && "content".equals(intent.getData().getScheme())) { 588 mimeType = mAm.getProviderMimeType(intent.getData(), mUserId); 589 } 590 591 do { 592 if (mStopOption) { 593 String packageName; 594 if (intent.getComponent() != null) { 595 packageName = intent.getComponent().getPackageName(); 596 } else { 597 IPackageManager pm = IPackageManager.Stub.asInterface( 598 ServiceManager.getService("package")); 599 if (pm == null) { 600 System.err.println("Error: Package manager not running; aborting"); 601 return; 602 } 603 List<ResolveInfo> activities = pm.queryIntentActivities(intent, mimeType, 0, 604 mUserId); 605 if (activities == null || activities.size() <= 0) { 606 System.err.println("Error: Intent does not match any activities: " 607 + intent); 608 return; 609 } else if (activities.size() > 1) { 610 System.err.println("Error: Intent matches multiple activities; can't stop: " 611 + intent); 612 return; 613 } 614 packageName = activities.get(0).activityInfo.packageName; 615 } 616 System.out.println("Stopping: " + packageName); 617 mAm.forceStopPackage(packageName, mUserId); 618 Thread.sleep(250); 619 } 620 621 System.out.println("Starting: " + intent); 622 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 623 624 ParcelFileDescriptor fd = null; 625 626 if (mProfileFile != null) { 627 try { 628 fd = ParcelFileDescriptor.open( 629 new File(mProfileFile), 630 ParcelFileDescriptor.MODE_CREATE | 631 ParcelFileDescriptor.MODE_TRUNCATE | 632 ParcelFileDescriptor.MODE_READ_WRITE); 633 } catch (FileNotFoundException e) { 634 System.err.println("Error: Unable to open file: " + mProfileFile); 635 return; 636 } 637 } 638 639 IActivityManager.WaitResult result = null; 640 int res; 641 if (mWaitOption) { 642 result = mAm.startActivityAndWait(null, null, intent, mimeType, 643 null, null, 0, mStartFlags, mProfileFile, fd, null, mUserId); 644 res = result.result; 645 } else { 646 res = mAm.startActivityAsUser(null, null, intent, mimeType, 647 null, null, 0, mStartFlags, mProfileFile, fd, null, mUserId); 648 } 649 PrintStream out = mWaitOption ? System.out : System.err; 650 boolean launched = false; 651 switch (res) { 652 case ActivityManager.START_SUCCESS: 653 launched = true; 654 break; 655 case ActivityManager.START_SWITCHES_CANCELED: 656 launched = true; 657 out.println( 658 "Warning: Activity not started because the " 659 + " current activity is being kept for the user."); 660 break; 661 case ActivityManager.START_DELIVERED_TO_TOP: 662 launched = true; 663 out.println( 664 "Warning: Activity not started, intent has " 665 + "been delivered to currently running " 666 + "top-most instance."); 667 break; 668 case ActivityManager.START_RETURN_INTENT_TO_CALLER: 669 launched = true; 670 out.println( 671 "Warning: Activity not started because intent " 672 + "should be handled by the caller"); 673 break; 674 case ActivityManager.START_TASK_TO_FRONT: 675 launched = true; 676 out.println( 677 "Warning: Activity not started, its current " 678 + "task has been brought to the front"); 679 break; 680 case ActivityManager.START_INTENT_NOT_RESOLVED: 681 out.println( 682 "Error: Activity not started, unable to " 683 + "resolve " + intent.toString()); 684 break; 685 case ActivityManager.START_CLASS_NOT_FOUND: 686 out.println(NO_CLASS_ERROR_CODE); 687 out.println("Error: Activity class " + 688 intent.getComponent().toShortString() 689 + " does not exist."); 690 break; 691 case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT: 692 out.println( 693 "Error: Activity not started, you requested to " 694 + "both forward and receive its result"); 695 break; 696 case ActivityManager.START_PERMISSION_DENIED: 697 out.println( 698 "Error: Activity not started, you do not " 699 + "have permission to access it."); 700 break; 701 default: 702 out.println( 703 "Error: Activity not started, unknown error code " + res); 704 break; 705 } 706 if (mWaitOption && launched) { 707 if (result == null) { 708 result = new IActivityManager.WaitResult(); 709 result.who = intent.getComponent(); 710 } 711 System.out.println("Status: " + (result.timeout ? "timeout" : "ok")); 712 if (result.who != null) { 713 System.out.println("Activity: " + result.who.flattenToShortString()); 714 } 715 if (result.thisTime >= 0) { 716 System.out.println("ThisTime: " + result.thisTime); 717 } 718 if (result.totalTime >= 0) { 719 System.out.println("TotalTime: " + result.totalTime); 720 } 721 System.out.println("Complete"); 722 } 723 mRepeat--; 724 if (mRepeat > 1) { 725 mAm.unhandledBack(); 726 } 727 } while (mRepeat > 1); 728 } 729 730 private void runForceStop() throws Exception { 731 int userId = UserHandle.USER_ALL; 732 733 String opt; 734 while ((opt=nextOption()) != null) { 735 if (opt.equals("--user")) { 736 userId = parseUserArg(nextArgRequired()); 737 } else { 738 System.err.println("Error: Unknown option: " + opt); 739 return; 740 } 741 } 742 mAm.forceStopPackage(nextArgRequired(), userId); 743 } 744 745 private void runKill() throws Exception { 746 int userId = UserHandle.USER_ALL; 747 748 String opt; 749 while ((opt=nextOption()) != null) { 750 if (opt.equals("--user")) { 751 userId = parseUserArg(nextArgRequired()); 752 } else { 753 System.err.println("Error: Unknown option: " + opt); 754 return; 755 } 756 } 757 mAm.killBackgroundProcesses(nextArgRequired(), userId); 758 } 759 760 private void runKillAll() throws Exception { 761 mAm.killAllBackgroundProcesses(); 762 } 763 764 private void sendBroadcast() throws Exception { 765 Intent intent = makeIntent(UserHandle.USER_ALL); 766 IntentReceiver receiver = new IntentReceiver(); 767 System.out.println("Broadcasting: " + intent); 768 mAm.broadcastIntent(null, intent, null, receiver, 0, null, null, mReceiverPermission, 769 android.app.AppOpsManager.OP_NONE, true, false, mUserId); 770 receiver.waitForFinish(); 771 } 772 773 private void runInstrument() throws Exception { 774 String profileFile = null; 775 boolean wait = false; 776 boolean rawMode = false; 777 boolean no_window_animation = false; 778 int userId = UserHandle.USER_CURRENT; 779 Bundle args = new Bundle(); 780 String argKey = null, argValue = null; 781 IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.getService("window")); 782 783 String opt; 784 while ((opt=nextOption()) != null) { 785 if (opt.equals("-p")) { 786 profileFile = nextArgRequired(); 787 } else if (opt.equals("-w")) { 788 wait = true; 789 } else if (opt.equals("-r")) { 790 rawMode = true; 791 } else if (opt.equals("-e")) { 792 argKey = nextArgRequired(); 793 argValue = nextArgRequired(); 794 args.putString(argKey, argValue); 795 } else if (opt.equals("--no_window_animation") 796 || opt.equals("--no-window-animation")) { 797 no_window_animation = true; 798 } else if (opt.equals("--user")) { 799 userId = parseUserArg(nextArgRequired()); 800 } else { 801 System.err.println("Error: Unknown option: " + opt); 802 return; 803 } 804 } 805 806 if (userId == UserHandle.USER_ALL) { 807 System.err.println("Error: Can't start instrumentation with user 'all'"); 808 return; 809 } 810 811 String cnArg = nextArgRequired(); 812 ComponentName cn = ComponentName.unflattenFromString(cnArg); 813 if (cn == null) throw new IllegalArgumentException("Bad component name: " + cnArg); 814 815 InstrumentationWatcher watcher = null; 816 UiAutomationConnection connection = null; 817 if (wait) { 818 watcher = new InstrumentationWatcher(); 819 watcher.setRawOutput(rawMode); 820 connection = new UiAutomationConnection(); 821 } 822 823 float[] oldAnims = null; 824 if (no_window_animation) { 825 oldAnims = wm.getAnimationScales(); 826 wm.setAnimationScale(0, 0.0f); 827 wm.setAnimationScale(1, 0.0f); 828 } 829 830 if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher, connection, userId)) { 831 throw new AndroidException("INSTRUMENTATION_FAILED: " + cn.flattenToString()); 832 } 833 834 if (watcher != null) { 835 if (!watcher.waitForFinish()) { 836 System.out.println("INSTRUMENTATION_ABORTED: System has crashed."); 837 } 838 } 839 840 if (oldAnims != null) { 841 wm.setAnimationScales(oldAnims); 842 } 843 } 844 845 static void removeWallOption() { 846 String props = SystemProperties.get("dalvik.vm.extra-opts"); 847 if (props != null && props.contains("-Xprofile:wallclock")) { 848 props = props.replace("-Xprofile:wallclock", ""); 849 props = props.trim(); 850 SystemProperties.set("dalvik.vm.extra-opts", props); 851 } 852 } 853 854 private void runProfile() throws Exception { 855 String profileFile = null; 856 boolean start = false; 857 boolean wall = false; 858 int userId = UserHandle.USER_CURRENT; 859 int profileType = 0; 860 861 String process = null; 862 863 String cmd = nextArgRequired(); 864 865 if ("start".equals(cmd)) { 866 start = true; 867 String opt; 868 while ((opt=nextOption()) != null) { 869 if (opt.equals("--user")) { 870 userId = parseUserArg(nextArgRequired()); 871 } else if (opt.equals("--wall")) { 872 wall = true; 873 } else { 874 System.err.println("Error: Unknown option: " + opt); 875 return; 876 } 877 } 878 process = nextArgRequired(); 879 } else if ("stop".equals(cmd)) { 880 String opt; 881 while ((opt=nextOption()) != null) { 882 if (opt.equals("--user")) { 883 userId = parseUserArg(nextArgRequired()); 884 } else { 885 System.err.println("Error: Unknown option: " + opt); 886 return; 887 } 888 } 889 process = nextArg(); 890 } else { 891 // Compatibility with old syntax: process is specified first. 892 process = cmd; 893 cmd = nextArgRequired(); 894 if ("start".equals(cmd)) { 895 start = true; 896 } else if (!"stop".equals(cmd)) { 897 throw new IllegalArgumentException("Profile command " + process + " not valid"); 898 } 899 } 900 901 if (userId == UserHandle.USER_ALL) { 902 System.err.println("Error: Can't profile with user 'all'"); 903 return; 904 } 905 906 ParcelFileDescriptor fd = null; 907 908 if (start) { 909 profileFile = nextArgRequired(); 910 try { 911 fd = ParcelFileDescriptor.open( 912 new File(profileFile), 913 ParcelFileDescriptor.MODE_CREATE | 914 ParcelFileDescriptor.MODE_TRUNCATE | 915 ParcelFileDescriptor.MODE_READ_WRITE); 916 } catch (FileNotFoundException e) { 917 System.err.println("Error: Unable to open file: " + profileFile); 918 return; 919 } 920 } 921 922 try { 923 if (wall) { 924 // XXX doesn't work -- this needs to be set before booting. 925 String props = SystemProperties.get("dalvik.vm.extra-opts"); 926 if (props == null || !props.contains("-Xprofile:wallclock")) { 927 props = props + " -Xprofile:wallclock"; 928 //SystemProperties.set("dalvik.vm.extra-opts", props); 929 } 930 } else if (start) { 931 //removeWallOption(); 932 } 933 if (!mAm.profileControl(process, userId, start, profileFile, fd, profileType)) { 934 wall = false; 935 throw new AndroidException("PROFILE FAILED on process " + process); 936 } 937 } finally { 938 if (!wall) { 939 //removeWallOption(); 940 } 941 } 942 } 943 944 private void runDumpHeap() throws Exception { 945 boolean managed = true; 946 int userId = UserHandle.USER_CURRENT; 947 948 String opt; 949 while ((opt=nextOption()) != null) { 950 if (opt.equals("--user")) { 951 userId = parseUserArg(nextArgRequired()); 952 if (userId == UserHandle.USER_ALL) { 953 System.err.println("Error: Can't dump heap with user 'all'"); 954 return; 955 } 956 } else if (opt.equals("-n")) { 957 managed = false; 958 } else { 959 System.err.println("Error: Unknown option: " + opt); 960 return; 961 } 962 } 963 String process = nextArgRequired(); 964 String heapFile = nextArgRequired(); 965 ParcelFileDescriptor fd = null; 966 967 try { 968 File file = new File(heapFile); 969 file.delete(); 970 fd = ParcelFileDescriptor.open(file, 971 ParcelFileDescriptor.MODE_CREATE | 972 ParcelFileDescriptor.MODE_TRUNCATE | 973 ParcelFileDescriptor.MODE_READ_WRITE); 974 } catch (FileNotFoundException e) { 975 System.err.println("Error: Unable to open file: " + heapFile); 976 return; 977 } 978 979 if (!mAm.dumpHeap(process, userId, managed, heapFile, fd)) { 980 throw new AndroidException("HEAP DUMP FAILED on process " + process); 981 } 982 } 983 984 private void runSetDebugApp() throws Exception { 985 boolean wait = false; 986 boolean persistent = false; 987 988 String opt; 989 while ((opt=nextOption()) != null) { 990 if (opt.equals("-w")) { 991 wait = true; 992 } else if (opt.equals("--persistent")) { 993 persistent = true; 994 } else { 995 System.err.println("Error: Unknown option: " + opt); 996 return; 997 } 998 } 999 1000 String pkg = nextArgRequired(); 1001 mAm.setDebugApp(pkg, wait, persistent); 1002 } 1003 1004 private void runClearDebugApp() throws Exception { 1005 mAm.setDebugApp(null, false, true); 1006 } 1007 1008 private void runBugReport() throws Exception { 1009 mAm.requestBugReport(); 1010 System.out.println("Your lovely bug report is being created; please be patient."); 1011 } 1012 1013 private void runSwitchUser() throws Exception { 1014 String user = nextArgRequired(); 1015 mAm.switchUser(Integer.parseInt(user)); 1016 } 1017 1018 private void runStopUser() throws Exception { 1019 String user = nextArgRequired(); 1020 int res = mAm.stopUser(Integer.parseInt(user), null); 1021 if (res != ActivityManager.USER_OP_SUCCESS) { 1022 String txt = ""; 1023 switch (res) { 1024 case ActivityManager.USER_OP_IS_CURRENT: 1025 txt = " (Can't stop current user)"; 1026 break; 1027 case ActivityManager.USER_OP_UNKNOWN_USER: 1028 txt = " (Unknown user " + user + ")"; 1029 break; 1030 } 1031 System.err.println("Switch failed: " + res + txt); 1032 } 1033 } 1034 1035 class MyActivityController extends IActivityController.Stub { 1036 final String mGdbPort; 1037 1038 static final int STATE_NORMAL = 0; 1039 static final int STATE_CRASHED = 1; 1040 static final int STATE_EARLY_ANR = 2; 1041 static final int STATE_ANR = 3; 1042 1043 int mState; 1044 1045 static final int RESULT_DEFAULT = 0; 1046 1047 static final int RESULT_CRASH_DIALOG = 0; 1048 static final int RESULT_CRASH_KILL = 1; 1049 1050 static final int RESULT_EARLY_ANR_CONTINUE = 0; 1051 static final int RESULT_EARLY_ANR_KILL = 1; 1052 1053 static final int RESULT_ANR_DIALOG = 0; 1054 static final int RESULT_ANR_KILL = 1; 1055 static final int RESULT_ANR_WAIT = 1; 1056 1057 int mResult; 1058 1059 Process mGdbProcess; 1060 Thread mGdbThread; 1061 boolean mGotGdbPrint; 1062 1063 MyActivityController(String gdbPort) { 1064 mGdbPort = gdbPort; 1065 } 1066 1067 @Override 1068 public boolean activityResuming(String pkg) { 1069 synchronized (this) { 1070 System.out.println("** Activity resuming: " + pkg); 1071 } 1072 return true; 1073 } 1074 1075 @Override 1076 public boolean activityStarting(Intent intent, String pkg) { 1077 synchronized (this) { 1078 System.out.println("** Activity starting: " + pkg); 1079 } 1080 return true; 1081 } 1082 1083 @Override 1084 public boolean appCrashed(String processName, int pid, String shortMsg, String longMsg, 1085 long timeMillis, String stackTrace) { 1086 synchronized (this) { 1087 System.out.println("** ERROR: PROCESS CRASHED"); 1088 System.out.println("processName: " + processName); 1089 System.out.println("processPid: " + pid); 1090 System.out.println("shortMsg: " + shortMsg); 1091 System.out.println("longMsg: " + longMsg); 1092 System.out.println("timeMillis: " + timeMillis); 1093 System.out.println("stack:"); 1094 System.out.print(stackTrace); 1095 System.out.println("#"); 1096 int result = waitControllerLocked(pid, STATE_CRASHED); 1097 return result == RESULT_CRASH_KILL ? false : true; 1098 } 1099 } 1100 1101 @Override 1102 public int appEarlyNotResponding(String processName, int pid, String annotation) { 1103 synchronized (this) { 1104 System.out.println("** ERROR: EARLY PROCESS NOT RESPONDING"); 1105 System.out.println("processName: " + processName); 1106 System.out.println("processPid: " + pid); 1107 System.out.println("annotation: " + annotation); 1108 int result = waitControllerLocked(pid, STATE_EARLY_ANR); 1109 if (result == RESULT_EARLY_ANR_KILL) return -1; 1110 return 0; 1111 } 1112 } 1113 1114 @Override 1115 public int appNotResponding(String processName, int pid, String processStats) { 1116 synchronized (this) { 1117 System.out.println("** ERROR: PROCESS NOT RESPONDING"); 1118 System.out.println("processName: " + processName); 1119 System.out.println("processPid: " + pid); 1120 System.out.println("processStats:"); 1121 System.out.print(processStats); 1122 System.out.println("#"); 1123 int result = waitControllerLocked(pid, STATE_ANR); 1124 if (result == RESULT_ANR_KILL) return -1; 1125 if (result == RESULT_ANR_WAIT) return 1; 1126 return 0; 1127 } 1128 } 1129 1130 @Override 1131 public int systemNotResponding(String message) { 1132 synchronized (this) { 1133 System.out.println("** ERROR: PROCESS NOT RESPONDING"); 1134 System.out.println("message: " + message); 1135 System.out.println("#"); 1136 System.out.println("Allowing system to die."); 1137 return -1; 1138 } 1139 } 1140 1141 void killGdbLocked() { 1142 mGotGdbPrint = false; 1143 if (mGdbProcess != null) { 1144 System.out.println("Stopping gdbserver"); 1145 mGdbProcess.destroy(); 1146 mGdbProcess = null; 1147 } 1148 if (mGdbThread != null) { 1149 mGdbThread.interrupt(); 1150 mGdbThread = null; 1151 } 1152 } 1153 1154 int waitControllerLocked(int pid, int state) { 1155 if (mGdbPort != null) { 1156 killGdbLocked(); 1157 1158 try { 1159 System.out.println("Starting gdbserver on port " + mGdbPort); 1160 System.out.println("Do the following:"); 1161 System.out.println(" adb forward tcp:" + mGdbPort + " tcp:" + mGdbPort); 1162 System.out.println(" gdbclient app_process :" + mGdbPort); 1163 1164 mGdbProcess = Runtime.getRuntime().exec(new String[] { 1165 "gdbserver", ":" + mGdbPort, "--attach", Integer.toString(pid) 1166 }); 1167 final InputStreamReader converter = new InputStreamReader( 1168 mGdbProcess.getInputStream()); 1169 mGdbThread = new Thread() { 1170 @Override 1171 public void run() { 1172 BufferedReader in = new BufferedReader(converter); 1173 String line; 1174 int count = 0; 1175 while (true) { 1176 synchronized (MyActivityController.this) { 1177 if (mGdbThread == null) { 1178 return; 1179 } 1180 if (count == 2) { 1181 mGotGdbPrint = true; 1182 MyActivityController.this.notifyAll(); 1183 } 1184 } 1185 try { 1186 line = in.readLine(); 1187 if (line == null) { 1188 return; 1189 } 1190 System.out.println("GDB: " + line); 1191 count++; 1192 } catch (IOException e) { 1193 return; 1194 } 1195 } 1196 } 1197 }; 1198 mGdbThread.start(); 1199 1200 // Stupid waiting for .5s. Doesn't matter if we end early. 1201 try { 1202 this.wait(500); 1203 } catch (InterruptedException e) { 1204 } 1205 1206 } catch (IOException e) { 1207 System.err.println("Failure starting gdbserver: " + e); 1208 killGdbLocked(); 1209 } 1210 } 1211 mState = state; 1212 System.out.println(""); 1213 printMessageForState(); 1214 1215 while (mState != STATE_NORMAL) { 1216 try { 1217 wait(); 1218 } catch (InterruptedException e) { 1219 } 1220 } 1221 1222 killGdbLocked(); 1223 1224 return mResult; 1225 } 1226 1227 void resumeController(int result) { 1228 synchronized (this) { 1229 mState = STATE_NORMAL; 1230 mResult = result; 1231 notifyAll(); 1232 } 1233 } 1234 1235 void printMessageForState() { 1236 switch (mState) { 1237 case STATE_NORMAL: 1238 System.out.println("Monitoring activity manager... available commands:"); 1239 break; 1240 case STATE_CRASHED: 1241 System.out.println("Waiting after crash... available commands:"); 1242 System.out.println("(c)ontinue: show crash dialog"); 1243 System.out.println("(k)ill: immediately kill app"); 1244 break; 1245 case STATE_EARLY_ANR: 1246 System.out.println("Waiting after early ANR... available commands:"); 1247 System.out.println("(c)ontinue: standard ANR processing"); 1248 System.out.println("(k)ill: immediately kill app"); 1249 break; 1250 case STATE_ANR: 1251 System.out.println("Waiting after ANR... available commands:"); 1252 System.out.println("(c)ontinue: show ANR dialog"); 1253 System.out.println("(k)ill: immediately kill app"); 1254 System.out.println("(w)ait: wait some more"); 1255 break; 1256 } 1257 System.out.println("(q)uit: finish monitoring"); 1258 } 1259 1260 void run() throws RemoteException { 1261 try { 1262 printMessageForState(); 1263 1264 mAm.setActivityController(this); 1265 mState = STATE_NORMAL; 1266 1267 InputStreamReader converter = new InputStreamReader(System.in); 1268 BufferedReader in = new BufferedReader(converter); 1269 String line; 1270 1271 while ((line = in.readLine()) != null) { 1272 boolean addNewline = true; 1273 if (line.length() <= 0) { 1274 addNewline = false; 1275 } else if ("q".equals(line) || "quit".equals(line)) { 1276 resumeController(RESULT_DEFAULT); 1277 break; 1278 } else if (mState == STATE_CRASHED) { 1279 if ("c".equals(line) || "continue".equals(line)) { 1280 resumeController(RESULT_CRASH_DIALOG); 1281 } else if ("k".equals(line) || "kill".equals(line)) { 1282 resumeController(RESULT_CRASH_KILL); 1283 } else { 1284 System.out.println("Invalid command: " + line); 1285 } 1286 } else if (mState == STATE_ANR) { 1287 if ("c".equals(line) || "continue".equals(line)) { 1288 resumeController(RESULT_ANR_DIALOG); 1289 } else if ("k".equals(line) || "kill".equals(line)) { 1290 resumeController(RESULT_ANR_KILL); 1291 } else if ("w".equals(line) || "wait".equals(line)) { 1292 resumeController(RESULT_ANR_WAIT); 1293 } else { 1294 System.out.println("Invalid command: " + line); 1295 } 1296 } else if (mState == STATE_EARLY_ANR) { 1297 if ("c".equals(line) || "continue".equals(line)) { 1298 resumeController(RESULT_EARLY_ANR_CONTINUE); 1299 } else if ("k".equals(line) || "kill".equals(line)) { 1300 resumeController(RESULT_EARLY_ANR_KILL); 1301 } else { 1302 System.out.println("Invalid command: " + line); 1303 } 1304 } else { 1305 System.out.println("Invalid command: " + line); 1306 } 1307 1308 synchronized (this) { 1309 if (addNewline) { 1310 System.out.println(""); 1311 } 1312 printMessageForState(); 1313 } 1314 } 1315 1316 } catch (IOException e) { 1317 e.printStackTrace(); 1318 } finally { 1319 mAm.setActivityController(null); 1320 } 1321 } 1322 } 1323 1324 private void runMonitor() throws Exception { 1325 String opt; 1326 String gdbPort = null; 1327 while ((opt=nextOption()) != null) { 1328 if (opt.equals("--gdb")) { 1329 gdbPort = nextArgRequired(); 1330 } else { 1331 System.err.println("Error: Unknown option: " + opt); 1332 return; 1333 } 1334 } 1335 1336 MyActivityController controller = new MyActivityController(gdbPort); 1337 controller.run(); 1338 } 1339 1340 private void runHang() throws Exception { 1341 String opt; 1342 boolean allowRestart = false; 1343 while ((opt=nextOption()) != null) { 1344 if (opt.equals("--allow-restart")) { 1345 allowRestart = true; 1346 } else { 1347 System.err.println("Error: Unknown option: " + opt); 1348 return; 1349 } 1350 } 1351 1352 System.out.println("Hanging the system..."); 1353 mAm.hang(new Binder(), allowRestart); 1354 } 1355 1356 private void runScreenCompat() throws Exception { 1357 String mode = nextArgRequired(); 1358 boolean enabled; 1359 if ("on".equals(mode)) { 1360 enabled = true; 1361 } else if ("off".equals(mode)) { 1362 enabled = false; 1363 } else { 1364 System.err.println("Error: enabled mode must be 'on' or 'off' at " + mode); 1365 return; 1366 } 1367 1368 String packageName = nextArgRequired(); 1369 do { 1370 try { 1371 mAm.setPackageScreenCompatMode(packageName, enabled 1372 ? ActivityManager.COMPAT_MODE_ENABLED 1373 : ActivityManager.COMPAT_MODE_DISABLED); 1374 } catch (RemoteException e) { 1375 } 1376 packageName = nextArg(); 1377 } while (packageName != null); 1378 } 1379 1380 private void runToUri(boolean intentScheme) throws Exception { 1381 Intent intent = makeIntent(UserHandle.USER_CURRENT); 1382 System.out.println(intent.toUri(intentScheme ? Intent.URI_INTENT_SCHEME : 0)); 1383 } 1384 1385 private class IntentReceiver extends IIntentReceiver.Stub { 1386 private boolean mFinished = false; 1387 1388 @Override 1389 public void performReceive(Intent intent, int resultCode, String data, Bundle extras, 1390 boolean ordered, boolean sticky, int sendingUser) { 1391 String line = "Broadcast completed: result=" + resultCode; 1392 if (data != null) line = line + ", data=\"" + data + "\""; 1393 if (extras != null) line = line + ", extras: " + extras; 1394 System.out.println(line); 1395 synchronized (this) { 1396 mFinished = true; 1397 notifyAll(); 1398 } 1399 } 1400 1401 public synchronized void waitForFinish() { 1402 try { 1403 while (!mFinished) wait(); 1404 } catch (InterruptedException e) { 1405 throw new IllegalStateException(e); 1406 } 1407 } 1408 } 1409 1410 private class InstrumentationWatcher extends IInstrumentationWatcher.Stub { 1411 private boolean mFinished = false; 1412 private boolean mRawMode = false; 1413 1414 /** 1415 * Set or reset "raw mode". In "raw mode", all bundles are dumped. In "pretty mode", 1416 * if a bundle includes Instrumentation.REPORT_KEY_STREAMRESULT, just print that. 1417 * @param rawMode true for raw mode, false for pretty mode. 1418 */ 1419 public void setRawOutput(boolean rawMode) { 1420 mRawMode = rawMode; 1421 } 1422 1423 @Override 1424 public void instrumentationStatus(ComponentName name, int resultCode, Bundle results) { 1425 synchronized (this) { 1426 // pretty printer mode? 1427 String pretty = null; 1428 if (!mRawMode && results != null) { 1429 pretty = results.getString(Instrumentation.REPORT_KEY_STREAMRESULT); 1430 } 1431 if (pretty != null) { 1432 System.out.print(pretty); 1433 } else { 1434 if (results != null) { 1435 for (String key : results.keySet()) { 1436 System.out.println( 1437 "INSTRUMENTATION_STATUS: " + key + "=" + results.get(key)); 1438 } 1439 } 1440 System.out.println("INSTRUMENTATION_STATUS_CODE: " + resultCode); 1441 } 1442 notifyAll(); 1443 } 1444 } 1445 1446 @Override 1447 public void instrumentationFinished(ComponentName name, int resultCode, 1448 Bundle results) { 1449 synchronized (this) { 1450 // pretty printer mode? 1451 String pretty = null; 1452 if (!mRawMode && results != null) { 1453 pretty = results.getString(Instrumentation.REPORT_KEY_STREAMRESULT); 1454 } 1455 if (pretty != null) { 1456 System.out.println(pretty); 1457 } else { 1458 if (results != null) { 1459 for (String key : results.keySet()) { 1460 System.out.println( 1461 "INSTRUMENTATION_RESULT: " + key + "=" + results.get(key)); 1462 } 1463 } 1464 System.out.println("INSTRUMENTATION_CODE: " + resultCode); 1465 } 1466 mFinished = true; 1467 notifyAll(); 1468 } 1469 } 1470 1471 public boolean waitForFinish() { 1472 synchronized (this) { 1473 while (!mFinished) { 1474 try { 1475 if (!mAm.asBinder().pingBinder()) { 1476 return false; 1477 } 1478 wait(1000); 1479 } catch (InterruptedException e) { 1480 throw new IllegalStateException(e); 1481 } 1482 } 1483 } 1484 return true; 1485 } 1486 } 1487 1488 private void runStack() throws Exception { 1489 String op = nextArgRequired(); 1490 if (op.equals("create")) { 1491 runStackCreate(); 1492 } else if (op.equals("movetask")) { 1493 runStackMoveTask(); 1494 } else if (op.equals("resize")) { 1495 runStackBoxResize(); 1496 } else if (op.equals("boxes")) { 1497 runStackBoxes(); 1498 } else if (op.equals("box")) { 1499 runStackBoxInfo(); 1500 } else { 1501 showError("Error: unknown command '" + op + "'"); 1502 return; 1503 } 1504 } 1505 1506 private void runStackCreate() throws Exception { 1507 String taskIdStr = nextArgRequired(); 1508 int taskId = Integer.valueOf(taskIdStr); 1509 String relativeToStr = nextArgRequired(); 1510 int relativeTo = Integer.valueOf(relativeToStr); 1511 String positionStr = nextArgRequired(); 1512 int position = Integer.valueOf(positionStr); 1513 String weightStr = nextArgRequired(); 1514 float weight = Float.valueOf(weightStr); 1515 1516 try { 1517 int stackId = mAm.createStack(taskId, relativeTo, position, weight); 1518 System.out.println("createStack returned new stackId=" + stackId + "\n\n"); 1519 } catch (RemoteException e) { 1520 } 1521 } 1522 1523 private void runStackMoveTask() throws Exception { 1524 String taskIdStr = nextArgRequired(); 1525 int taskId = Integer.valueOf(taskIdStr); 1526 String stackIdStr = nextArgRequired(); 1527 int stackId = Integer.valueOf(stackIdStr); 1528 String toTopStr = nextArgRequired(); 1529 final boolean toTop; 1530 if ("true".equals(toTopStr)) { 1531 toTop = true; 1532 } else if ("false".equals(toTopStr)) { 1533 toTop = false; 1534 } else { 1535 System.err.println("Error: bad toTop arg: " + toTopStr); 1536 return; 1537 } 1538 1539 try { 1540 mAm.moveTaskToStack(taskId, stackId, toTop); 1541 } catch (RemoteException e) { 1542 } 1543 } 1544 1545 private void runStackBoxResize() throws Exception { 1546 String stackBoxIdStr = nextArgRequired(); 1547 int stackBoxId = Integer.valueOf(stackBoxIdStr); 1548 String weightStr = nextArgRequired(); 1549 float weight = Float.valueOf(weightStr); 1550 1551 try { 1552 mAm.resizeStackBox(stackBoxId, weight); 1553 } catch (RemoteException e) { 1554 } 1555 } 1556 1557 private void runStackBoxes() throws Exception { 1558 try { 1559 List<StackBoxInfo> stackBoxes = mAm.getStackBoxes(); 1560 for (StackBoxInfo info : stackBoxes) { 1561 System.out.println(info); 1562 } 1563 } catch (RemoteException e) { 1564 } 1565 } 1566 1567 private void runStackBoxInfo() throws Exception { 1568 try { 1569 String stackBoxIdStr = nextArgRequired(); 1570 int stackBoxId = Integer.valueOf(stackBoxIdStr); 1571 StackBoxInfo stackBoxInfo = mAm.getStackBoxInfo(stackBoxId); 1572 System.out.println(stackBoxInfo); 1573 } catch (RemoteException e) { 1574 } 1575 } 1576} 1577