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