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