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