Am.java revision 9c8dd55a9d829c29a3feee9469d8c2f27a9f5516
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.IActivityManager; 23import android.app.IInstrumentationWatcher; 24import android.app.Instrumentation; 25import android.content.ComponentName; 26import android.content.Intent; 27import android.net.Uri; 28import android.os.Bundle; 29import android.os.ParcelFileDescriptor; 30import android.os.RemoteException; 31import android.os.ServiceManager; 32import android.view.IWindowManager; 33 34import java.io.File; 35import java.io.FileNotFoundException; 36import java.util.Iterator; 37import java.util.Set; 38 39public class Am { 40 41 private IActivityManager mAm; 42 private String[] mArgs; 43 private int mNextArg; 44 private String mCurArgData; 45 46 private boolean mDebugOption = false; 47 48 /** 49 * Command-line entry point. 50 * 51 * @param args The command-line arguments 52 */ 53 public static void main(String[] args) { 54 (new Am()).run(args); 55 } 56 57 private void run(String[] args) { 58 if (args.length < 1) { 59 showUsage(); 60 return; 61 } 62 63 mAm = ActivityManagerNative.getDefault(); 64 if (mAm == null) { 65 System.err.println("Error type 2"); 66 System.err.println("Error: Unable to connect to activity manager; is the system running?"); 67 showUsage(); 68 return; 69 } 70 71 mArgs = args; 72 73 String op = args[0]; 74 mNextArg = 1; 75 if (op.equals("start")) { 76 runStart(); 77 } else if (op.equals("instrument")) { 78 runInstrument(); 79 } else if (op.equals("broadcast")) { 80 sendBroadcast(); 81 } else if (op.equals("profile")) { 82 runProfile(); 83 } else { 84 System.err.println("Error: Unknown command: " + op); 85 showUsage(); 86 return; 87 } 88 } 89 90 private Intent makeIntent() { 91 Intent intent = new Intent(); 92 boolean hasIntentInfo = false; 93 94 mDebugOption = false; 95 Uri data = null; 96 String type = null; 97 98 try { 99 String opt; 100 while ((opt=nextOption()) != null) { 101 if (opt.equals("-a")) { 102 intent.setAction(nextOptionData()); 103 hasIntentInfo = true; 104 } else if (opt.equals("-d")) { 105 data = Uri.parse(nextOptionData()); 106 hasIntentInfo = true; 107 } else if (opt.equals("-t")) { 108 type = nextOptionData(); 109 hasIntentInfo = true; 110 } else if (opt.equals("-c")) { 111 intent.addCategory(nextOptionData()); 112 hasIntentInfo = true; 113 } else if (opt.equals("-e") || opt.equals("--es")) { 114 String key = nextOptionData(); 115 String value = nextOptionData(); 116 intent.putExtra(key, value); 117 hasIntentInfo = true; 118 } else if (opt.equals("--ei")) { 119 String key = nextOptionData(); 120 String value = nextOptionData(); 121 intent.putExtra(key, Integer.valueOf(value)); 122 hasIntentInfo = true; 123 } else if (opt.equals("--ez")) { 124 String key = nextOptionData(); 125 String value = nextOptionData(); 126 intent.putExtra(key, Boolean.valueOf(value)); 127 hasIntentInfo = true; 128 } else if (opt.equals("-n")) { 129 String str = nextOptionData(); 130 ComponentName cn = ComponentName.unflattenFromString(str); 131 if (cn == null) { 132 System.err.println("Error: Bad component name: " + str); 133 showUsage(); 134 return null; 135 } 136 intent.setComponent(cn); 137 hasIntentInfo = true; 138 } else if (opt.equals("-f")) { 139 String str = nextOptionData(); 140 intent.setFlags(Integer.decode(str).intValue()); 141 } else if (opt.equals("-D")) { 142 mDebugOption = true; 143 } else { 144 System.err.println("Error: Unknown option: " + opt); 145 showUsage(); 146 return null; 147 } 148 } 149 } catch (RuntimeException ex) { 150 System.err.println("Error: " + ex.toString()); 151 showUsage(); 152 return null; 153 } 154 intent.setDataAndType(data, type); 155 156 String uri = nextArg(); 157 if (uri != null) { 158 try { 159 Intent oldIntent = intent; 160 try { 161 intent = Intent.getIntent(uri); 162 } catch (java.net.URISyntaxException ex) { 163 System.err.println("Bad URI: " + uri); 164 showUsage(); 165 return null; 166 } 167 if (oldIntent.getAction() != null) { 168 intent.setAction(oldIntent.getAction()); 169 } 170 if (oldIntent.getData() != null || oldIntent.getType() != null) { 171 intent.setDataAndType(oldIntent.getData(), oldIntent.getType()); 172 } 173 Set cats = oldIntent.getCategories(); 174 if (cats != null) { 175 Iterator it = cats.iterator(); 176 while (it.hasNext()) { 177 intent.addCategory((String)it.next()); 178 } 179 } 180 } catch (RuntimeException ex) { 181 System.err.println("Error creating from URI: " + ex.toString()); 182 showUsage(); 183 return null; 184 } 185 } else if (!hasIntentInfo) { 186 System.err.println("Error: No intent supplied"); 187 showUsage(); 188 return null; 189 } 190 191 return intent; 192 } 193 194 private void runStart() { 195 Intent intent = makeIntent(); 196 197 if (intent != null) { 198 System.out.println("Starting: " + intent); 199 try { 200 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 201 // XXX should do something to determine the MIME type. 202 int res = mAm.startActivity(null, intent, intent.getType(), 203 null, 0, null, null, 0, false, mDebugOption); 204 switch (res) { 205 case IActivityManager.START_SUCCESS: 206 break; 207 case IActivityManager.START_SWITCHES_CANCELED: 208 System.err.println( 209 "Warning: Activity not started because the " 210 + " current activity is being kept for the user."); 211 break; 212 case IActivityManager.START_DELIVERED_TO_TOP: 213 System.err.println( 214 "Warning: Activity not started, intent has " 215 + "been delivered to currently running " 216 + "top-most instance."); 217 break; 218 case IActivityManager.START_RETURN_INTENT_TO_CALLER: 219 System.err.println( 220 "Warning: Activity not started because intent " 221 + "should be handled by the caller"); 222 break; 223 case IActivityManager.START_TASK_TO_FRONT: 224 System.err.println( 225 "Warning: Activity not started, its current " 226 + "task has been brought to the front"); 227 break; 228 case IActivityManager.START_INTENT_NOT_RESOLVED: 229 System.err.println( 230 "Error: Activity not started, unable to " 231 + "resolve " + intent.toString()); 232 break; 233 case IActivityManager.START_CLASS_NOT_FOUND: 234 System.err.println("Error type 3"); 235 System.err.println("Error: Activity class " + 236 intent.getComponent().toShortString() 237 + " does not exist."); 238 break; 239 case IActivityManager.START_FORWARD_AND_REQUEST_CONFLICT: 240 System.err.println( 241 "Error: Activity not started, you requested to " 242 + "both forward and receive its result"); 243 break; 244 case IActivityManager.START_PERMISSION_DENIED: 245 System.err.println( 246 "Error: Activity not started, you do not " 247 + "have permission to access it."); 248 break; 249 default: 250 System.err.println( 251 "Error: Activity not started, unknown error " 252 + "code " + res); 253 break; 254 } 255 } catch (RemoteException e) { 256 System.err.println("Error type 1"); 257 System.err.println( 258 "Error: Activity not started, unable to " 259 + "call on to activity manager service"); 260 } 261 } 262 } 263 264 private void sendBroadcast() { 265 Intent intent = makeIntent(); 266 267 if (intent != null) { 268 System.out.println("Broadcasting: " + intent); 269 try { 270 mAm.broadcastIntent(null, intent, null, null, 0, null, null, 271 null, true, false); 272 } catch (RemoteException e) { 273 } 274 } 275 } 276 277 private void runInstrument() { 278 String profileFile = null; 279 boolean wait = false; 280 boolean rawMode = false; 281 boolean no_window_animation = false; 282 Bundle args = new Bundle(); 283 String argKey = null, argValue = null; 284 IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.getService("window")); 285 286 try { 287 String opt; 288 while ((opt=nextOption()) != null) { 289 if (opt.equals("-p")) { 290 profileFile = nextOptionData(); 291 } else if (opt.equals("-w")) { 292 wait = true; 293 } else if (opt.equals("-r")) { 294 rawMode = true; 295 } else if (opt.equals("-e")) { 296 argKey = nextOptionData(); 297 argValue = nextOptionData(); 298 args.putString(argKey, argValue); 299 } else if (opt.equals("--no_window_animation")) { 300 no_window_animation = true; 301 } else { 302 System.err.println("Error: Unknown option: " + opt); 303 showUsage(); 304 return; 305 } 306 } 307 } catch (RuntimeException ex) { 308 System.err.println("Error: " + ex.toString()); 309 showUsage(); 310 return; 311 } 312 313 String cnArg = nextArg(); 314 if (cnArg == null) { 315 System.err.println("Error: No instrumentation component supplied"); 316 showUsage(); 317 return; 318 } 319 320 ComponentName cn = ComponentName.unflattenFromString(cnArg); 321 if (cn == null) { 322 System.err.println("Error: Bad component name: " + cnArg); 323 showUsage(); 324 return; 325 } 326 327 InstrumentationWatcher watcher = null; 328 if (wait) { 329 watcher = new InstrumentationWatcher(); 330 watcher.setRawOutput(rawMode); 331 } 332 float[] oldAnims = null; 333 if (no_window_animation) { 334 try { 335 oldAnims = wm.getAnimationScales(); 336 wm.setAnimationScale(0, 0.0f); 337 wm.setAnimationScale(1, 0.0f); 338 } catch (RemoteException e) { 339 } 340 } 341 342 try { 343 if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher)) { 344 System.out.println("INSTRUMENTATION_FAILED: " + 345 cn.flattenToString()); 346 showUsage(); 347 return; 348 } 349 } catch (RemoteException e) { 350 } 351 352 if (watcher != null) { 353 if (!watcher.waitForFinish()) { 354 System.out.println("INSTRUMENTATION_ABORTED: System has crashed."); 355 } 356 } 357 358 if (oldAnims != null) { 359 try { 360 wm.setAnimationScales(oldAnims); 361 } catch (RemoteException e) { 362 } 363 } 364 } 365 366 private class InstrumentationWatcher extends IInstrumentationWatcher.Stub { 367 private boolean mFinished = false; 368 private boolean mRawMode = false; 369 370 /** 371 * Set or reset "raw mode". In "raw mode", all bundles are dumped. In "pretty mode", 372 * if a bundle includes Instrumentation.REPORT_KEY_STREAMRESULT, just print that. 373 * @param rawMode true for raw mode, false for pretty mode. 374 */ 375 public void setRawOutput(boolean rawMode) { 376 mRawMode = rawMode; 377 } 378 379 public void instrumentationStatus(ComponentName name, int resultCode, Bundle results) { 380 synchronized (this) { 381 // pretty printer mode? 382 String pretty = null; 383 if (!mRawMode && results != null) { 384 pretty = results.getString(Instrumentation.REPORT_KEY_STREAMRESULT); 385 } 386 if (pretty != null) { 387 System.out.print(pretty); 388 } else { 389 if (results != null) { 390 for (String key : results.keySet()) { 391 System.out.println( 392 "INSTRUMENTATION_STATUS: " + key + "=" + results.get(key)); 393 } 394 } 395 System.out.println("INSTRUMENTATION_STATUS_CODE: " + resultCode); 396 } 397 notifyAll(); 398 } 399 } 400 401 public void instrumentationFinished(ComponentName name, int resultCode, 402 Bundle results) { 403 synchronized (this) { 404 // pretty printer mode? 405 String pretty = null; 406 if (!mRawMode && results != null) { 407 pretty = results.getString(Instrumentation.REPORT_KEY_STREAMRESULT); 408 } 409 if (pretty != null) { 410 System.out.println(pretty); 411 } else { 412 if (results != null) { 413 for (String key : results.keySet()) { 414 System.out.println( 415 "INSTRUMENTATION_RESULT: " + key + "=" + results.get(key)); 416 } 417 } 418 System.out.println("INSTRUMENTATION_CODE: " + resultCode); 419 } 420 mFinished = true; 421 notifyAll(); 422 } 423 } 424 425 public boolean waitForFinish() { 426 synchronized (this) { 427 while (!mFinished) { 428 try { 429 if (!mAm.asBinder().pingBinder()) { 430 return false; 431 } 432 wait(1000); 433 } catch (InterruptedException e) { 434 } 435 } 436 } 437 return true; 438 } 439 } 440 441 private void runProfile() { 442 String profileFile = null; 443 boolean start = false; 444 445 String process = nextArg(); 446 if (process == null) { 447 System.err.println("Error: No profile process supplied"); 448 showUsage(); 449 return; 450 } 451 452 ParcelFileDescriptor fd = null; 453 454 String cmd = nextArg(); 455 if ("start".equals(cmd)) { 456 start = true; 457 profileFile = nextArg(); 458 if (profileFile == null) { 459 System.err.println("Error: No profile file path supplied"); 460 showUsage(); 461 return; 462 } 463 try { 464 fd = ParcelFileDescriptor.open( 465 new File(profileFile), 466 ParcelFileDescriptor.MODE_CREATE | 467 ParcelFileDescriptor.MODE_TRUNCATE | 468 ParcelFileDescriptor.MODE_READ_WRITE); 469 } catch (FileNotFoundException e) { 470 System.err.println("Error: Unable to open file: " + profileFile); 471 return; 472 } 473 } else if (!"stop".equals(cmd)) { 474 System.err.println("Error: Profile command " + cmd + " not valid"); 475 showUsage(); 476 return; 477 } 478 479 try { 480 if (!mAm.profileControl(process, start, profileFile, fd)) { 481 System.err.println("PROFILE FAILED on process " + process); 482 return; 483 } 484 } catch (IllegalArgumentException e) { 485 System.out.println("PROFILE FAILED: " + e.getMessage()); 486 return; 487 } catch (IllegalStateException e) { 488 System.out.println("PROFILE FAILED: " + e.getMessage()); 489 return; 490 } catch (RemoteException e) { 491 System.out.println("PROFILE FAILED: activity manager gone"); 492 return; 493 } 494 } 495 496 private String nextOption() { 497 if (mNextArg >= mArgs.length) { 498 return null; 499 } 500 String arg = mArgs[mNextArg]; 501 if (!arg.startsWith("-")) { 502 return null; 503 } 504 mNextArg++; 505 if (arg.equals("--")) { 506 return null; 507 } 508 if (arg.length() > 1 && arg.charAt(1) != '-') { 509 if (arg.length() > 2) { 510 mCurArgData = arg.substring(2); 511 return arg.substring(0, 2); 512 } else { 513 mCurArgData = null; 514 return arg; 515 } 516 } 517 mCurArgData = null; 518 return arg; 519 } 520 521 private String nextOptionData() { 522 if (mCurArgData != null) { 523 return mCurArgData; 524 } 525 if (mNextArg >= mArgs.length) { 526 return null; 527 } 528 String data = mArgs[mNextArg]; 529 mNextArg++; 530 return data; 531 } 532 533 private String nextArg() { 534 if (mNextArg >= mArgs.length) { 535 return null; 536 } 537 String arg = mArgs[mNextArg]; 538 mNextArg++; 539 return arg; 540 } 541 542 private void showUsage() { 543 System.err.println("usage: am [start|broadcast|instrument|profile]"); 544 System.err.println(" am start [-D] INTENT"); 545 System.err.println(" am broadcast INTENT"); 546 System.err.println(" am instrument [-r] [-e <ARG_NAME> <ARG_VALUE>] [-p <PROF_FILE>]"); 547 System.err.println(" [-w] <COMPONENT> "); 548 System.err.println(" am profile <PROCESS> [start <PROF_FILE>|stop]"); 549 System.err.println(""); 550 System.err.println(" INTENT is described with:"); 551 System.err.println(" [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]"); 552 System.err.println(" [-c <CATEGORY> [-c <CATEGORY>] ...]"); 553 System.err.println(" [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]"); 554 System.err.println(" [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]"); 555 System.err.println(" [-e|--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]"); 556 System.err.println(" [-n <COMPONENT>] [-f <FLAGS>] [<URI>]"); 557 } 558} 559