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