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