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