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