Am.java revision 287952c35e148811c106bc0f5036eabf20f71562
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.ActivityManagerNative; 22import android.app.IActivityController; 23import android.app.IActivityManager; 24import android.app.IInstrumentationWatcher; 25import android.app.Instrumentation; 26import android.content.ComponentName; 27import android.content.IIntentReceiver; 28import android.content.Intent; 29import android.net.Uri; 30import android.os.Bundle; 31import android.os.ParcelFileDescriptor; 32import android.os.RemoteException; 33import android.os.ServiceManager; 34import android.util.AndroidException; 35import android.view.IWindowManager; 36 37import java.io.BufferedReader; 38import java.io.DataInputStream; 39import java.io.File; 40import java.io.FileInputStream; 41import java.io.FileNotFoundException; 42import java.io.IOException; 43import java.io.InputStreamReader; 44import java.io.PrintStream; 45import java.net.URISyntaxException; 46import java.util.Iterator; 47import java.util.Set; 48 49public class Am { 50 51 private IActivityManager mAm; 52 private String[] mArgs; 53 private int mNextArg; 54 private String mCurArgData; 55 56 private boolean mDebugOption = false; 57 private boolean mWaitOption = false; 58 59 // These are magic strings understood by the Eclipse plugin. 60 private static final String FATAL_ERROR_CODE = "Error type 1"; 61 private static final String NO_SYSTEM_ERROR_CODE = "Error type 2"; 62 private static final String NO_CLASS_ERROR_CODE = "Error type 3"; 63 64 /** 65 * Command-line entry point. 66 * 67 * @param args The command-line arguments 68 */ 69 public static void main(String[] args) { 70 try { 71 (new Am()).run(args); 72 } catch (IllegalArgumentException e) { 73 showUsage(); 74 System.err.println("Error: " + e.getMessage()); 75 } catch (Exception e) { 76 System.err.println(e.toString()); 77 System.exit(1); 78 } 79 } 80 81 private void run(String[] args) throws Exception { 82 if (args.length < 1) { 83 showUsage(); 84 return; 85 } 86 87 mAm = ActivityManagerNative.getDefault(); 88 if (mAm == null) { 89 System.err.println(NO_SYSTEM_ERROR_CODE); 90 throw new AndroidException("Can't connect to activity manager; is the system running?"); 91 } 92 93 mArgs = args; 94 String op = args[0]; 95 mNextArg = 1; 96 97 if (op.equals("start")) { 98 runStart(); 99 } else if (op.equals("startservice")) { 100 runStartService(); 101 } else if (op.equals("instrument")) { 102 runInstrument(); 103 } else if (op.equals("broadcast")) { 104 sendBroadcast(); 105 } else if (op.equals("profile")) { 106 runProfile(); 107 } else if (op.equals("monitor")) { 108 runMonitor(); 109 } else { 110 throw new IllegalArgumentException("Unknown command: " + op); 111 } 112 } 113 114 private Intent makeIntent() throws URISyntaxException { 115 Intent intent = new Intent(); 116 boolean hasIntentInfo = false; 117 118 mDebugOption = false; 119 mWaitOption = false; 120 Uri data = null; 121 String type = null; 122 123 String opt; 124 while ((opt=nextOption()) != null) { 125 if (opt.equals("-a")) { 126 intent.setAction(nextArgRequired()); 127 hasIntentInfo = true; 128 } else if (opt.equals("-d")) { 129 data = Uri.parse(nextArgRequired()); 130 hasIntentInfo = true; 131 } else if (opt.equals("-t")) { 132 type = nextArgRequired(); 133 hasIntentInfo = true; 134 } else if (opt.equals("-c")) { 135 intent.addCategory(nextArgRequired()); 136 hasIntentInfo = true; 137 } else if (opt.equals("-e") || opt.equals("--es")) { 138 String key = nextArgRequired(); 139 String value = nextArgRequired(); 140 intent.putExtra(key, value); 141 hasIntentInfo = true; 142 } else if (opt.equals("--esn")) { 143 String key = nextArgRequired(); 144 intent.putExtra(key, (String) null); 145 hasIntentInfo = true; 146 } else if (opt.equals("--ei")) { 147 String key = nextArgRequired(); 148 String value = nextArgRequired(); 149 intent.putExtra(key, Integer.valueOf(value)); 150 hasIntentInfo = true; 151 } else if (opt.equals("--ez")) { 152 String key = nextArgRequired(); 153 String value = nextArgRequired(); 154 intent.putExtra(key, Boolean.valueOf(value)); 155 hasIntentInfo = true; 156 } else if (opt.equals("-n")) { 157 String str = nextArgRequired(); 158 ComponentName cn = ComponentName.unflattenFromString(str); 159 if (cn == null) throw new IllegalArgumentException("Bad component name: " + str); 160 intent.setComponent(cn); 161 hasIntentInfo = true; 162 } else if (opt.equals("-f")) { 163 String str = nextArgRequired(); 164 intent.setFlags(Integer.decode(str).intValue()); 165 } else if (opt.equals("--grant-read-uri-permission")) { 166 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 167 } else if (opt.equals("--grant-write-uri-permission")) { 168 intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); 169 } else if (opt.equals("--debug-log-resolution")) { 170 intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION); 171 } else if (opt.equals("--activity-brought-to-front")) { 172 intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT); 173 } else if (opt.equals("--activity-clear-top")) { 174 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 175 } else if (opt.equals("--activity-clear-when-task-reset")) { 176 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); 177 } else if (opt.equals("--activity-exclude-from-recents")) { 178 intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); 179 } else if (opt.equals("--activity-launched-from-history")) { 180 intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY); 181 } else if (opt.equals("--activity-multiple-task")) { 182 intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); 183 } else if (opt.equals("--activity-no-animation")) { 184 intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); 185 } else if (opt.equals("--activity-no-history")) { 186 intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); 187 } else if (opt.equals("--activity-no-user-action")) { 188 intent.addFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION); 189 } else if (opt.equals("--activity-previous-is-top")) { 190 intent.addFlags(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP); 191 } else if (opt.equals("--activity-reorder-to-front")) { 192 intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); 193 } else if (opt.equals("--activity-reset-task-if-needed")) { 194 intent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); 195 } else if (opt.equals("--activity-single-top")) { 196 intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); 197 } else if (opt.equals("--receiver-registered-only")) { 198 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); 199 } else if (opt.equals("--receiver-replace-pending")) { 200 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); 201 } else if (opt.equals("-D")) { 202 mDebugOption = true; 203 } else if (opt.equals("-W")) { 204 mWaitOption = true; 205 } else { 206 System.err.println("Error: Unknown option: " + opt); 207 showUsage(); 208 return null; 209 } 210 } 211 intent.setDataAndType(data, type); 212 213 String uri = nextArg(); 214 if (uri != null) { 215 Intent oldIntent = intent; 216 intent = Intent.parseUri(uri, 0); 217 if (oldIntent.getAction() != null) { 218 intent.setAction(oldIntent.getAction()); 219 } 220 if (oldIntent.getData() != null || oldIntent.getType() != null) { 221 intent.setDataAndType(oldIntent.getData(), oldIntent.getType()); 222 } 223 Set cats = oldIntent.getCategories(); 224 if (cats != null) { 225 Iterator it = cats.iterator(); 226 while (it.hasNext()) { 227 intent.addCategory((String)it.next()); 228 } 229 } 230 hasIntentInfo = true; 231 } 232 233 if (!hasIntentInfo) throw new IllegalArgumentException("No intent supplied"); 234 return intent; 235 } 236 237 private void runStartService() throws Exception { 238 Intent intent = makeIntent(); 239 System.out.println("Starting service: " + intent); 240 ComponentName cn = mAm.startService(null, intent, intent.getType()); 241 if (cn == null) { 242 System.err.println("Error: Not found; no service started."); 243 } 244 } 245 246 private void runStart() throws Exception { 247 Intent intent = makeIntent(); 248 System.out.println("Starting: " + intent); 249 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 250 // XXX should do something to determine the MIME type. 251 IActivityManager.WaitResult result = null; 252 int res; 253 if (mWaitOption) { 254 result = mAm.startActivityAndWait(null, intent, intent.getType(), 255 null, 0, null, null, 0, false, mDebugOption); 256 res = result.result; 257 } else { 258 res = mAm.startActivity(null, intent, intent.getType(), 259 null, 0, null, null, 0, false, mDebugOption); 260 } 261 PrintStream out = mWaitOption ? System.out : System.err; 262 boolean launched = false; 263 switch (res) { 264 case IActivityManager.START_SUCCESS: 265 launched = true; 266 break; 267 case IActivityManager.START_SWITCHES_CANCELED: 268 launched = true; 269 out.println( 270 "Warning: Activity not started because the " 271 + " current activity is being kept for the user."); 272 break; 273 case IActivityManager.START_DELIVERED_TO_TOP: 274 launched = true; 275 out.println( 276 "Warning: Activity not started, intent has " 277 + "been delivered to currently running " 278 + "top-most instance."); 279 break; 280 case IActivityManager.START_RETURN_INTENT_TO_CALLER: 281 launched = true; 282 out.println( 283 "Warning: Activity not started because intent " 284 + "should be handled by the caller"); 285 break; 286 case IActivityManager.START_TASK_TO_FRONT: 287 launched = true; 288 out.println( 289 "Warning: Activity not started, its current " 290 + "task has been brought to the front"); 291 break; 292 case IActivityManager.START_INTENT_NOT_RESOLVED: 293 out.println( 294 "Error: Activity not started, unable to " 295 + "resolve " + intent.toString()); 296 break; 297 case IActivityManager.START_CLASS_NOT_FOUND: 298 out.println(NO_CLASS_ERROR_CODE); 299 out.println("Error: Activity class " + 300 intent.getComponent().toShortString() 301 + " does not exist."); 302 break; 303 case IActivityManager.START_FORWARD_AND_REQUEST_CONFLICT: 304 out.println( 305 "Error: Activity not started, you requested to " 306 + "both forward and receive its result"); 307 break; 308 case IActivityManager.START_PERMISSION_DENIED: 309 out.println( 310 "Error: Activity not started, you do not " 311 + "have permission to access it."); 312 break; 313 default: 314 out.println( 315 "Error: Activity not started, unknown error code " + res); 316 break; 317 } 318 if (mWaitOption && launched) { 319 if (result == null) { 320 result = new IActivityManager.WaitResult(); 321 result.who = intent.getComponent(); 322 } 323 System.out.println("Status: " + (result.timeout ? "timeout" : "ok")); 324 if (result.who != null) { 325 System.out.println("Activity: " + result.who.flattenToShortString()); 326 } 327 if (result.thisTime >= 0) { 328 System.out.println("ThisTime: " + result.thisTime); 329 } 330 if (result.totalTime >= 0) { 331 System.out.println("TotalTime: " + result.totalTime); 332 } 333 System.out.println("Complete"); 334 } 335 } 336 337 private void sendBroadcast() throws Exception { 338 Intent intent = makeIntent(); 339 IntentReceiver receiver = new IntentReceiver(); 340 System.out.println("Broadcasting: " + intent); 341 mAm.broadcastIntent(null, intent, null, receiver, 0, null, null, null, true, false); 342 receiver.waitForFinish(); 343 } 344 345 private void runInstrument() throws Exception { 346 String profileFile = null; 347 boolean wait = false; 348 boolean rawMode = false; 349 boolean no_window_animation = false; 350 Bundle args = new Bundle(); 351 String argKey = null, argValue = null; 352 IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.getService("window")); 353 354 String opt; 355 while ((opt=nextOption()) != null) { 356 if (opt.equals("-p")) { 357 profileFile = nextArgRequired(); 358 } else if (opt.equals("-w")) { 359 wait = true; 360 } else if (opt.equals("-r")) { 361 rawMode = true; 362 } else if (opt.equals("-e")) { 363 argKey = nextArgRequired(); 364 argValue = nextArgRequired(); 365 args.putString(argKey, argValue); 366 } else if (opt.equals("--no_window_animation")) { 367 no_window_animation = true; 368 } else { 369 System.err.println("Error: Unknown option: " + opt); 370 showUsage(); 371 return; 372 } 373 } 374 375 String cnArg = nextArgRequired(); 376 ComponentName cn = ComponentName.unflattenFromString(cnArg); 377 if (cn == null) throw new IllegalArgumentException("Bad component name: " + cnArg); 378 379 InstrumentationWatcher watcher = null; 380 if (wait) { 381 watcher = new InstrumentationWatcher(); 382 watcher.setRawOutput(rawMode); 383 } 384 float[] oldAnims = null; 385 if (no_window_animation) { 386 oldAnims = wm.getAnimationScales(); 387 wm.setAnimationScale(0, 0.0f); 388 wm.setAnimationScale(1, 0.0f); 389 } 390 391 if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher)) { 392 throw new AndroidException("INSTRUMENTATION_FAILED: " + cn.flattenToString()); 393 } 394 395 if (watcher != null) { 396 if (!watcher.waitForFinish()) { 397 System.out.println("INSTRUMENTATION_ABORTED: System has crashed."); 398 } 399 } 400 401 if (oldAnims != null) { 402 wm.setAnimationScales(oldAnims); 403 } 404 } 405 406 private void runProfile() throws Exception { 407 String profileFile = null; 408 boolean start = false; 409 String process = nextArgRequired(); 410 ParcelFileDescriptor fd = null; 411 412 String cmd = nextArgRequired(); 413 if ("start".equals(cmd)) { 414 start = true; 415 profileFile = nextArgRequired(); 416 try { 417 fd = ParcelFileDescriptor.open( 418 new File(profileFile), 419 ParcelFileDescriptor.MODE_CREATE | 420 ParcelFileDescriptor.MODE_TRUNCATE | 421 ParcelFileDescriptor.MODE_READ_WRITE); 422 } catch (FileNotFoundException e) { 423 System.err.println("Error: Unable to open file: " + profileFile); 424 return; 425 } 426 } else if (!"stop".equals(cmd)) { 427 throw new IllegalArgumentException("Profile command " + cmd + " not valid"); 428 } 429 430 if (!mAm.profileControl(process, start, profileFile, fd)) { 431 throw new AndroidException("PROFILE FAILED on process " + process); 432 } 433 } 434 435 class MyActivityController extends IActivityController.Stub { 436 static final int STATE_NORMAL = 0; 437 static final int STATE_CRASHED = 1; 438 static final int STATE_EARLY_ANR = 2; 439 static final int STATE_ANR = 3; 440 441 int mState; 442 443 static final int RESULT_DEFAULT = 0; 444 445 static final int RESULT_CRASH_DIALOG = 0; 446 static final int RESULT_CRASH_KILL = 1; 447 448 static final int RESULT_EARLY_ANR_CONTINUE = 0; 449 static final int RESULT_EARLY_ANR_KILL = 1; 450 451 static final int RESULT_ANR_DIALOG = 0; 452 static final int RESULT_ANR_KILL = 1; 453 static final int RESULT_ANR_WAIT = 1; 454 455 int mResult; 456 457 @Override 458 public boolean activityResuming(String pkg) throws RemoteException { 459 synchronized (this) { 460 System.out.println("** Activity resuming: " + pkg); 461 } 462 return true; 463 } 464 465 @Override 466 public boolean activityStarting(Intent intent, String pkg) throws RemoteException { 467 synchronized (this) { 468 System.out.println("** Activity starting: " + pkg); 469 } 470 return true; 471 } 472 473 @Override 474 public boolean appCrashed(String processName, int pid, String shortMsg, String longMsg, 475 long timeMillis, String stackTrace) throws RemoteException { 476 synchronized (this) { 477 System.out.println("** ERROR: PROCESS CRASHED"); 478 System.out.println("processName: " + processName); 479 System.out.println("processPid: " + pid); 480 System.out.println("shortMsg: " + shortMsg); 481 System.out.println("longMsg: " + longMsg); 482 System.out.println("timeMillis: " + timeMillis); 483 System.out.println("stack:"); 484 System.out.print(stackTrace); 485 System.out.println("#"); 486 int result = waitControllerLocked(STATE_CRASHED); 487 return result == RESULT_CRASH_KILL ? false : true; 488 } 489 } 490 491 @Override 492 public int appEarlyNotResponding(String processName, int pid, String annotation) 493 throws RemoteException { 494 synchronized (this) { 495 System.out.println("** ERROR: EARLY PROCESS NOT RESPONDING"); 496 System.out.println("processName: " + processName); 497 System.out.println("processPid: " + pid); 498 System.out.println("annotation: " + annotation); 499 int result = waitControllerLocked(STATE_EARLY_ANR); 500 if (result == RESULT_EARLY_ANR_KILL) return -1; 501 return 0; 502 } 503 } 504 505 @Override 506 public int appNotResponding(String processName, int pid, String processStats) 507 throws RemoteException { 508 synchronized (this) { 509 System.out.println("** ERROR: PROCESS NOT RESPONDING"); 510 System.out.println("processName: " + processName); 511 System.out.println("processPid: " + pid); 512 System.out.println("processStats:"); 513 System.out.print(processStats); 514 System.out.println("#"); 515 int result = waitControllerLocked(STATE_ANR); 516 if (result == RESULT_ANR_KILL) return -1; 517 if (result == RESULT_ANR_WAIT) return 1; 518 return 0; 519 } 520 } 521 522 int waitControllerLocked(int state) { 523 mState = state; 524 System.out.println(""); 525 printMessageForState(); 526 527 while (mState != STATE_NORMAL) { 528 try { 529 wait(); 530 } catch (InterruptedException e) { 531 } 532 } 533 534 return mResult; 535 } 536 537 void resumeController(int result) { 538 synchronized (this) { 539 mState = STATE_NORMAL; 540 mResult = result; 541 notifyAll(); 542 } 543 } 544 545 void printMessageForState() { 546 switch (mState) { 547 case STATE_NORMAL: 548 System.out.println("Monitoring activity manager... available commands:"); 549 break; 550 case STATE_CRASHED: 551 System.out.println("Waiting after crash... available commands:"); 552 System.out.println("(c)ontinue: show crash dialog"); 553 System.out.println("(k)ill: immediately kill app"); 554 break; 555 case STATE_EARLY_ANR: 556 System.out.println("Waiting after early ANR... available commands:"); 557 System.out.println("(c)ontinue: standard ANR processing"); 558 System.out.println("(k)ill: immediately kill app"); 559 break; 560 case STATE_ANR: 561 System.out.println("Waiting after ANR... available commands:"); 562 System.out.println("(c)ontinue: show ANR dialog"); 563 System.out.println("(k)ill: immediately kill app"); 564 System.out.println("(w)ait: wait some more"); 565 break; 566 } 567 System.out.println("(q)uit: finish monitoring"); 568 } 569 570 void run() throws RemoteException { 571 try { 572 printMessageForState(); 573 574 mAm.setActivityController(this); 575 mState = STATE_NORMAL; 576 577 InputStreamReader converter = new InputStreamReader(System.in); 578 BufferedReader in = new BufferedReader(converter); 579 String line; 580 581 while ((line = in.readLine()) != null) { 582 boolean addNewline = true; 583 if (line.length() <= 0) { 584 addNewline = false; 585 } else if ("q".equals(line) || "quit".equals(line)) { 586 resumeController(RESULT_DEFAULT); 587 break; 588 } else if (mState == STATE_CRASHED) { 589 if ("c".equals(line) || "continue".equals(line)) { 590 resumeController(RESULT_CRASH_DIALOG); 591 } else if ("k".equals(line) || "kill".equals(line)) { 592 resumeController(RESULT_CRASH_KILL); 593 } else { 594 System.out.println("Invalid command: " + line); 595 } 596 } else if (mState == STATE_ANR) { 597 if ("c".equals(line) || "continue".equals(line)) { 598 resumeController(RESULT_ANR_DIALOG); 599 } else if ("k".equals(line) || "kill".equals(line)) { 600 resumeController(RESULT_ANR_KILL); 601 } else if ("w".equals(line) || "wait".equals(line)) { 602 resumeController(RESULT_ANR_WAIT); 603 } else { 604 System.out.println("Invalid command: " + line); 605 } 606 } else if (mState == STATE_EARLY_ANR) { 607 if ("c".equals(line) || "continue".equals(line)) { 608 resumeController(RESULT_EARLY_ANR_CONTINUE); 609 } else if ("k".equals(line) || "kill".equals(line)) { 610 resumeController(RESULT_EARLY_ANR_KILL); 611 } else { 612 System.out.println("Invalid command: " + line); 613 } 614 } else { 615 System.out.println("Invalid command: " + line); 616 } 617 618 synchronized (this) { 619 if (addNewline) { 620 System.out.println(""); 621 } 622 printMessageForState(); 623 } 624 } 625 626 } catch (IOException e) { 627 e.printStackTrace(); 628 } finally { 629 mAm.setActivityController(null); 630 } 631 } 632 } 633 634 private void runMonitor() throws Exception { 635 MyActivityController controller = new MyActivityController(); 636 controller.run(); 637 } 638 639 private class IntentReceiver extends IIntentReceiver.Stub { 640 private boolean mFinished = false; 641 642 public synchronized void performReceive( 643 Intent intent, int rc, String data, Bundle ext, boolean ord, 644 boolean sticky) { 645 String line = "Broadcast completed: result=" + rc; 646 if (data != null) line = line + ", data=\"" + data + "\""; 647 if (ext != null) line = line + ", extras: " + ext; 648 System.out.println(line); 649 mFinished = true; 650 notifyAll(); 651 } 652 653 public synchronized void waitForFinish() { 654 try { 655 while (!mFinished) wait(); 656 } catch (InterruptedException e) { 657 throw new IllegalStateException(e); 658 } 659 } 660 } 661 662 private class InstrumentationWatcher extends IInstrumentationWatcher.Stub { 663 private boolean mFinished = false; 664 private boolean mRawMode = false; 665 666 /** 667 * Set or reset "raw mode". In "raw mode", all bundles are dumped. In "pretty mode", 668 * if a bundle includes Instrumentation.REPORT_KEY_STREAMRESULT, just print that. 669 * @param rawMode true for raw mode, false for pretty mode. 670 */ 671 public void setRawOutput(boolean rawMode) { 672 mRawMode = rawMode; 673 } 674 675 public void instrumentationStatus(ComponentName name, int resultCode, Bundle results) { 676 synchronized (this) { 677 // pretty printer mode? 678 String pretty = null; 679 if (!mRawMode && results != null) { 680 pretty = results.getString(Instrumentation.REPORT_KEY_STREAMRESULT); 681 } 682 if (pretty != null) { 683 System.out.print(pretty); 684 } else { 685 if (results != null) { 686 for (String key : results.keySet()) { 687 System.out.println( 688 "INSTRUMENTATION_STATUS: " + key + "=" + results.get(key)); 689 } 690 } 691 System.out.println("INSTRUMENTATION_STATUS_CODE: " + resultCode); 692 } 693 notifyAll(); 694 } 695 } 696 697 public void instrumentationFinished(ComponentName name, int resultCode, 698 Bundle results) { 699 synchronized (this) { 700 // pretty printer mode? 701 String pretty = null; 702 if (!mRawMode && results != null) { 703 pretty = results.getString(Instrumentation.REPORT_KEY_STREAMRESULT); 704 } 705 if (pretty != null) { 706 System.out.println(pretty); 707 } else { 708 if (results != null) { 709 for (String key : results.keySet()) { 710 System.out.println( 711 "INSTRUMENTATION_RESULT: " + key + "=" + results.get(key)); 712 } 713 } 714 System.out.println("INSTRUMENTATION_CODE: " + resultCode); 715 } 716 mFinished = true; 717 notifyAll(); 718 } 719 } 720 721 public boolean waitForFinish() { 722 synchronized (this) { 723 while (!mFinished) { 724 try { 725 if (!mAm.asBinder().pingBinder()) { 726 return false; 727 } 728 wait(1000); 729 } catch (InterruptedException e) { 730 throw new IllegalStateException(e); 731 } 732 } 733 } 734 return true; 735 } 736 } 737 738 private String nextOption() { 739 if (mCurArgData != null) { 740 String prev = mArgs[mNextArg - 1]; 741 throw new IllegalArgumentException("No argument expected after \"" + prev + "\""); 742 } 743 if (mNextArg >= mArgs.length) { 744 return null; 745 } 746 String arg = mArgs[mNextArg]; 747 if (!arg.startsWith("-")) { 748 return null; 749 } 750 mNextArg++; 751 if (arg.equals("--")) { 752 return null; 753 } 754 if (arg.length() > 1 && arg.charAt(1) != '-') { 755 if (arg.length() > 2) { 756 mCurArgData = arg.substring(2); 757 return arg.substring(0, 2); 758 } else { 759 mCurArgData = null; 760 return arg; 761 } 762 } 763 mCurArgData = null; 764 return arg; 765 } 766 767 private String nextArg() { 768 if (mCurArgData != null) { 769 String arg = mCurArgData; 770 mCurArgData = null; 771 return arg; 772 } else if (mNextArg < mArgs.length) { 773 return mArgs[mNextArg++]; 774 } else { 775 return null; 776 } 777 } 778 779 private String nextArgRequired() { 780 String arg = nextArg(); 781 if (arg == null) { 782 String prev = mArgs[mNextArg - 1]; 783 throw new IllegalArgumentException("Argument expected after \"" + prev + "\""); 784 } 785 return arg; 786 } 787 788 private static void showUsage() { 789 System.err.println( 790 "usage: am [subcommand] [options]\n" + 791 "\n" + 792 " start an Activity: am start [-D] [-W] <INTENT>\n" + 793 " -D: enable debugging\n" + 794 " -W: wait for launch to complete\n" + 795 "\n" + 796 " start a Service: am startservice <INTENT>\n" + 797 "\n" + 798 " send a broadcast Intent: am broadcast <INTENT>\n" + 799 "\n" + 800 " start an Instrumentation: am instrument [flags] <COMPONENT>\n" + 801 " -r: print raw results (otherwise decode REPORT_KEY_STREAMRESULT)\n" + 802 " -e <NAME> <VALUE>: set argument <NAME> to <VALUE>\n" + 803 " -p <FILE>: write profiling data to <FILE>\n" + 804 " -w: wait for instrumentation to finish before returning\n" + 805 "\n" + 806 " start profiling: am profile <PROCESS> start <FILE>\n" + 807 " stop profiling: am profile <PROCESS> stop\n" + 808 "\n" + 809 " start monitoring: am monitor\n" + 810 "\n" + 811 " <INTENT> specifications include these flags:\n" + 812 " [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" + 813 " [-c <CATEGORY> [-c <CATEGORY>] ...]\n" + 814 " [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]\n" + 815 " [--esn <EXTRA_KEY> ...]\n" + 816 " [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]\n" + 817 " [-e|--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]\n" + 818 " [-n <COMPONENT>] [-f <FLAGS>]\n" + 819 " [--grant-read-uri-permission] [--grant-write-uri-permission]\n" + 820 " [--debug-log-resolution]\n" + 821 " [--activity-brought-to-front] [--activity-clear-top]\n" + 822 " [--activity-clear-when-task-reset] [--activity-exclude-from-recents]\n" + 823 " [--activity-launched-from-history] [--activity-multiple-task]\n" + 824 " [--activity-no-animation] [--activity-no-history]\n" + 825 " [--activity-no-user-action] [--activity-previous-is-top]\n" + 826 " [--activity-reorder-to-front] [--activity-reset-task-if-needed]\n" + 827 " [--activity-single-top]\n" + 828 " [--receiver-registered-only] [--receiver-replace-pending]\n" + 829 " [<URI>]\n" 830 ); 831 } 832} 833