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