Am.java revision 0bd2aa760346edd096f7c27283f394631f246f30
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.ActivityManager.StackInfo; 23import android.app.ActivityManagerNative; 24import android.app.IActivityContainer; 25import android.app.IActivityController; 26import android.app.IActivityManager; 27import android.app.IInstrumentationWatcher; 28import android.app.Instrumentation; 29import android.app.ProfilerInfo; 30import android.app.UiAutomationConnection; 31import android.app.usage.ConfigurationStats; 32import android.app.usage.IUsageStatsManager; 33import android.app.usage.UsageStatsManager; 34import android.content.ComponentName; 35import android.content.Context; 36import android.content.IIntentReceiver; 37import android.content.Intent; 38import android.content.pm.IPackageManager; 39import android.content.pm.ParceledListSlice; 40import android.content.pm.ResolveInfo; 41import android.content.res.Configuration; 42import android.graphics.Rect; 43import android.net.Uri; 44import android.os.Binder; 45import android.os.Build; 46import android.os.Bundle; 47import android.os.ParcelFileDescriptor; 48import android.os.RemoteException; 49import android.os.SELinux; 50import android.os.ServiceManager; 51import android.os.SystemClock; 52import android.os.SystemProperties; 53import android.os.UserHandle; 54import android.text.TextUtils; 55import android.util.AndroidException; 56import android.util.ArrayMap; 57import android.view.IWindowManager; 58 59import com.android.internal.os.BaseCommand; 60 61import java.io.BufferedReader; 62import java.io.File; 63import java.io.FileNotFoundException; 64import java.io.IOException; 65import java.io.InputStreamReader; 66import java.io.PrintStream; 67import java.net.URISyntaxException; 68import java.util.ArrayList; 69import java.util.Collections; 70import java.util.Comparator; 71import java.util.HashSet; 72import java.util.List; 73 74public class Am extends BaseCommand { 75 76 private IActivityManager mAm; 77 78 private int mStartFlags = 0; 79 private boolean mWaitOption = false; 80 private boolean mStopOption = false; 81 82 private int mRepeat = 0; 83 private int mUserId; 84 private String mReceiverPermission; 85 86 private String mProfileFile; 87 private int mSamplingInterval; 88 private boolean mAutoStop; 89 90 /** 91 * Command-line entry point. 92 * 93 * @param args The command-line arguments 94 */ 95 public static void main(String[] args) { 96 (new Am()).run(args); 97 } 98 99 @Override 100 public void onShowUsage(PrintStream out) { 101 out.println( 102 "usage: am [subcommand] [options]\n" + 103 "usage: am start [-D] [-W] [-P <FILE>] [--start-profiler <FILE>]\n" + 104 " [--sampling INTERVAL] [-R COUNT] [-S] [--opengl-trace]\n" + 105 " [--user <USER_ID> | current] <INTENT>\n" + 106 " am startservice [--user <USER_ID> | current] <INTENT>\n" + 107 " am stopservice [--user <USER_ID> | current] <INTENT>\n" + 108 " am force-stop [--user <USER_ID> | all | current] <PACKAGE>\n" + 109 " am kill [--user <USER_ID> | all | current] <PACKAGE>\n" + 110 " am kill-all\n" + 111 " am broadcast [--user <USER_ID> | all | current] <INTENT>\n" + 112 " am instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]\n" + 113 " [--user <USER_ID> | current]\n" + 114 " [--no-window-animation] [--abi <ABI>] <COMPONENT>\n" + 115 " am profile start [--user <USER_ID> current] [--sampling INTERVAL] <PROCESS> <FILE>\n" + 116 " am profile stop [--user <USER_ID> current] [<PROCESS>]\n" + 117 " am dumpheap [--user <USER_ID> current] [-n] <PROCESS> <FILE>\n" + 118 " am set-debug-app [-w] [--persistent] <PACKAGE>\n" + 119 " am clear-debug-app\n" + 120 " am set-watch-heap <PROCESS> <MEM-LIMIT>\n" + 121 " am clear-watch-heap\n" + 122 " am monitor [--gdb <port>]\n" + 123 " am hang [--allow-restart]\n" + 124 " am restart\n" + 125 " am idle-maintenance\n" + 126 " am screen-compat [on|off] <PACKAGE>\n" + 127 " am package-importance <PACKAGE>\n" + 128 " am to-uri [INTENT]\n" + 129 " am to-intent-uri [INTENT]\n" + 130 " am to-app-uri [INTENT]\n" + 131 " am switch-user <USER_ID>\n" + 132 " am start-user <USER_ID>\n" + 133 " am stop-user <USER_ID>\n" + 134 " am stack start <DISPLAY_ID> <INTENT>\n" + 135 " am stack movetask <TASK_ID> <STACK_ID> [true|false]\n" + 136 " am stack resize <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" + 137 " am stack split <STACK_ID> <v|h> [INTENT]\n" + 138 " am stack list\n" + 139 " am stack info <STACK_ID>\n" + 140 " am task lock <TASK_ID>\n" + 141 " am task lock stop\n" + 142 " am task resizeable <TASK_ID> [true|false]\n" + 143 " am task resize <TASK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" + 144 " am get-config\n" + 145 "\n" + 146 "am start: start an Activity. Options are:\n" + 147 " -D: enable debugging\n" + 148 " -W: wait for launch to complete\n" + 149 " --start-profiler <FILE>: start profiler and send results to <FILE>\n" + 150 " --sampling INTERVAL: use sample profiling with INTERVAL microseconds\n" + 151 " between samples (use with --start-profiler)\n" + 152 " -P <FILE>: like above, but profiling stops when app goes idle\n" + 153 " -R: repeat the activity launch <COUNT> times. Prior to each repeat,\n" + 154 " the top activity will be finished.\n" + 155 " -S: force stop the target app before starting the activity\n" + 156 " --opengl-trace: enable tracing of OpenGL functions\n" + 157 " --user <USER_ID> | current: Specify which user to run as; if not\n" + 158 " specified then run as the current user.\n" + 159 "\n" + 160 "am startservice: start a Service. Options are:\n" + 161 " --user <USER_ID> | current: Specify which user to run as; if not\n" + 162 " specified then run as the current user.\n" + 163 "\n" + 164 "am stopservice: stop a Service. Options are:\n" + 165 " --user <USER_ID> | current: Specify which user to run as; if not\n" + 166 " specified then run as the current user.\n" + 167 "\n" + 168 "am force-stop: force stop everything associated with <PACKAGE>.\n" + 169 " --user <USER_ID> | all | current: Specify user to force stop;\n" + 170 " all users if not specified.\n" + 171 "\n" + 172 "am kill: Kill all processes associated with <PACKAGE>. Only kills.\n" + 173 " processes that are safe to kill -- that is, will not impact the user\n" + 174 " experience.\n" + 175 " --user <USER_ID> | all | current: Specify user whose processes to kill;\n" + 176 " all users if not specified.\n" + 177 "\n" + 178 "am kill-all: Kill all background processes.\n" + 179 "\n" + 180 "am broadcast: send a broadcast Intent. Options are:\n" + 181 " --user <USER_ID> | all | current: Specify which user to send to; if not\n" + 182 " specified then send to all users.\n" + 183 " --receiver-permission <PERMISSION>: Require receiver to hold permission.\n" + 184 "\n" + 185 "am instrument: start an Instrumentation. Typically this target <COMPONENT>\n" + 186 " is the form <TEST_PACKAGE>/<RUNNER_CLASS>. Options are:\n" + 187 " -r: print raw results (otherwise decode REPORT_KEY_STREAMRESULT). Use with\n" + 188 " [-e perf true] to generate raw output for performance measurements.\n" + 189 " -e <NAME> <VALUE>: set argument <NAME> to <VALUE>. For test runners a\n" + 190 " common form is [-e <testrunner_flag> <value>[,<value>...]].\n" + 191 " -p <FILE>: write profiling data to <FILE>\n" + 192 " -w: wait for instrumentation to finish before returning. Required for\n" + 193 " test runners.\n" + 194 " --user <USER_ID> | current: Specify user instrumentation runs in;\n" + 195 " current user if not specified.\n" + 196 " --no-window-animation: turn off window animations while running.\n" + 197 " --abi <ABI>: Launch the instrumented process with the selected ABI.\n" + 198 " This assumes that the process supports the selected ABI.\n" + 199 "\n" + 200 "am profile: start and stop profiler on a process. The given <PROCESS> argument\n" + 201 " may be either a process name or pid. Options are:\n" + 202 " --user <USER_ID> | current: When supplying a process name,\n" + 203 " specify user of process to profile; uses current user if not specified.\n" + 204 "\n" + 205 "am dumpheap: dump the heap of a process. The given <PROCESS> argument may\n" + 206 " be either a process name or pid. Options are:\n" + 207 " -n: dump native heap instead of managed heap\n" + 208 " --user <USER_ID> | current: When supplying a process name,\n" + 209 " specify user of process to dump; uses current user if not specified.\n" + 210 "\n" + 211 "am set-debug-app: set application <PACKAGE> to debug. Options are:\n" + 212 " -w: wait for debugger when application starts\n" + 213 " --persistent: retain this value\n" + 214 "\n" + 215 "am clear-debug-app: clear the previously set-debug-app.\n" + 216 "\n" + 217 "am set-watch-heap: start monitoring pss size of <PROCESS>, if it is at or\n" + 218 " above <HEAP-LIMIT> then a heap dump is collected for the user to report\n" + 219 "\n" + 220 "am clear-watch-heap: clear the previously set-watch-heap.\n" + 221 "\n" + 222 "am bug-report: request bug report generation; will launch UI\n" + 223 " when done to select where it should be delivered.\n" + 224 "\n" + 225 "am monitor: start monitoring for crashes or ANRs.\n" + 226 " --gdb: start gdbserv on the given port at crash/ANR\n" + 227 "\n" + 228 "am hang: hang the system.\n" + 229 " --allow-restart: allow watchdog to perform normal system restart\n" + 230 "\n" + 231 "am restart: restart the user-space system.\n" + 232 "\n" + 233 "am idle-maintenance: perform idle maintenance now.\n" + 234 "\n" + 235 "am screen-compat: control screen compatibility mode of <PACKAGE>.\n" + 236 "\n" + 237 "am package-importance: print current importance of <PACKAGE>.\n" + 238 "\n" + 239 "am to-uri: print the given Intent specification as a URI.\n" + 240 "\n" + 241 "am to-intent-uri: print the given Intent specification as an intent: URI.\n" + 242 "\n" + 243 "am to-app-uri: print the given Intent specification as an android-app: URI.\n" + 244 "\n" + 245 "am switch-user: switch to put USER_ID in the foreground, starting\n" + 246 " execution of that user if it is currently stopped.\n" + 247 "\n" + 248 "am start-user: start USER_ID in background if it is currently stopped,\n" + 249 " use switch-user if you want to start the user in foreground.\n" + 250 "\n" + 251 "am stop-user: stop execution of USER_ID, not allowing it to run any\n" + 252 " code until a later explicit start or switch to it.\n" + 253 "\n" + 254 "am stack start: start a new activity on <DISPLAY_ID> using <INTENT>.\n" + 255 "\n" + 256 "am stack movetask: move <TASK_ID> from its current stack to the top (true) or" + 257 " bottom (false) of <STACK_ID>.\n" + 258 "\n" + 259 "am stack resize: change <STACK_ID> size and position to <LEFT,TOP,RIGHT,BOTTOM>" + 260 ".\n" + 261 "\n" + 262 "am stack split: split <STACK_ID> into 2 stacks <v>ertically or <h>orizontally\n" + 263 " starting the new stack with [INTENT] if specified. If [INTENT] isn't\n" + 264 " specified and the current stack has more than one task, then the top task\n" + 265 " of the current task will be moved to the new stack. Command will also force\n" + 266 " all current tasks in both stacks to be resizeable.\n" + 267 "\n" + 268 "am stack list: list all of the activity stacks and their sizes.\n" + 269 "\n" + 270 "am stack info: display the information about activity stack <STACK_ID>.\n" + 271 "\n" + 272 "am task lock: bring <TASK_ID> to the front and don't allow other tasks to run\n" + 273 "\n" + 274 "am task lock stop: end the current task lock\n" + 275 "\n" + 276 "am task resizeable: change if <TASK_ID> is resizeable (true) or not (false).\n" + 277 "\n" + 278 "am task resize: makes sure <TASK_ID> is in a stack with the specified bounds.\n" + 279 " Forces the task to be resizeable and creates a stack if no existing stack\n" + 280 " has the specified bounds.\n" + 281 "\n" + 282 "am get-config: retrieve the configuration and any recent configurations\n" + 283 " of the device\n" + 284 "\n" + 285 "<INTENT> specifications include these flags and arguments:\n" + 286 " [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" + 287 " [-c <CATEGORY> [-c <CATEGORY>] ...]\n" + 288 " [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]\n" + 289 " [--esn <EXTRA_KEY> ...]\n" + 290 " [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]\n" + 291 " [--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]\n" + 292 " [--el <EXTRA_KEY> <EXTRA_LONG_VALUE> ...]\n" + 293 " [--ef <EXTRA_KEY> <EXTRA_FLOAT_VALUE> ...]\n" + 294 " [--eu <EXTRA_KEY> <EXTRA_URI_VALUE> ...]\n" + 295 " [--ecn <EXTRA_KEY> <EXTRA_COMPONENT_NAME_VALUE>]\n" + 296 " [--eia <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]]\n" + 297 " [--ela <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]\n" + 298 " [--efa <EXTRA_KEY> <EXTRA_FLOAT_VALUE>[,<EXTRA_FLOAT_VALUE...]]\n" + 299 " [--esa <EXTRA_KEY> <EXTRA_STRING_VALUE>[,<EXTRA_STRING_VALUE...]]\n" + 300 " (to embed a comma into a string escape it using \"\\,\")\n" + 301 " [-n <COMPONENT>] [-p <PACKAGE>] [-f <FLAGS>]\n" + 302 " [--grant-read-uri-permission] [--grant-write-uri-permission]\n" + 303 " [--grant-persistable-uri-permission] [--grant-prefix-uri-permission]\n" + 304 " [--debug-log-resolution] [--exclude-stopped-packages]\n" + 305 " [--include-stopped-packages]\n" + 306 " [--activity-brought-to-front] [--activity-clear-top]\n" + 307 " [--activity-clear-when-task-reset] [--activity-exclude-from-recents]\n" + 308 " [--activity-launched-from-history] [--activity-multiple-task]\n" + 309 " [--activity-no-animation] [--activity-no-history]\n" + 310 " [--activity-no-user-action] [--activity-previous-is-top]\n" + 311 " [--activity-reorder-to-front] [--activity-reset-task-if-needed]\n" + 312 " [--activity-single-top] [--activity-clear-task]\n" + 313 " [--activity-task-on-home]\n" + 314 " [--receiver-registered-only] [--receiver-replace-pending]\n" + 315 " [--selector]\n" + 316 " [<URI> | <PACKAGE> | <COMPONENT>]\n" 317 ); 318 } 319 320 @Override 321 public void onRun() throws Exception { 322 323 mAm = ActivityManagerNative.getDefault(); 324 if (mAm == null) { 325 System.err.println(NO_SYSTEM_ERROR_CODE); 326 throw new AndroidException("Can't connect to activity manager; is the system running?"); 327 } 328 329 String op = nextArgRequired(); 330 331 if (op.equals("start")) { 332 runStart(); 333 } else if (op.equals("startservice")) { 334 runStartService(); 335 } else if (op.equals("stopservice")) { 336 runStopService(); 337 } else if (op.equals("force-stop")) { 338 runForceStop(); 339 } else if (op.equals("kill")) { 340 runKill(); 341 } else if (op.equals("kill-all")) { 342 runKillAll(); 343 } else if (op.equals("instrument")) { 344 runInstrument(); 345 } else if (op.equals("broadcast")) { 346 sendBroadcast(); 347 } else if (op.equals("profile")) { 348 runProfile(); 349 } else if (op.equals("dumpheap")) { 350 runDumpHeap(); 351 } else if (op.equals("set-debug-app")) { 352 runSetDebugApp(); 353 } else if (op.equals("clear-debug-app")) { 354 runClearDebugApp(); 355 } else if (op.equals("set-watch-heap")) { 356 runSetWatchHeap(); 357 } else if (op.equals("clear-watch-heap")) { 358 runClearWatchHeap(); 359 } else if (op.equals("bug-report")) { 360 runBugReport(); 361 } else if (op.equals("monitor")) { 362 runMonitor(); 363 } else if (op.equals("hang")) { 364 runHang(); 365 } else if (op.equals("restart")) { 366 runRestart(); 367 } else if (op.equals("idle-maintenance")) { 368 runIdleMaintenance(); 369 } else if (op.equals("screen-compat")) { 370 runScreenCompat(); 371 } else if (op.equals("package-importance")) { 372 runPackageImportance(); 373 } else if (op.equals("to-uri")) { 374 runToUri(0); 375 } else if (op.equals("to-intent-uri")) { 376 runToUri(Intent.URI_INTENT_SCHEME); 377 } else if (op.equals("to-app-uri")) { 378 runToUri(Intent.URI_ANDROID_APP_SCHEME); 379 } else if (op.equals("switch-user")) { 380 runSwitchUser(); 381 } else if (op.equals("start-user")) { 382 runStartUserInBackground(); 383 } else if (op.equals("stop-user")) { 384 runStopUser(); 385 } else if (op.equals("stack")) { 386 runStack(); 387 } else if (op.equals("task")) { 388 runTask(); 389 } else if (op.equals("get-config")) { 390 runGetConfig(); 391 } else { 392 showError("Error: unknown command '" + op + "'"); 393 } 394 } 395 396 int parseUserArg(String arg) { 397 int userId; 398 if ("all".equals(arg)) { 399 userId = UserHandle.USER_ALL; 400 } else if ("current".equals(arg) || "cur".equals(arg)) { 401 userId = UserHandle.USER_CURRENT; 402 } else { 403 userId = Integer.parseInt(arg); 404 } 405 return userId; 406 } 407 408 private Intent makeIntent(int defUser) throws URISyntaxException { 409 Intent intent = new Intent(); 410 Intent baseIntent = intent; 411 boolean hasIntentInfo = false; 412 413 mStartFlags = 0; 414 mWaitOption = false; 415 mStopOption = false; 416 mRepeat = 0; 417 mProfileFile = null; 418 mSamplingInterval = 0; 419 mAutoStop = false; 420 mUserId = defUser; 421 Uri data = null; 422 String type = null; 423 424 String opt; 425 while ((opt=nextOption()) != null) { 426 if (opt.equals("-a")) { 427 intent.setAction(nextArgRequired()); 428 if (intent == baseIntent) { 429 hasIntentInfo = true; 430 } 431 } else if (opt.equals("-d")) { 432 data = Uri.parse(nextArgRequired()); 433 if (intent == baseIntent) { 434 hasIntentInfo = true; 435 } 436 } else if (opt.equals("-t")) { 437 type = nextArgRequired(); 438 if (intent == baseIntent) { 439 hasIntentInfo = true; 440 } 441 } else if (opt.equals("-c")) { 442 intent.addCategory(nextArgRequired()); 443 if (intent == baseIntent) { 444 hasIntentInfo = true; 445 } 446 } else if (opt.equals("-e") || opt.equals("--es")) { 447 String key = nextArgRequired(); 448 String value = nextArgRequired(); 449 intent.putExtra(key, value); 450 } else if (opt.equals("--esn")) { 451 String key = nextArgRequired(); 452 intent.putExtra(key, (String) null); 453 } else if (opt.equals("--ei")) { 454 String key = nextArgRequired(); 455 String value = nextArgRequired(); 456 intent.putExtra(key, Integer.decode(value)); 457 } else if (opt.equals("--eu")) { 458 String key = nextArgRequired(); 459 String value = nextArgRequired(); 460 intent.putExtra(key, Uri.parse(value)); 461 } else if (opt.equals("--ecn")) { 462 String key = nextArgRequired(); 463 String value = nextArgRequired(); 464 ComponentName cn = ComponentName.unflattenFromString(value); 465 if (cn == null) throw new IllegalArgumentException("Bad component name: " + value); 466 intent.putExtra(key, cn); 467 } else if (opt.equals("--eia")) { 468 String key = nextArgRequired(); 469 String value = nextArgRequired(); 470 String[] strings = value.split(","); 471 int[] list = new int[strings.length]; 472 for (int i = 0; i < strings.length; i++) { 473 list[i] = Integer.decode(strings[i]); 474 } 475 intent.putExtra(key, list); 476 } else if (opt.equals("--el")) { 477 String key = nextArgRequired(); 478 String value = nextArgRequired(); 479 intent.putExtra(key, Long.valueOf(value)); 480 } else if (opt.equals("--ela")) { 481 String key = nextArgRequired(); 482 String value = nextArgRequired(); 483 String[] strings = value.split(","); 484 long[] list = new long[strings.length]; 485 for (int i = 0; i < strings.length; i++) { 486 list[i] = Long.valueOf(strings[i]); 487 } 488 intent.putExtra(key, list); 489 hasIntentInfo = true; 490 } else if (opt.equals("--ef")) { 491 String key = nextArgRequired(); 492 String value = nextArgRequired(); 493 intent.putExtra(key, Float.valueOf(value)); 494 hasIntentInfo = true; 495 } else if (opt.equals("--efa")) { 496 String key = nextArgRequired(); 497 String value = nextArgRequired(); 498 String[] strings = value.split(","); 499 float[] list = new float[strings.length]; 500 for (int i = 0; i < strings.length; i++) { 501 list[i] = Float.valueOf(strings[i]); 502 } 503 intent.putExtra(key, list); 504 hasIntentInfo = true; 505 } else if (opt.equals("--esa")) { 506 String key = nextArgRequired(); 507 String value = nextArgRequired(); 508 // Split on commas unless they are preceeded by an escape. 509 // The escape character must be escaped for the string and 510 // again for the regex, thus four escape characters become one. 511 String[] strings = value.split("(?<!\\\\),"); 512 intent.putExtra(key, strings); 513 hasIntentInfo = true; 514 } else if (opt.equals("--ez")) { 515 String key = nextArgRequired(); 516 String value = nextArgRequired().toLowerCase(); 517 // Boolean.valueOf() results in false for anything that is not "true", which is 518 // error-prone in shell commands 519 boolean arg; 520 if ("true".equals(value) || "t".equals(value)) { 521 arg = true; 522 } else if ("false".equals(value) || "f".equals(value)) { 523 arg = false; 524 } else { 525 try { 526 arg = Integer.decode(value) != 0; 527 } catch (NumberFormatException ex) { 528 throw new IllegalArgumentException("Invalid boolean value: " + value); 529 } 530 } 531 532 intent.putExtra(key, arg); 533 } else if (opt.equals("-n")) { 534 String str = nextArgRequired(); 535 ComponentName cn = ComponentName.unflattenFromString(str); 536 if (cn == null) throw new IllegalArgumentException("Bad component name: " + str); 537 intent.setComponent(cn); 538 if (intent == baseIntent) { 539 hasIntentInfo = true; 540 } 541 } else if (opt.equals("-p")) { 542 String str = nextArgRequired(); 543 intent.setPackage(str); 544 if (intent == baseIntent) { 545 hasIntentInfo = true; 546 } 547 } else if (opt.equals("-f")) { 548 String str = nextArgRequired(); 549 intent.setFlags(Integer.decode(str).intValue()); 550 } else if (opt.equals("--grant-read-uri-permission")) { 551 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 552 } else if (opt.equals("--grant-write-uri-permission")) { 553 intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); 554 } else if (opt.equals("--grant-persistable-uri-permission")) { 555 intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION); 556 } else if (opt.equals("--grant-prefix-uri-permission")) { 557 intent.addFlags(Intent.FLAG_GRANT_PREFIX_URI_PERMISSION); 558 } else if (opt.equals("--exclude-stopped-packages")) { 559 intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES); 560 } else if (opt.equals("--include-stopped-packages")) { 561 intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); 562 } else if (opt.equals("--debug-log-resolution")) { 563 intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION); 564 } else if (opt.equals("--activity-brought-to-front")) { 565 intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT); 566 } else if (opt.equals("--activity-clear-top")) { 567 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 568 } else if (opt.equals("--activity-clear-when-task-reset")) { 569 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); 570 } else if (opt.equals("--activity-exclude-from-recents")) { 571 intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); 572 } else if (opt.equals("--activity-launched-from-history")) { 573 intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY); 574 } else if (opt.equals("--activity-multiple-task")) { 575 intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); 576 } else if (opt.equals("--activity-no-animation")) { 577 intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); 578 } else if (opt.equals("--activity-no-history")) { 579 intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); 580 } else if (opt.equals("--activity-no-user-action")) { 581 intent.addFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION); 582 } else if (opt.equals("--activity-previous-is-top")) { 583 intent.addFlags(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP); 584 } else if (opt.equals("--activity-reorder-to-front")) { 585 intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); 586 } else if (opt.equals("--activity-reset-task-if-needed")) { 587 intent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); 588 } else if (opt.equals("--activity-single-top")) { 589 intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); 590 } else if (opt.equals("--activity-clear-task")) { 591 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); 592 } else if (opt.equals("--activity-task-on-home")) { 593 intent.addFlags(Intent.FLAG_ACTIVITY_TASK_ON_HOME); 594 } else if (opt.equals("--receiver-registered-only")) { 595 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); 596 } else if (opt.equals("--receiver-replace-pending")) { 597 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); 598 } else if (opt.equals("--selector")) { 599 intent.setDataAndType(data, type); 600 intent = new Intent(); 601 } else if (opt.equals("-D")) { 602 mStartFlags |= ActivityManager.START_FLAG_DEBUG; 603 } else if (opt.equals("-W")) { 604 mWaitOption = true; 605 } else if (opt.equals("-P")) { 606 mProfileFile = nextArgRequired(); 607 mAutoStop = true; 608 } else if (opt.equals("--start-profiler")) { 609 mProfileFile = nextArgRequired(); 610 mAutoStop = false; 611 } else if (opt.equals("--sampling")) { 612 mSamplingInterval = Integer.parseInt(nextArgRequired()); 613 } else if (opt.equals("-R")) { 614 mRepeat = Integer.parseInt(nextArgRequired()); 615 } else if (opt.equals("-S")) { 616 mStopOption = true; 617 } else if (opt.equals("--opengl-trace")) { 618 mStartFlags |= ActivityManager.START_FLAG_OPENGL_TRACES; 619 } else if (opt.equals("--user")) { 620 mUserId = parseUserArg(nextArgRequired()); 621 } else if (opt.equals("--receiver-permission")) { 622 mReceiverPermission = nextArgRequired(); 623 } else { 624 System.err.println("Error: Unknown option: " + opt); 625 return null; 626 } 627 } 628 intent.setDataAndType(data, type); 629 630 final boolean hasSelector = intent != baseIntent; 631 if (hasSelector) { 632 // A selector was specified; fix up. 633 baseIntent.setSelector(intent); 634 intent = baseIntent; 635 } 636 637 String arg = nextArg(); 638 baseIntent = null; 639 if (arg == null) { 640 if (hasSelector) { 641 // If a selector has been specified, and no arguments 642 // have been supplied for the main Intent, then we can 643 // assume it is ACTION_MAIN CATEGORY_LAUNCHER; we don't 644 // need to have a component name specified yet, the 645 // selector will take care of that. 646 baseIntent = new Intent(Intent.ACTION_MAIN); 647 baseIntent.addCategory(Intent.CATEGORY_LAUNCHER); 648 } 649 } else if (arg.indexOf(':') >= 0) { 650 // The argument is a URI. Fully parse it, and use that result 651 // to fill in any data not specified so far. 652 baseIntent = Intent.parseUri(arg, Intent.URI_INTENT_SCHEME 653 | Intent.URI_ANDROID_APP_SCHEME | Intent.URI_ALLOW_UNSAFE); 654 } else if (arg.indexOf('/') >= 0) { 655 // The argument is a component name. Build an Intent to launch 656 // it. 657 baseIntent = new Intent(Intent.ACTION_MAIN); 658 baseIntent.addCategory(Intent.CATEGORY_LAUNCHER); 659 baseIntent.setComponent(ComponentName.unflattenFromString(arg)); 660 } else { 661 // Assume the argument is a package name. 662 baseIntent = new Intent(Intent.ACTION_MAIN); 663 baseIntent.addCategory(Intent.CATEGORY_LAUNCHER); 664 baseIntent.setPackage(arg); 665 } 666 if (baseIntent != null) { 667 Bundle extras = intent.getExtras(); 668 intent.replaceExtras((Bundle)null); 669 Bundle uriExtras = baseIntent.getExtras(); 670 baseIntent.replaceExtras((Bundle)null); 671 if (intent.getAction() != null && baseIntent.getCategories() != null) { 672 HashSet<String> cats = new HashSet<String>(baseIntent.getCategories()); 673 for (String c : cats) { 674 baseIntent.removeCategory(c); 675 } 676 } 677 intent.fillIn(baseIntent, Intent.FILL_IN_COMPONENT | Intent.FILL_IN_SELECTOR); 678 if (extras == null) { 679 extras = uriExtras; 680 } else if (uriExtras != null) { 681 uriExtras.putAll(extras); 682 extras = uriExtras; 683 } 684 intent.replaceExtras(extras); 685 hasIntentInfo = true; 686 } 687 688 if (!hasIntentInfo) throw new IllegalArgumentException("No intent supplied"); 689 return intent; 690 } 691 692 private void runStartService() throws Exception { 693 Intent intent = makeIntent(UserHandle.USER_CURRENT); 694 if (mUserId == UserHandle.USER_ALL) { 695 System.err.println("Error: Can't start activity with user 'all'"); 696 return; 697 } 698 System.out.println("Starting service: " + intent); 699 ComponentName cn = mAm.startService(null, intent, intent.getType(), mUserId); 700 if (cn == null) { 701 System.err.println("Error: Not found; no service started."); 702 } else if (cn.getPackageName().equals("!")) { 703 System.err.println("Error: Requires permission " + cn.getClassName()); 704 } else if (cn.getPackageName().equals("!!")) { 705 System.err.println("Error: " + cn.getClassName()); 706 } 707 } 708 709 private void runStopService() throws Exception { 710 Intent intent = makeIntent(UserHandle.USER_CURRENT); 711 if (mUserId == UserHandle.USER_ALL) { 712 System.err.println("Error: Can't stop activity with user 'all'"); 713 return; 714 } 715 System.out.println("Stopping service: " + intent); 716 int result = mAm.stopService(null, intent, intent.getType(), mUserId); 717 if (result == 0) { 718 System.err.println("Service not stopped: was not running."); 719 } else if (result == 1) { 720 System.err.println("Service stopped"); 721 } else if (result == -1) { 722 System.err.println("Error stopping service"); 723 } 724 } 725 726 private void runStart() throws Exception { 727 Intent intent = makeIntent(UserHandle.USER_CURRENT); 728 729 if (mUserId == UserHandle.USER_ALL) { 730 System.err.println("Error: Can't start service with user 'all'"); 731 return; 732 } 733 734 String mimeType = intent.getType(); 735 if (mimeType == null && intent.getData() != null 736 && "content".equals(intent.getData().getScheme())) { 737 mimeType = mAm.getProviderMimeType(intent.getData(), mUserId); 738 } 739 740 do { 741 if (mStopOption) { 742 String packageName; 743 if (intent.getComponent() != null) { 744 packageName = intent.getComponent().getPackageName(); 745 } else { 746 IPackageManager pm = IPackageManager.Stub.asInterface( 747 ServiceManager.getService("package")); 748 if (pm == null) { 749 System.err.println("Error: Package manager not running; aborting"); 750 return; 751 } 752 List<ResolveInfo> activities = pm.queryIntentActivities(intent, mimeType, 0, 753 mUserId); 754 if (activities == null || activities.size() <= 0) { 755 System.err.println("Error: Intent does not match any activities: " 756 + intent); 757 return; 758 } else if (activities.size() > 1) { 759 System.err.println("Error: Intent matches multiple activities; can't stop: " 760 + intent); 761 return; 762 } 763 packageName = activities.get(0).activityInfo.packageName; 764 } 765 System.out.println("Stopping: " + packageName); 766 mAm.forceStopPackage(packageName, mUserId); 767 Thread.sleep(250); 768 } 769 770 System.out.println("Starting: " + intent); 771 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 772 773 ParcelFileDescriptor fd = null; 774 ProfilerInfo profilerInfo = null; 775 776 if (mProfileFile != null) { 777 try { 778 fd = openForSystemServer( 779 new File(mProfileFile), 780 ParcelFileDescriptor.MODE_CREATE | 781 ParcelFileDescriptor.MODE_TRUNCATE | 782 ParcelFileDescriptor.MODE_READ_WRITE); 783 } catch (FileNotFoundException e) { 784 System.err.println("Error: Unable to open file: " + mProfileFile); 785 System.err.println("Consider using a file under /data/local/tmp/"); 786 return; 787 } 788 profilerInfo = new ProfilerInfo(mProfileFile, fd, mSamplingInterval, mAutoStop); 789 } 790 791 IActivityManager.WaitResult result = null; 792 int res; 793 final long startTime = SystemClock.uptimeMillis(); 794 if (mWaitOption) { 795 result = mAm.startActivityAndWait(null, null, intent, mimeType, 796 null, null, 0, mStartFlags, profilerInfo, null, mUserId); 797 res = result.result; 798 } else { 799 res = mAm.startActivityAsUser(null, null, intent, mimeType, 800 null, null, 0, mStartFlags, profilerInfo, null, mUserId); 801 } 802 final long endTime = SystemClock.uptimeMillis(); 803 PrintStream out = mWaitOption ? System.out : System.err; 804 boolean launched = false; 805 switch (res) { 806 case ActivityManager.START_SUCCESS: 807 launched = true; 808 break; 809 case ActivityManager.START_SWITCHES_CANCELED: 810 launched = true; 811 out.println( 812 "Warning: Activity not started because the " 813 + " current activity is being kept for the user."); 814 break; 815 case ActivityManager.START_DELIVERED_TO_TOP: 816 launched = true; 817 out.println( 818 "Warning: Activity not started, intent has " 819 + "been delivered to currently running " 820 + "top-most instance."); 821 break; 822 case ActivityManager.START_RETURN_INTENT_TO_CALLER: 823 launched = true; 824 out.println( 825 "Warning: Activity not started because intent " 826 + "should be handled by the caller"); 827 break; 828 case ActivityManager.START_TASK_TO_FRONT: 829 launched = true; 830 out.println( 831 "Warning: Activity not started, its current " 832 + "task has been brought to the front"); 833 break; 834 case ActivityManager.START_INTENT_NOT_RESOLVED: 835 out.println( 836 "Error: Activity not started, unable to " 837 + "resolve " + intent.toString()); 838 break; 839 case ActivityManager.START_CLASS_NOT_FOUND: 840 out.println(NO_CLASS_ERROR_CODE); 841 out.println("Error: Activity class " + 842 intent.getComponent().toShortString() 843 + " does not exist."); 844 break; 845 case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT: 846 out.println( 847 "Error: Activity not started, you requested to " 848 + "both forward and receive its result"); 849 break; 850 case ActivityManager.START_PERMISSION_DENIED: 851 out.println( 852 "Error: Activity not started, you do not " 853 + "have permission to access it."); 854 break; 855 case ActivityManager.START_NOT_VOICE_COMPATIBLE: 856 out.println( 857 "Error: Activity not started, voice control not allowed for: " 858 + intent); 859 break; 860 case ActivityManager.START_NOT_CURRENT_USER_ACTIVITY: 861 out.println( 862 "Error: Not allowed to start background user activity" 863 + " that shouldn't be displayed for all users."); 864 break; 865 default: 866 out.println( 867 "Error: Activity not started, unknown error code " + res); 868 break; 869 } 870 if (mWaitOption && launched) { 871 if (result == null) { 872 result = new IActivityManager.WaitResult(); 873 result.who = intent.getComponent(); 874 } 875 System.out.println("Status: " + (result.timeout ? "timeout" : "ok")); 876 if (result.who != null) { 877 System.out.println("Activity: " + result.who.flattenToShortString()); 878 } 879 if (result.thisTime >= 0) { 880 System.out.println("ThisTime: " + result.thisTime); 881 } 882 if (result.totalTime >= 0) { 883 System.out.println("TotalTime: " + result.totalTime); 884 } 885 System.out.println("WaitTime: " + (endTime-startTime)); 886 System.out.println("Complete"); 887 } 888 mRepeat--; 889 if (mRepeat > 1) { 890 mAm.unhandledBack(); 891 } 892 } while (mRepeat > 1); 893 } 894 895 private void runForceStop() throws Exception { 896 int userId = UserHandle.USER_ALL; 897 898 String opt; 899 while ((opt=nextOption()) != null) { 900 if (opt.equals("--user")) { 901 userId = parseUserArg(nextArgRequired()); 902 } else { 903 System.err.println("Error: Unknown option: " + opt); 904 return; 905 } 906 } 907 mAm.forceStopPackage(nextArgRequired(), userId); 908 } 909 910 private void runKill() throws Exception { 911 int userId = UserHandle.USER_ALL; 912 913 String opt; 914 while ((opt=nextOption()) != null) { 915 if (opt.equals("--user")) { 916 userId = parseUserArg(nextArgRequired()); 917 } else { 918 System.err.println("Error: Unknown option: " + opt); 919 return; 920 } 921 } 922 mAm.killBackgroundProcesses(nextArgRequired(), userId); 923 } 924 925 private void runKillAll() throws Exception { 926 mAm.killAllBackgroundProcesses(); 927 } 928 929 private void sendBroadcast() throws Exception { 930 Intent intent = makeIntent(UserHandle.USER_CURRENT); 931 IntentReceiver receiver = new IntentReceiver(); 932 System.out.println("Broadcasting: " + intent); 933 mAm.broadcastIntent(null, intent, null, receiver, 0, null, null, mReceiverPermission, 934 android.app.AppOpsManager.OP_NONE, true, false, mUserId); 935 receiver.waitForFinish(); 936 } 937 938 private void runInstrument() throws Exception { 939 String profileFile = null; 940 boolean wait = false; 941 boolean rawMode = false; 942 boolean no_window_animation = false; 943 int userId = UserHandle.USER_CURRENT; 944 Bundle args = new Bundle(); 945 String argKey = null, argValue = null; 946 IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.getService("window")); 947 String abi = null; 948 949 String opt; 950 while ((opt=nextOption()) != null) { 951 if (opt.equals("-p")) { 952 profileFile = nextArgRequired(); 953 } else if (opt.equals("-w")) { 954 wait = true; 955 } else if (opt.equals("-r")) { 956 rawMode = true; 957 } else if (opt.equals("-e")) { 958 argKey = nextArgRequired(); 959 argValue = nextArgRequired(); 960 args.putString(argKey, argValue); 961 } else if (opt.equals("--no_window_animation") 962 || opt.equals("--no-window-animation")) { 963 no_window_animation = true; 964 } else if (opt.equals("--user")) { 965 userId = parseUserArg(nextArgRequired()); 966 } else if (opt.equals("--abi")) { 967 abi = nextArgRequired(); 968 } else { 969 System.err.println("Error: Unknown option: " + opt); 970 return; 971 } 972 } 973 974 if (userId == UserHandle.USER_ALL) { 975 System.err.println("Error: Can't start instrumentation with user 'all'"); 976 return; 977 } 978 979 String cnArg = nextArgRequired(); 980 ComponentName cn = ComponentName.unflattenFromString(cnArg); 981 if (cn == null) throw new IllegalArgumentException("Bad component name: " + cnArg); 982 983 InstrumentationWatcher watcher = null; 984 UiAutomationConnection connection = null; 985 if (wait) { 986 watcher = new InstrumentationWatcher(); 987 watcher.setRawOutput(rawMode); 988 connection = new UiAutomationConnection(); 989 } 990 991 float[] oldAnims = null; 992 if (no_window_animation) { 993 oldAnims = wm.getAnimationScales(); 994 wm.setAnimationScale(0, 0.0f); 995 wm.setAnimationScale(1, 0.0f); 996 } 997 998 if (abi != null) { 999 final String[] supportedAbis = Build.SUPPORTED_ABIS; 1000 boolean matched = false; 1001 for (String supportedAbi : supportedAbis) { 1002 if (supportedAbi.equals(abi)) { 1003 matched = true; 1004 break; 1005 } 1006 } 1007 1008 if (!matched) { 1009 throw new AndroidException( 1010 "INSTRUMENTATION_FAILED: Unsupported instruction set " + abi); 1011 } 1012 } 1013 1014 if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher, connection, userId, abi)) { 1015 throw new AndroidException("INSTRUMENTATION_FAILED: " + cn.flattenToString()); 1016 } 1017 1018 if (watcher != null) { 1019 if (!watcher.waitForFinish()) { 1020 System.out.println("INSTRUMENTATION_ABORTED: System has crashed."); 1021 } 1022 } 1023 1024 if (oldAnims != null) { 1025 wm.setAnimationScales(oldAnims); 1026 } 1027 } 1028 1029 static void removeWallOption() { 1030 String props = SystemProperties.get("dalvik.vm.extra-opts"); 1031 if (props != null && props.contains("-Xprofile:wallclock")) { 1032 props = props.replace("-Xprofile:wallclock", ""); 1033 props = props.trim(); 1034 SystemProperties.set("dalvik.vm.extra-opts", props); 1035 } 1036 } 1037 1038 private void runProfile() throws Exception { 1039 String profileFile = null; 1040 boolean start = false; 1041 boolean wall = false; 1042 int userId = UserHandle.USER_CURRENT; 1043 int profileType = 0; 1044 mSamplingInterval = 0; 1045 1046 String process = null; 1047 1048 String cmd = nextArgRequired(); 1049 1050 if ("start".equals(cmd)) { 1051 start = true; 1052 String opt; 1053 while ((opt=nextOption()) != null) { 1054 if (opt.equals("--user")) { 1055 userId = parseUserArg(nextArgRequired()); 1056 } else if (opt.equals("--wall")) { 1057 wall = true; 1058 } else if (opt.equals("--sampling")) { 1059 mSamplingInterval = Integer.parseInt(nextArgRequired()); 1060 } else { 1061 System.err.println("Error: Unknown option: " + opt); 1062 return; 1063 } 1064 } 1065 process = nextArgRequired(); 1066 } else if ("stop".equals(cmd)) { 1067 String opt; 1068 while ((opt=nextOption()) != null) { 1069 if (opt.equals("--user")) { 1070 userId = parseUserArg(nextArgRequired()); 1071 } else { 1072 System.err.println("Error: Unknown option: " + opt); 1073 return; 1074 } 1075 } 1076 process = nextArg(); 1077 } else { 1078 // Compatibility with old syntax: process is specified first. 1079 process = cmd; 1080 cmd = nextArgRequired(); 1081 if ("start".equals(cmd)) { 1082 start = true; 1083 } else if (!"stop".equals(cmd)) { 1084 throw new IllegalArgumentException("Profile command " + process + " not valid"); 1085 } 1086 } 1087 1088 if (userId == UserHandle.USER_ALL) { 1089 System.err.println("Error: Can't profile with user 'all'"); 1090 return; 1091 } 1092 1093 ParcelFileDescriptor fd = null; 1094 ProfilerInfo profilerInfo = null; 1095 1096 if (start) { 1097 profileFile = nextArgRequired(); 1098 try { 1099 fd = openForSystemServer( 1100 new File(profileFile), 1101 ParcelFileDescriptor.MODE_CREATE | 1102 ParcelFileDescriptor.MODE_TRUNCATE | 1103 ParcelFileDescriptor.MODE_READ_WRITE); 1104 } catch (FileNotFoundException e) { 1105 System.err.println("Error: Unable to open file: " + profileFile); 1106 System.err.println("Consider using a file under /data/local/tmp/"); 1107 return; 1108 } 1109 profilerInfo = new ProfilerInfo(profileFile, fd, mSamplingInterval, false); 1110 } 1111 1112 try { 1113 if (wall) { 1114 // XXX doesn't work -- this needs to be set before booting. 1115 String props = SystemProperties.get("dalvik.vm.extra-opts"); 1116 if (props == null || !props.contains("-Xprofile:wallclock")) { 1117 props = props + " -Xprofile:wallclock"; 1118 //SystemProperties.set("dalvik.vm.extra-opts", props); 1119 } 1120 } else if (start) { 1121 //removeWallOption(); 1122 } 1123 if (!mAm.profileControl(process, userId, start, profilerInfo, profileType)) { 1124 wall = false; 1125 throw new AndroidException("PROFILE FAILED on process " + process); 1126 } 1127 } finally { 1128 if (!wall) { 1129 //removeWallOption(); 1130 } 1131 } 1132 } 1133 1134 private void runDumpHeap() throws Exception { 1135 boolean managed = true; 1136 int userId = UserHandle.USER_CURRENT; 1137 1138 String opt; 1139 while ((opt=nextOption()) != null) { 1140 if (opt.equals("--user")) { 1141 userId = parseUserArg(nextArgRequired()); 1142 if (userId == UserHandle.USER_ALL) { 1143 System.err.println("Error: Can't dump heap with user 'all'"); 1144 return; 1145 } 1146 } else if (opt.equals("-n")) { 1147 managed = false; 1148 } else { 1149 System.err.println("Error: Unknown option: " + opt); 1150 return; 1151 } 1152 } 1153 String process = nextArgRequired(); 1154 String heapFile = nextArgRequired(); 1155 ParcelFileDescriptor fd = null; 1156 1157 try { 1158 File file = new File(heapFile); 1159 file.delete(); 1160 fd = openForSystemServer(file, 1161 ParcelFileDescriptor.MODE_CREATE | 1162 ParcelFileDescriptor.MODE_TRUNCATE | 1163 ParcelFileDescriptor.MODE_READ_WRITE); 1164 } catch (FileNotFoundException e) { 1165 System.err.println("Error: Unable to open file: " + heapFile); 1166 System.err.println("Consider using a file under /data/local/tmp/"); 1167 return; 1168 } 1169 1170 if (!mAm.dumpHeap(process, userId, managed, heapFile, fd)) { 1171 throw new AndroidException("HEAP DUMP FAILED on process " + process); 1172 } 1173 } 1174 1175 private void runSetDebugApp() throws Exception { 1176 boolean wait = false; 1177 boolean persistent = false; 1178 1179 String opt; 1180 while ((opt=nextOption()) != null) { 1181 if (opt.equals("-w")) { 1182 wait = true; 1183 } else if (opt.equals("--persistent")) { 1184 persistent = true; 1185 } else { 1186 System.err.println("Error: Unknown option: " + opt); 1187 return; 1188 } 1189 } 1190 1191 String pkg = nextArgRequired(); 1192 mAm.setDebugApp(pkg, wait, persistent); 1193 } 1194 1195 private void runClearDebugApp() throws Exception { 1196 mAm.setDebugApp(null, false, true); 1197 } 1198 1199 private void runSetWatchHeap() throws Exception { 1200 String proc = nextArgRequired(); 1201 String limit = nextArgRequired(); 1202 mAm.setDumpHeapDebugLimit(proc, 0, Long.parseLong(limit), null); 1203 } 1204 1205 private void runClearWatchHeap() throws Exception { 1206 String proc = nextArgRequired(); 1207 mAm.setDumpHeapDebugLimit(proc, 0, -1, null); 1208 } 1209 1210 private void runBugReport() throws Exception { 1211 mAm.requestBugReport(); 1212 System.out.println("Your lovely bug report is being created; please be patient."); 1213 } 1214 1215 private void runSwitchUser() throws Exception { 1216 String user = nextArgRequired(); 1217 mAm.switchUser(Integer.parseInt(user)); 1218 } 1219 1220 private void runStartUserInBackground() throws Exception { 1221 String user = nextArgRequired(); 1222 boolean success = mAm.startUserInBackground(Integer.parseInt(user)); 1223 if (success) { 1224 System.out.println("Success: user started"); 1225 } else { 1226 System.err.println("Error: could not start user"); 1227 } 1228 } 1229 1230 private void runStopUser() throws Exception { 1231 String user = nextArgRequired(); 1232 int res = mAm.stopUser(Integer.parseInt(user), null); 1233 if (res != ActivityManager.USER_OP_SUCCESS) { 1234 String txt = ""; 1235 switch (res) { 1236 case ActivityManager.USER_OP_IS_CURRENT: 1237 txt = " (Can't stop current user)"; 1238 break; 1239 case ActivityManager.USER_OP_UNKNOWN_USER: 1240 txt = " (Unknown user " + user + ")"; 1241 break; 1242 } 1243 System.err.println("Switch failed: " + res + txt); 1244 } 1245 } 1246 1247 class MyActivityController extends IActivityController.Stub { 1248 final String mGdbPort; 1249 1250 static final int STATE_NORMAL = 0; 1251 static final int STATE_CRASHED = 1; 1252 static final int STATE_EARLY_ANR = 2; 1253 static final int STATE_ANR = 3; 1254 1255 int mState; 1256 1257 static final int RESULT_DEFAULT = 0; 1258 1259 static final int RESULT_CRASH_DIALOG = 0; 1260 static final int RESULT_CRASH_KILL = 1; 1261 1262 static final int RESULT_EARLY_ANR_CONTINUE = 0; 1263 static final int RESULT_EARLY_ANR_KILL = 1; 1264 1265 static final int RESULT_ANR_DIALOG = 0; 1266 static final int RESULT_ANR_KILL = 1; 1267 static final int RESULT_ANR_WAIT = 1; 1268 1269 int mResult; 1270 1271 Process mGdbProcess; 1272 Thread mGdbThread; 1273 boolean mGotGdbPrint; 1274 1275 MyActivityController(String gdbPort) { 1276 mGdbPort = gdbPort; 1277 } 1278 1279 @Override 1280 public boolean activityResuming(String pkg) { 1281 synchronized (this) { 1282 System.out.println("** Activity resuming: " + pkg); 1283 } 1284 return true; 1285 } 1286 1287 @Override 1288 public boolean activityStarting(Intent intent, String pkg) { 1289 synchronized (this) { 1290 System.out.println("** Activity starting: " + pkg); 1291 } 1292 return true; 1293 } 1294 1295 @Override 1296 public boolean appCrashed(String processName, int pid, String shortMsg, String longMsg, 1297 long timeMillis, String stackTrace) { 1298 synchronized (this) { 1299 System.out.println("** ERROR: PROCESS CRASHED"); 1300 System.out.println("processName: " + processName); 1301 System.out.println("processPid: " + pid); 1302 System.out.println("shortMsg: " + shortMsg); 1303 System.out.println("longMsg: " + longMsg); 1304 System.out.println("timeMillis: " + timeMillis); 1305 System.out.println("stack:"); 1306 System.out.print(stackTrace); 1307 System.out.println("#"); 1308 int result = waitControllerLocked(pid, STATE_CRASHED); 1309 return result == RESULT_CRASH_KILL ? false : true; 1310 } 1311 } 1312 1313 @Override 1314 public int appEarlyNotResponding(String processName, int pid, String annotation) { 1315 synchronized (this) { 1316 System.out.println("** ERROR: EARLY PROCESS NOT RESPONDING"); 1317 System.out.println("processName: " + processName); 1318 System.out.println("processPid: " + pid); 1319 System.out.println("annotation: " + annotation); 1320 int result = waitControllerLocked(pid, STATE_EARLY_ANR); 1321 if (result == RESULT_EARLY_ANR_KILL) return -1; 1322 return 0; 1323 } 1324 } 1325 1326 @Override 1327 public int appNotResponding(String processName, int pid, String processStats) { 1328 synchronized (this) { 1329 System.out.println("** ERROR: PROCESS NOT RESPONDING"); 1330 System.out.println("processName: " + processName); 1331 System.out.println("processPid: " + pid); 1332 System.out.println("processStats:"); 1333 System.out.print(processStats); 1334 System.out.println("#"); 1335 int result = waitControllerLocked(pid, STATE_ANR); 1336 if (result == RESULT_ANR_KILL) return -1; 1337 if (result == RESULT_ANR_WAIT) return 1; 1338 return 0; 1339 } 1340 } 1341 1342 @Override 1343 public int systemNotResponding(String message) { 1344 synchronized (this) { 1345 System.out.println("** ERROR: PROCESS NOT RESPONDING"); 1346 System.out.println("message: " + message); 1347 System.out.println("#"); 1348 System.out.println("Allowing system to die."); 1349 return -1; 1350 } 1351 } 1352 1353 void killGdbLocked() { 1354 mGotGdbPrint = false; 1355 if (mGdbProcess != null) { 1356 System.out.println("Stopping gdbserver"); 1357 mGdbProcess.destroy(); 1358 mGdbProcess = null; 1359 } 1360 if (mGdbThread != null) { 1361 mGdbThread.interrupt(); 1362 mGdbThread = null; 1363 } 1364 } 1365 1366 int waitControllerLocked(int pid, int state) { 1367 if (mGdbPort != null) { 1368 killGdbLocked(); 1369 1370 try { 1371 System.out.println("Starting gdbserver on port " + mGdbPort); 1372 System.out.println("Do the following:"); 1373 System.out.println(" adb forward tcp:" + mGdbPort + " tcp:" + mGdbPort); 1374 System.out.println(" gdbclient app_process :" + mGdbPort); 1375 1376 mGdbProcess = Runtime.getRuntime().exec(new String[] { 1377 "gdbserver", ":" + mGdbPort, "--attach", Integer.toString(pid) 1378 }); 1379 final InputStreamReader converter = new InputStreamReader( 1380 mGdbProcess.getInputStream()); 1381 mGdbThread = new Thread() { 1382 @Override 1383 public void run() { 1384 BufferedReader in = new BufferedReader(converter); 1385 String line; 1386 int count = 0; 1387 while (true) { 1388 synchronized (MyActivityController.this) { 1389 if (mGdbThread == null) { 1390 return; 1391 } 1392 if (count == 2) { 1393 mGotGdbPrint = true; 1394 MyActivityController.this.notifyAll(); 1395 } 1396 } 1397 try { 1398 line = in.readLine(); 1399 if (line == null) { 1400 return; 1401 } 1402 System.out.println("GDB: " + line); 1403 count++; 1404 } catch (IOException e) { 1405 return; 1406 } 1407 } 1408 } 1409 }; 1410 mGdbThread.start(); 1411 1412 // Stupid waiting for .5s. Doesn't matter if we end early. 1413 try { 1414 this.wait(500); 1415 } catch (InterruptedException e) { 1416 } 1417 1418 } catch (IOException e) { 1419 System.err.println("Failure starting gdbserver: " + e); 1420 killGdbLocked(); 1421 } 1422 } 1423 mState = state; 1424 System.out.println(""); 1425 printMessageForState(); 1426 1427 while (mState != STATE_NORMAL) { 1428 try { 1429 wait(); 1430 } catch (InterruptedException e) { 1431 } 1432 } 1433 1434 killGdbLocked(); 1435 1436 return mResult; 1437 } 1438 1439 void resumeController(int result) { 1440 synchronized (this) { 1441 mState = STATE_NORMAL; 1442 mResult = result; 1443 notifyAll(); 1444 } 1445 } 1446 1447 void printMessageForState() { 1448 switch (mState) { 1449 case STATE_NORMAL: 1450 System.out.println("Monitoring activity manager... available commands:"); 1451 break; 1452 case STATE_CRASHED: 1453 System.out.println("Waiting after crash... available commands:"); 1454 System.out.println("(c)ontinue: show crash dialog"); 1455 System.out.println("(k)ill: immediately kill app"); 1456 break; 1457 case STATE_EARLY_ANR: 1458 System.out.println("Waiting after early ANR... available commands:"); 1459 System.out.println("(c)ontinue: standard ANR processing"); 1460 System.out.println("(k)ill: immediately kill app"); 1461 break; 1462 case STATE_ANR: 1463 System.out.println("Waiting after ANR... available commands:"); 1464 System.out.println("(c)ontinue: show ANR dialog"); 1465 System.out.println("(k)ill: immediately kill app"); 1466 System.out.println("(w)ait: wait some more"); 1467 break; 1468 } 1469 System.out.println("(q)uit: finish monitoring"); 1470 } 1471 1472 void run() throws RemoteException { 1473 try { 1474 printMessageForState(); 1475 1476 mAm.setActivityController(this); 1477 mState = STATE_NORMAL; 1478 1479 InputStreamReader converter = new InputStreamReader(System.in); 1480 BufferedReader in = new BufferedReader(converter); 1481 String line; 1482 1483 while ((line = in.readLine()) != null) { 1484 boolean addNewline = true; 1485 if (line.length() <= 0) { 1486 addNewline = false; 1487 } else if ("q".equals(line) || "quit".equals(line)) { 1488 resumeController(RESULT_DEFAULT); 1489 break; 1490 } else if (mState == STATE_CRASHED) { 1491 if ("c".equals(line) || "continue".equals(line)) { 1492 resumeController(RESULT_CRASH_DIALOG); 1493 } else if ("k".equals(line) || "kill".equals(line)) { 1494 resumeController(RESULT_CRASH_KILL); 1495 } else { 1496 System.out.println("Invalid command: " + line); 1497 } 1498 } else if (mState == STATE_ANR) { 1499 if ("c".equals(line) || "continue".equals(line)) { 1500 resumeController(RESULT_ANR_DIALOG); 1501 } else if ("k".equals(line) || "kill".equals(line)) { 1502 resumeController(RESULT_ANR_KILL); 1503 } else if ("w".equals(line) || "wait".equals(line)) { 1504 resumeController(RESULT_ANR_WAIT); 1505 } else { 1506 System.out.println("Invalid command: " + line); 1507 } 1508 } else if (mState == STATE_EARLY_ANR) { 1509 if ("c".equals(line) || "continue".equals(line)) { 1510 resumeController(RESULT_EARLY_ANR_CONTINUE); 1511 } else if ("k".equals(line) || "kill".equals(line)) { 1512 resumeController(RESULT_EARLY_ANR_KILL); 1513 } else { 1514 System.out.println("Invalid command: " + line); 1515 } 1516 } else { 1517 System.out.println("Invalid command: " + line); 1518 } 1519 1520 synchronized (this) { 1521 if (addNewline) { 1522 System.out.println(""); 1523 } 1524 printMessageForState(); 1525 } 1526 } 1527 1528 } catch (IOException e) { 1529 e.printStackTrace(); 1530 } finally { 1531 mAm.setActivityController(null); 1532 } 1533 } 1534 } 1535 1536 private void runMonitor() throws Exception { 1537 String opt; 1538 String gdbPort = null; 1539 while ((opt=nextOption()) != null) { 1540 if (opt.equals("--gdb")) { 1541 gdbPort = nextArgRequired(); 1542 } else { 1543 System.err.println("Error: Unknown option: " + opt); 1544 return; 1545 } 1546 } 1547 1548 MyActivityController controller = new MyActivityController(gdbPort); 1549 controller.run(); 1550 } 1551 1552 private void runHang() throws Exception { 1553 String opt; 1554 boolean allowRestart = false; 1555 while ((opt=nextOption()) != null) { 1556 if (opt.equals("--allow-restart")) { 1557 allowRestart = true; 1558 } else { 1559 System.err.println("Error: Unknown option: " + opt); 1560 return; 1561 } 1562 } 1563 1564 System.out.println("Hanging the system..."); 1565 mAm.hang(new Binder(), allowRestart); 1566 } 1567 1568 private void runRestart() throws Exception { 1569 String opt; 1570 while ((opt=nextOption()) != null) { 1571 System.err.println("Error: Unknown option: " + opt); 1572 return; 1573 } 1574 1575 System.out.println("Restart the system..."); 1576 mAm.restart(); 1577 } 1578 1579 private void runIdleMaintenance() throws Exception { 1580 String opt; 1581 while ((opt=nextOption()) != null) { 1582 System.err.println("Error: Unknown option: " + opt); 1583 return; 1584 } 1585 1586 System.out.println("Performing idle maintenance..."); 1587 Intent intent = new Intent( 1588 "com.android.server.task.controllers.IdleController.ACTION_TRIGGER_IDLE"); 1589 mAm.broadcastIntent(null, intent, null, null, 0, null, null, null, 1590 android.app.AppOpsManager.OP_NONE, true, false, UserHandle.USER_ALL); 1591 } 1592 1593 private void runScreenCompat() throws Exception { 1594 String mode = nextArgRequired(); 1595 boolean enabled; 1596 if ("on".equals(mode)) { 1597 enabled = true; 1598 } else if ("off".equals(mode)) { 1599 enabled = false; 1600 } else { 1601 System.err.println("Error: enabled mode must be 'on' or 'off' at " + mode); 1602 return; 1603 } 1604 1605 String packageName = nextArgRequired(); 1606 do { 1607 try { 1608 mAm.setPackageScreenCompatMode(packageName, enabled 1609 ? ActivityManager.COMPAT_MODE_ENABLED 1610 : ActivityManager.COMPAT_MODE_DISABLED); 1611 } catch (RemoteException e) { 1612 } 1613 packageName = nextArg(); 1614 } while (packageName != null); 1615 } 1616 1617 private void runPackageImportance() throws Exception { 1618 String packageName = nextArgRequired(); 1619 try { 1620 int procState = mAm.getPackageProcessState(packageName); 1621 System.out.println( 1622 ActivityManager.RunningAppProcessInfo.procStateToImportance(procState)); 1623 } catch (RemoteException e) { 1624 } 1625 } 1626 1627 private void runToUri(int flags) throws Exception { 1628 Intent intent = makeIntent(UserHandle.USER_CURRENT); 1629 System.out.println(intent.toUri(flags)); 1630 } 1631 1632 private class IntentReceiver extends IIntentReceiver.Stub { 1633 private boolean mFinished = false; 1634 1635 @Override 1636 public void performReceive(Intent intent, int resultCode, String data, Bundle extras, 1637 boolean ordered, boolean sticky, int sendingUser) { 1638 String line = "Broadcast completed: result=" + resultCode; 1639 if (data != null) line = line + ", data=\"" + data + "\""; 1640 if (extras != null) line = line + ", extras: " + extras; 1641 System.out.println(line); 1642 synchronized (this) { 1643 mFinished = true; 1644 notifyAll(); 1645 } 1646 } 1647 1648 public synchronized void waitForFinish() { 1649 try { 1650 while (!mFinished) wait(); 1651 } catch (InterruptedException e) { 1652 throw new IllegalStateException(e); 1653 } 1654 } 1655 } 1656 1657 private class InstrumentationWatcher extends IInstrumentationWatcher.Stub { 1658 private boolean mFinished = false; 1659 private boolean mRawMode = false; 1660 1661 /** 1662 * Set or reset "raw mode". In "raw mode", all bundles are dumped. In "pretty mode", 1663 * if a bundle includes Instrumentation.REPORT_KEY_STREAMRESULT, just print that. 1664 * @param rawMode true for raw mode, false for pretty mode. 1665 */ 1666 public void setRawOutput(boolean rawMode) { 1667 mRawMode = rawMode; 1668 } 1669 1670 @Override 1671 public void instrumentationStatus(ComponentName name, int resultCode, Bundle results) { 1672 synchronized (this) { 1673 // pretty printer mode? 1674 String pretty = null; 1675 if (!mRawMode && results != null) { 1676 pretty = results.getString(Instrumentation.REPORT_KEY_STREAMRESULT); 1677 } 1678 if (pretty != null) { 1679 System.out.print(pretty); 1680 } else { 1681 if (results != null) { 1682 for (String key : results.keySet()) { 1683 System.out.println( 1684 "INSTRUMENTATION_STATUS: " + key + "=" + results.get(key)); 1685 } 1686 } 1687 System.out.println("INSTRUMENTATION_STATUS_CODE: " + resultCode); 1688 } 1689 notifyAll(); 1690 } 1691 } 1692 1693 @Override 1694 public void instrumentationFinished(ComponentName name, int resultCode, 1695 Bundle results) { 1696 synchronized (this) { 1697 // pretty printer mode? 1698 String pretty = null; 1699 if (!mRawMode && results != null) { 1700 pretty = results.getString(Instrumentation.REPORT_KEY_STREAMRESULT); 1701 } 1702 if (pretty != null) { 1703 System.out.println(pretty); 1704 } else { 1705 if (results != null) { 1706 for (String key : results.keySet()) { 1707 System.out.println( 1708 "INSTRUMENTATION_RESULT: " + key + "=" + results.get(key)); 1709 } 1710 } 1711 System.out.println("INSTRUMENTATION_CODE: " + resultCode); 1712 } 1713 mFinished = true; 1714 notifyAll(); 1715 } 1716 } 1717 1718 public boolean waitForFinish() { 1719 synchronized (this) { 1720 while (!mFinished) { 1721 try { 1722 if (!mAm.asBinder().pingBinder()) { 1723 return false; 1724 } 1725 wait(1000); 1726 } catch (InterruptedException e) { 1727 throw new IllegalStateException(e); 1728 } 1729 } 1730 } 1731 return true; 1732 } 1733 } 1734 1735 private void runStack() throws Exception { 1736 String op = nextArgRequired(); 1737 if (op.equals("start")) { 1738 runStackStart(); 1739 } else if (op.equals("movetask")) { 1740 runStackMoveTask(); 1741 } else if (op.equals("resize")) { 1742 runStackResize(); 1743 } else if (op.equals("list")) { 1744 runStackList(); 1745 } else if (op.equals("info")) { 1746 runStackInfo(); 1747 } else if (op.equals("split")) { 1748 runStackSplit(); 1749 } else { 1750 showError("Error: unknown command '" + op + "'"); 1751 return; 1752 } 1753 } 1754 1755 private void runStackStart() throws Exception { 1756 String displayIdStr = nextArgRequired(); 1757 int displayId = Integer.valueOf(displayIdStr); 1758 Intent intent = makeIntent(UserHandle.USER_CURRENT); 1759 1760 try { 1761 IActivityContainer container = mAm.createStackOnDisplay(displayId); 1762 if (container != null) { 1763 container.startActivity(intent); 1764 } 1765 } catch (RemoteException e) { 1766 } 1767 } 1768 1769 private void runStackMoveTask() throws Exception { 1770 String taskIdStr = nextArgRequired(); 1771 int taskId = Integer.valueOf(taskIdStr); 1772 String stackIdStr = nextArgRequired(); 1773 int stackId = Integer.valueOf(stackIdStr); 1774 String toTopStr = nextArgRequired(); 1775 final boolean toTop; 1776 if ("true".equals(toTopStr)) { 1777 toTop = true; 1778 } else if ("false".equals(toTopStr)) { 1779 toTop = false; 1780 } else { 1781 System.err.println("Error: bad toTop arg: " + toTopStr); 1782 return; 1783 } 1784 1785 try { 1786 mAm.moveTaskToStack(taskId, stackId, toTop); 1787 } catch (RemoteException e) { 1788 } 1789 } 1790 1791 private void runStackResize() throws Exception { 1792 String stackIdStr = nextArgRequired(); 1793 int stackId = Integer.valueOf(stackIdStr); 1794 final Rect bounds = getBounds(); 1795 if (bounds == null) { 1796 System.err.println("Error: invalid input bounds"); 1797 return; 1798 } 1799 1800 try { 1801 mAm.resizeStack(stackId, bounds); 1802 } catch (RemoteException e) { 1803 } 1804 } 1805 1806 private void runStackList() throws Exception { 1807 try { 1808 List<StackInfo> stacks = mAm.getAllStackInfos(); 1809 for (StackInfo info : stacks) { 1810 System.out.println(info); 1811 } 1812 } catch (RemoteException e) { 1813 } 1814 } 1815 1816 private void runStackInfo() throws Exception { 1817 try { 1818 String stackIdStr = nextArgRequired(); 1819 int stackId = Integer.valueOf(stackIdStr); 1820 StackInfo info = mAm.getStackInfo(stackId); 1821 System.out.println(info); 1822 } catch (RemoteException e) { 1823 } 1824 } 1825 1826 private void runStackSplit() throws Exception { 1827 final int stackId = Integer.valueOf(nextArgRequired()); 1828 final String splitDirection = nextArgRequired(); 1829 Intent intent = null; 1830 try { 1831 intent = makeIntent(UserHandle.USER_CURRENT); 1832 } catch (IllegalArgumentException e) { 1833 // no intent supplied. 1834 } 1835 1836 try { 1837 final StackInfo currentStackInfo = mAm.getStackInfo(stackId); 1838 // Calculate bounds for new and current stack. 1839 final Rect currentStackBounds = new Rect(currentStackInfo.bounds); 1840 final Rect newStackBounds = new Rect(currentStackInfo.bounds); 1841 if ("v".equals(splitDirection)) { 1842 currentStackBounds.right = newStackBounds.left = currentStackInfo.bounds.centerX(); 1843 } else if ("h".equals(splitDirection)) { 1844 currentStackBounds.bottom = newStackBounds.top = currentStackInfo.bounds.centerY(); 1845 } else { 1846 showError("Error: unknown split direction '" + splitDirection + "'"); 1847 return; 1848 } 1849 1850 // Create new stack 1851 IActivityContainer container = mAm.createStackOnDisplay(currentStackInfo.displayId); 1852 if (container == null) { 1853 showError("Error: Unable to create new stack..."); 1854 } 1855 1856 final int newStackId = container.getStackId(); 1857 1858 if (intent != null) { 1859 container.startActivity(intent); 1860 } else if (currentStackInfo.taskIds != null && currentStackInfo.taskIds.length > 1) { 1861 // Move top task over to new stack 1862 mAm.moveTaskToStack(currentStackInfo.taskIds[currentStackInfo.taskIds.length - 1], 1863 newStackId, true); 1864 } 1865 1866 final StackInfo newStackInfo = mAm.getStackInfo(newStackId); 1867 1868 // Make all tasks in the stacks resizeable. 1869 for (int taskId : currentStackInfo.taskIds) { 1870 mAm.setTaskResizeable(taskId, true); 1871 } 1872 1873 for (int taskId : newStackInfo.taskIds) { 1874 mAm.setTaskResizeable(taskId, true); 1875 } 1876 1877 // Resize stacks 1878 mAm.resizeStack(currentStackInfo.stackId, currentStackBounds); 1879 mAm.resizeStack(newStackInfo.stackId, newStackBounds); 1880 } catch (RemoteException e) { 1881 } 1882 } 1883 1884 private void runTask() throws Exception { 1885 String op = nextArgRequired(); 1886 if (op.equals("lock")) { 1887 runTaskLock(); 1888 } else if (op.equals("resizeable")) { 1889 runTaskResizeable(); 1890 } else if (op.equals("resize")) { 1891 runTaskResize(); 1892 } else { 1893 showError("Error: unknown command '" + op + "'"); 1894 return; 1895 } 1896 } 1897 1898 private void runTaskLock() throws Exception { 1899 String taskIdStr = nextArgRequired(); 1900 try { 1901 if (taskIdStr.equals("stop")) { 1902 mAm.stopLockTaskMode(); 1903 } else { 1904 int taskId = Integer.valueOf(taskIdStr); 1905 mAm.startLockTaskMode(taskId); 1906 } 1907 System.err.println("Activity manager is " + (mAm.isInLockTaskMode() ? "" : "not ") + 1908 "in lockTaskMode"); 1909 } catch (RemoteException e) { 1910 } 1911 } 1912 1913 private void runTaskResizeable() throws Exception { 1914 final String taskIdStr = nextArgRequired(); 1915 final int taskId = Integer.valueOf(taskIdStr); 1916 final String resizeableStr = nextArgRequired(); 1917 final boolean resizeable = Boolean.valueOf(resizeableStr); 1918 1919 try { 1920 mAm.setTaskResizeable(taskId, resizeable); 1921 } catch (RemoteException e) { 1922 } 1923 } 1924 1925 private void runTaskResize() throws Exception { 1926 final String taskIdStr = nextArgRequired(); 1927 final int taskId = Integer.valueOf(taskIdStr); 1928 final Rect bounds = getBounds(); 1929 if (bounds == null) { 1930 System.err.println("Error: invalid input bounds"); 1931 return; 1932 } 1933 try { 1934 mAm.resizeTask(taskId, bounds); 1935 } catch (RemoteException e) { 1936 } 1937 } 1938 1939 private List<Configuration> getRecentConfigurations(int days) { 1940 IUsageStatsManager usm = IUsageStatsManager.Stub.asInterface(ServiceManager.getService( 1941 Context.USAGE_STATS_SERVICE)); 1942 final long now = System.currentTimeMillis(); 1943 final long nDaysAgo = now - (days * 24 * 60 * 60 * 1000); 1944 try { 1945 @SuppressWarnings("unchecked") 1946 ParceledListSlice<ConfigurationStats> configStatsSlice = usm.queryConfigurationStats( 1947 UsageStatsManager.INTERVAL_BEST, nDaysAgo, now, "com.android.shell"); 1948 if (configStatsSlice == null) { 1949 return Collections.emptyList(); 1950 } 1951 1952 final ArrayMap<Configuration, Integer> recentConfigs = new ArrayMap<>(); 1953 final List<ConfigurationStats> configStatsList = configStatsSlice.getList(); 1954 final int configStatsListSize = configStatsList.size(); 1955 for (int i = 0; i < configStatsListSize; i++) { 1956 final ConfigurationStats stats = configStatsList.get(i); 1957 final int indexOfKey = recentConfigs.indexOfKey(stats.getConfiguration()); 1958 if (indexOfKey < 0) { 1959 recentConfigs.put(stats.getConfiguration(), stats.getActivationCount()); 1960 } else { 1961 recentConfigs.setValueAt(indexOfKey, 1962 recentConfigs.valueAt(indexOfKey) + stats.getActivationCount()); 1963 } 1964 } 1965 1966 final Comparator<Configuration> comparator = new Comparator<Configuration>() { 1967 @Override 1968 public int compare(Configuration a, Configuration b) { 1969 return recentConfigs.get(b).compareTo(recentConfigs.get(a)); 1970 } 1971 }; 1972 1973 ArrayList<Configuration> configs = new ArrayList<>(recentConfigs.size()); 1974 configs.addAll(recentConfigs.keySet()); 1975 Collections.sort(configs, comparator); 1976 return configs; 1977 1978 } catch (RemoteException e) { 1979 return Collections.emptyList(); 1980 } 1981 } 1982 1983 private void runGetConfig() throws Exception { 1984 int days = 14; 1985 String option = nextOption(); 1986 if (option != null) { 1987 if (!option.equals("--days")) { 1988 throw new IllegalArgumentException("unrecognized option " + option); 1989 } 1990 1991 days = Integer.parseInt(nextArgRequired()); 1992 if (days <= 0) { 1993 throw new IllegalArgumentException("--days must be a positive integer"); 1994 } 1995 } 1996 1997 try { 1998 Configuration config = mAm.getConfiguration(); 1999 if (config == null) { 2000 System.err.println("Activity manager has no configuration"); 2001 return; 2002 } 2003 2004 System.out.println("config: " + Configuration.resourceQualifierString(config)); 2005 System.out.println("abi: " + TextUtils.join(",", Build.SUPPORTED_ABIS)); 2006 2007 final List<Configuration> recentConfigs = getRecentConfigurations(days); 2008 final int recentConfigSize = recentConfigs.size(); 2009 if (recentConfigSize > 0) { 2010 System.out.println("recentConfigs:"); 2011 } 2012 2013 for (int i = 0; i < recentConfigSize; i++) { 2014 System.out.println(" config: " + Configuration.resourceQualifierString( 2015 recentConfigs.get(i))); 2016 } 2017 2018 } catch (RemoteException e) { 2019 } 2020 } 2021 2022 /** 2023 * Open the given file for sending into the system process. This verifies 2024 * with SELinux that the system will have access to the file. 2025 */ 2026 private static ParcelFileDescriptor openForSystemServer(File file, int mode) 2027 throws FileNotFoundException { 2028 final ParcelFileDescriptor fd = ParcelFileDescriptor.open(file, mode); 2029 final String tcon = SELinux.getFileContext(file.getAbsolutePath()); 2030 if (!SELinux.checkSELinuxAccess("u:r:system_server:s0", tcon, "file", "read")) { 2031 throw new FileNotFoundException("System server has no access to file context " + tcon); 2032 } 2033 return fd; 2034 } 2035 2036 private Rect getBounds() { 2037 String leftStr = nextArgRequired(); 2038 int left = Integer.valueOf(leftStr); 2039 String topStr = nextArgRequired(); 2040 int top = Integer.valueOf(topStr); 2041 String rightStr = nextArgRequired(); 2042 int right = Integer.valueOf(rightStr); 2043 String bottomStr = nextArgRequired(); 2044 int bottom = Integer.valueOf(bottomStr); 2045 if (left < 0) { 2046 System.err.println("Error: bad left arg: " + leftStr); 2047 return null; 2048 } 2049 if (top < 0) { 2050 System.err.println("Error: bad top arg: " + topStr); 2051 return null; 2052 } 2053 if (right <= 0) { 2054 System.err.println("Error: bad right arg: " + rightStr); 2055 return null; 2056 } 2057 if (bottom <= 0) { 2058 System.err.println("Error: bad bottom arg: " + bottomStr); 2059 return null; 2060 } 2061 return new Rect(left, top, right, bottom); 2062 } 2063} 2064