Am.java revision f5b4b98fada53d91c4c2ebeb5a1d33ccc95c94d2
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_CLASS_NOT_FOUND: 205 System.err.println("Error type 3"); 206 System.err.println("Error: Activity class " + 207 intent.getComponent().toShortString() 208 + " does not exist."); 209 break; 210 case IActivityManager.START_DELIVERED_TO_TOP: 211 System.err.println( 212 "Warning: Activity not started, intent has " 213 + "been delivered to currently running " 214 + "top-most instance."); 215 break; 216 case IActivityManager.START_FORWARD_AND_REQUEST_CONFLICT: 217 System.err.println( 218 "Error: Activity not started, you requested to " 219 + "both forward and receive its result"); 220 break; 221 case IActivityManager.START_INTENT_NOT_RESOLVED: 222 System.err.println( 223 "Error: Activity not started, unable to " 224 + "resolve " + intent.toString()); 225 break; 226 case IActivityManager.START_RETURN_INTENT_TO_CALLER: 227 System.err.println( 228 "Warning: Activity not started because intent " 229 + "should be handled by the caller"); 230 break; 231 case IActivityManager.START_TASK_TO_FRONT: 232 System.err.println( 233 "Warning: Activity not started, its current " 234 + "task has been brought to the front"); 235 break; 236 default: 237 System.err.println( 238 "Error: Activity not started, unknown error " 239 + "code " + res); 240 break; 241 } 242 } catch (RemoteException e) { 243 System.err.println("Error type 1"); 244 System.err.println( 245 "Error: Activity not started, unable to " 246 + "call on to activity manager service"); 247 } 248 } 249 } 250 251 private void sendBroadcast() { 252 Intent intent = makeIntent(); 253 254 if (intent != null) { 255 System.out.println("Broadcasting: " + intent); 256 try { 257 mAm.broadcastIntent(null, intent, null, null, 0, null, null, 258 null, true, false); 259 } catch (RemoteException e) { 260 } 261 } 262 } 263 264 private void runInstrument() { 265 String profileFile = null; 266 boolean wait = false; 267 boolean rawMode = false; 268 boolean no_window_animation = false; 269 Bundle args = new Bundle(); 270 String argKey = null, argValue = null; 271 IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.getService("window")); 272 273 try { 274 String opt; 275 while ((opt=nextOption()) != null) { 276 if (opt.equals("-p")) { 277 profileFile = nextOptionData(); 278 } else if (opt.equals("-w")) { 279 wait = true; 280 } else if (opt.equals("-r")) { 281 rawMode = true; 282 } else if (opt.equals("-e")) { 283 argKey = nextOptionData(); 284 argValue = nextOptionData(); 285 args.putString(argKey, argValue); 286 } else if (opt.equals("--no_window_animation")) { 287 no_window_animation = true; 288 } else { 289 System.err.println("Error: Unknown option: " + opt); 290 showUsage(); 291 return; 292 } 293 } 294 } catch (RuntimeException ex) { 295 System.err.println("Error: " + ex.toString()); 296 showUsage(); 297 return; 298 } 299 300 String cnArg = nextArg(); 301 if (cnArg == null) { 302 System.err.println("Error: No instrumentation component supplied"); 303 showUsage(); 304 return; 305 } 306 307 ComponentName cn = ComponentName.unflattenFromString(cnArg); 308 if (cn == null) { 309 System.err.println("Error: Bad component name: " + cnArg); 310 showUsage(); 311 return; 312 } 313 314 InstrumentationWatcher watcher = null; 315 if (wait) { 316 watcher = new InstrumentationWatcher(); 317 watcher.setRawOutput(rawMode); 318 } 319 float[] oldAnims = null; 320 if (no_window_animation) { 321 try { 322 oldAnims = wm.getAnimationScales(); 323 wm.setAnimationScale(0, 0.0f); 324 wm.setAnimationScale(1, 0.0f); 325 } catch (RemoteException e) { 326 } 327 } 328 329 try { 330 if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher)) { 331 System.out.println("INSTRUMENTATION_FAILED: " + 332 cn.flattenToString()); 333 showUsage(); 334 return; 335 } 336 } catch (RemoteException e) { 337 } 338 339 if (watcher != null) { 340 if (!watcher.waitForFinish()) { 341 System.out.println("INSTRUMENTATION_ABORTED: System has crashed."); 342 } 343 } 344 345 if (oldAnims != null) { 346 try { 347 wm.setAnimationScales(oldAnims); 348 } catch (RemoteException e) { 349 } 350 } 351 } 352 353 private class InstrumentationWatcher extends IInstrumentationWatcher.Stub { 354 private boolean mFinished = false; 355 private boolean mRawMode = false; 356 357 /** 358 * Set or reset "raw mode". In "raw mode", all bundles are dumped. In "pretty mode", 359 * if a bundle includes Instrumentation.REPORT_KEY_STREAMRESULT, just print that. 360 * @param rawMode true for raw mode, false for pretty mode. 361 */ 362 public void setRawOutput(boolean rawMode) { 363 mRawMode = rawMode; 364 } 365 366 public void instrumentationStatus(ComponentName name, int resultCode, Bundle results) { 367 synchronized (this) { 368 // pretty printer mode? 369 String pretty = null; 370 if (!mRawMode && results != null) { 371 pretty = results.getString(Instrumentation.REPORT_KEY_STREAMRESULT); 372 } 373 if (pretty != null) { 374 System.out.print(pretty); 375 } else { 376 if (results != null) { 377 for (String key : results.keySet()) { 378 System.out.println( 379 "INSTRUMENTATION_STATUS: " + key + "=" + results.get(key)); 380 } 381 } 382 System.out.println("INSTRUMENTATION_STATUS_CODE: " + resultCode); 383 } 384 notifyAll(); 385 } 386 } 387 388 public void instrumentationFinished(ComponentName name, int resultCode, 389 Bundle results) { 390 synchronized (this) { 391 // pretty printer mode? 392 String pretty = null; 393 if (!mRawMode && results != null) { 394 pretty = results.getString(Instrumentation.REPORT_KEY_STREAMRESULT); 395 } 396 if (pretty != null) { 397 System.out.println(pretty); 398 } else { 399 if (results != null) { 400 for (String key : results.keySet()) { 401 System.out.println( 402 "INSTRUMENTATION_RESULT: " + key + "=" + results.get(key)); 403 } 404 } 405 System.out.println("INSTRUMENTATION_CODE: " + resultCode); 406 } 407 mFinished = true; 408 notifyAll(); 409 } 410 } 411 412 public boolean waitForFinish() { 413 synchronized (this) { 414 while (!mFinished) { 415 try { 416 if (!mAm.asBinder().pingBinder()) { 417 return false; 418 } 419 wait(1000); 420 } catch (InterruptedException e) { 421 } 422 } 423 } 424 return true; 425 } 426 } 427 428 private void runProfile() { 429 String profileFile = null; 430 boolean start = false; 431 432 String process = nextArg(); 433 if (process == null) { 434 System.err.println("Error: No profile process supplied"); 435 showUsage(); 436 return; 437 } 438 439 String cmd = nextArg(); 440 if ("start".equals(cmd)) { 441 start = true; 442 profileFile = nextArg(); 443 if (profileFile == null) { 444 System.err.println("Error: No profile file path supplied"); 445 showUsage(); 446 return; 447 } 448 } else if (!"stop".equals(cmd)) { 449 System.err.println("Error: Profile command " + cmd + " not valid"); 450 showUsage(); 451 return; 452 } 453 454 try { 455 if (!mAm.profileControl(process, start, profileFile)) { 456 System.out.println("PROFILE FAILED on process " + process); 457 return; 458 } 459 } catch (IllegalArgumentException e) { 460 System.out.println("PROFILE FAILED: " + e.getMessage()); 461 return; 462 } catch (IllegalStateException e) { 463 System.out.println("PROFILE FAILED: " + e.getMessage()); 464 return; 465 } catch (RemoteException e) { 466 System.out.println("PROFILE FAILED: activity manager gone"); 467 return; 468 } 469 } 470 471 private String nextOption() { 472 if (mNextArg >= mArgs.length) { 473 return null; 474 } 475 String arg = mArgs[mNextArg]; 476 if (!arg.startsWith("-")) { 477 return null; 478 } 479 mNextArg++; 480 if (arg.equals("--")) { 481 return null; 482 } 483 if (arg.length() > 1 && arg.charAt(1) != '-') { 484 if (arg.length() > 2) { 485 mCurArgData = arg.substring(2); 486 return arg.substring(0, 2); 487 } else { 488 mCurArgData = null; 489 return arg; 490 } 491 } 492 mCurArgData = null; 493 return arg; 494 } 495 496 private String nextOptionData() { 497 if (mCurArgData != null) { 498 return mCurArgData; 499 } 500 if (mNextArg >= mArgs.length) { 501 return null; 502 } 503 String data = mArgs[mNextArg]; 504 mNextArg++; 505 return data; 506 } 507 508 private String nextArg() { 509 if (mNextArg >= mArgs.length) { 510 return null; 511 } 512 String arg = mArgs[mNextArg]; 513 mNextArg++; 514 return arg; 515 } 516 517 private void showUsage() { 518 System.err.println("usage: am [start|broadcast|instrument|profile]"); 519 System.err.println(" am start -D INTENT"); 520 System.err.println(" am broadcast INTENT"); 521 System.err.println(" am instrument [-r] [-e <ARG_NAME> <ARG_VALUE>] [-p <PROF_FILE>]"); 522 System.err.println(" [-w] <COMPONENT> "); 523 System.err.println(" am profile <PROCESS> [start <PROF_FILE>|stop]"); 524 System.err.println(""); 525 System.err.println(" INTENT is described with:"); 526 System.err.println(" [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]"); 527 System.err.println(" [-c <CATEGORY> [-c <CATEGORY>] ...]"); 528 System.err.println(" [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]"); 529 System.err.println(" [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]"); 530 System.err.println(" [-e|--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]"); 531 System.err.println(" [-n <COMPONENT>] [-f <FLAGS>] [<URI>]"); 532 } 533} 534