Am.java revision a4d4e82927ceadc23863e74b7e1160e4497504a7
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 static android.app.ActivityManager.DOCKED_STACK_ID; 22import static android.app.ActivityManager.RESIZE_MODE_SYSTEM; 23import static android.app.ActivityManager.RESIZE_MODE_USER; 24 25import android.app.ActivityManager; 26import android.app.ActivityManager.StackInfo; 27import android.app.ActivityManagerNative; 28import android.app.IActivityContainer; 29import android.app.IActivityController; 30import android.app.IActivityManager; 31import android.app.IInstrumentationWatcher; 32import android.app.Instrumentation; 33import android.app.IStopUserCallback; 34import android.app.ProfilerInfo; 35import android.app.UiAutomationConnection; 36import android.app.usage.ConfigurationStats; 37import android.app.usage.IUsageStatsManager; 38import android.app.usage.UsageStatsManager; 39import android.content.ComponentCallbacks2; 40import android.content.ComponentName; 41import android.content.Context; 42import android.content.IIntentReceiver; 43import android.content.Intent; 44import android.content.pm.IPackageManager; 45import android.content.pm.ParceledListSlice; 46import android.content.pm.ResolveInfo; 47import android.content.pm.UserInfo; 48import android.content.res.Configuration; 49import android.graphics.Rect; 50import android.net.Uri; 51import android.os.Binder; 52import android.os.Build; 53import android.os.Bundle; 54import android.os.ParcelFileDescriptor; 55import android.os.RemoteException; 56import android.os.SELinux; 57import android.os.ServiceManager; 58import android.os.SystemClock; 59import android.os.SystemProperties; 60import android.os.UserHandle; 61import android.text.TextUtils; 62import android.util.AndroidException; 63import android.util.ArrayMap; 64import android.view.IWindowManager; 65 66import com.android.internal.os.BaseCommand; 67import com.android.internal.util.Preconditions; 68 69import java.io.BufferedReader; 70import java.io.File; 71import java.io.FileNotFoundException; 72import java.io.IOException; 73import java.io.InputStreamReader; 74import java.io.PrintStream; 75import java.net.URISyntaxException; 76import java.util.ArrayList; 77import java.util.Collections; 78import java.util.Comparator; 79import java.util.HashSet; 80import java.util.List; 81 82public class Am extends BaseCommand { 83 84 private static final String SHELL_PACKAGE_NAME = "com.android.shell"; 85 86 // Is the object moving in a positive direction? 87 private static final boolean MOVING_FORWARD = true; 88 // Is the object moving in the horizontal plan? 89 private static final boolean MOVING_HORIZONTALLY = true; 90 // Is the object current point great then its target point? 91 private static final boolean GREATER_THAN_TARGET = true; 92 // Amount we reduce the stack size by when testing a task re-size. 93 private static final int STACK_BOUNDS_INSET = 10; 94 95 private IActivityManager mAm; 96 97 private int mStartFlags = 0; 98 private boolean mWaitOption = false; 99 private boolean mStopOption = false; 100 101 private int mRepeat = 0; 102 private int mUserId; 103 private String mReceiverPermission; 104 105 private String mProfileFile; 106 private int mSamplingInterval; 107 private boolean mAutoStop; 108 109 /** 110 * Command-line entry point. 111 * 112 * @param args The command-line arguments 113 */ 114 public static void main(String[] args) { 115 (new Am()).run(args); 116 } 117 118 @Override 119 public void onShowUsage(PrintStream out) { 120 out.println( 121 "usage: am [subcommand] [options]\n" + 122 "usage: am start [-D] [-W] [-P <FILE>] [--start-profiler <FILE>]\n" + 123 " [--sampling INTERVAL] [-R COUNT] [-S]\n" + 124 " [--track-allocation] [--user <USER_ID> | current] <INTENT>\n" + 125 " am startservice [--user <USER_ID> | current] <INTENT>\n" + 126 " am stopservice [--user <USER_ID> | current] <INTENT>\n" + 127 " am force-stop [--user <USER_ID> | all | current] <PACKAGE>\n" + 128 " am kill [--user <USER_ID> | all | current] <PACKAGE>\n" + 129 " am kill-all\n" + 130 " am broadcast [--user <USER_ID> | all | current] <INTENT>\n" + 131 " am instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]\n" + 132 " [--user <USER_ID> | current]\n" + 133 " [--no-window-animation] [--abi <ABI>] <COMPONENT>\n" + 134 " am profile start [--user <USER_ID> current] [--sampling INTERVAL] <PROCESS> <FILE>\n" + 135 " am profile stop [--user <USER_ID> current] [<PROCESS>]\n" + 136 " am dumpheap [--user <USER_ID> current] [-n] <PROCESS> <FILE>\n" + 137 " am set-debug-app [-w] [--persistent] <PACKAGE>\n" + 138 " am clear-debug-app\n" + 139 " am set-watch-heap <PROCESS> <MEM-LIMIT>\n" + 140 " am clear-watch-heap\n" + 141 " am monitor [--gdb <port>]\n" + 142 " am hang [--allow-restart]\n" + 143 " am restart\n" + 144 " am idle-maintenance\n" + 145 " am screen-compat [on|off] <PACKAGE>\n" + 146 " am package-importance <PACKAGE>\n" + 147 " am to-uri [INTENT]\n" + 148 " am to-intent-uri [INTENT]\n" + 149 " am to-app-uri [INTENT]\n" + 150 " am switch-user <USER_ID>\n" + 151 " am start-user <USER_ID>\n" + 152 " am stop-user [-w] <USER_ID>\n" + 153 " am stack start <DISPLAY_ID> <INTENT>\n" + 154 " am stack movetask <TASK_ID> <STACK_ID> [true|false]\n" + 155 " am stack resize <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" + 156 " am stack size-docked-stack-test: <STEP_SIZE> <l|t|r|b> [DELAY_MS]\n" + 157 " am stack split <STACK_ID> <v|h> [INTENT]\n" + 158 " am stack positiontask <TASK_ID> <STACK_ID> <POSITION>\n" + 159 " am stack list\n" + 160 " am stack info <STACK_ID>\n" + 161 " am task lock <TASK_ID>\n" + 162 " am task lock stop\n" + 163 " am task resizeable <TASK_ID> [true|false]\n" + 164 " am task resize <TASK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" + 165 " am task drag-task-test <TASK_ID> <STEP_SIZE> [DELAY_MS] \n" + 166 " am task size-task-test <TASK_ID> <STEP_SIZE> [DELAY_MS] \n" + 167 " am get-config\n" + 168 " am suppress-resize-config-changes <true|false>\n" + 169 " am set-inactive [--user <USER_ID>] <PACKAGE> true|false\n" + 170 " am get-inactive [--user <USER_ID>] <PACKAGE>\n" + 171 " am send-trim-memory [--user <USER_ID>] <PROCESS>\n" + 172 " [HIDDEN|RUNNING_MODERATE|BACKGROUND|RUNNING_LOW|MODERATE|RUNNING_CRITICAL|COMPLETE]\n" + 173 " am get-current-user\n" + 174 "\n" + 175 "am start: start an Activity. Options are:\n" + 176 " -D: enable debugging\n" + 177 " -W: wait for launch to complete\n" + 178 " --start-profiler <FILE>: start profiler and send results to <FILE>\n" + 179 " --sampling INTERVAL: use sample profiling with INTERVAL microseconds\n" + 180 " between samples (use with --start-profiler)\n" + 181 " -P <FILE>: like above, but profiling stops when app goes idle\n" + 182 " -R: repeat the activity launch <COUNT> times. Prior to each repeat,\n" + 183 " the top activity will be finished.\n" + 184 " -S: force stop the target app before starting the activity\n" + 185 " --track-allocation: enable tracking of object allocations\n" + 186 " --user <USER_ID> | current: Specify which user to run as; if not\n" + 187 " specified then run as the current user.\n" + 188 "\n" + 189 "am startservice: start a Service. Options are:\n" + 190 " --user <USER_ID> | current: Specify which user to run as; if not\n" + 191 " specified then run as the current user.\n" + 192 "\n" + 193 "am stopservice: stop a Service. Options are:\n" + 194 " --user <USER_ID> | current: Specify which user to run as; if not\n" + 195 " specified then run as the current user.\n" + 196 "\n" + 197 "am force-stop: force stop everything associated with <PACKAGE>.\n" + 198 " --user <USER_ID> | all | current: Specify user to force stop;\n" + 199 " all users if not specified.\n" + 200 "\n" + 201 "am kill: Kill all processes associated with <PACKAGE>. Only kills.\n" + 202 " processes that are safe to kill -- that is, will not impact the user\n" + 203 " experience.\n" + 204 " --user <USER_ID> | all | current: Specify user whose processes to kill;\n" + 205 " all users if not specified.\n" + 206 "\n" + 207 "am kill-all: Kill all background processes.\n" + 208 "\n" + 209 "am broadcast: send a broadcast Intent. Options are:\n" + 210 " --user <USER_ID> | all | current: Specify which user to send to; if not\n" + 211 " specified then send to all users.\n" + 212 " --receiver-permission <PERMISSION>: Require receiver to hold permission.\n" + 213 "\n" + 214 "am instrument: start an Instrumentation. Typically this target <COMPONENT>\n" + 215 " is the form <TEST_PACKAGE>/<RUNNER_CLASS>. Options are:\n" + 216 " -r: print raw results (otherwise decode REPORT_KEY_STREAMRESULT). Use with\n" + 217 " [-e perf true] to generate raw output for performance measurements.\n" + 218 " -e <NAME> <VALUE>: set argument <NAME> to <VALUE>. For test runners a\n" + 219 " common form is [-e <testrunner_flag> <value>[,<value>...]].\n" + 220 " -p <FILE>: write profiling data to <FILE>\n" + 221 " -w: wait for instrumentation to finish before returning. Required for\n" + 222 " test runners.\n" + 223 " --user <USER_ID> | current: Specify user instrumentation runs in;\n" + 224 " current user if not specified.\n" + 225 " --no-window-animation: turn off window animations while running.\n" + 226 " --abi <ABI>: Launch the instrumented process with the selected ABI.\n" + 227 " This assumes that the process supports the selected ABI.\n" + 228 "\n" + 229 "am trace-ipc: Trace IPC transactions.\n" + 230 " start: start tracing IPC transactions.\n" + 231 " stop: stop tracing IPC transactions and dump the results to file.\n" + 232 " --dump-file <FILE>: Specify the file the trace should be dumped to.\n" + 233 "\n" + 234 "am profile: start and stop profiler on a process. The given <PROCESS> argument\n" + 235 " may be either a process name or pid. Options are:\n" + 236 " --user <USER_ID> | current: When supplying a process name,\n" + 237 " specify user of process to profile; uses current user if not specified.\n" + 238 "\n" + 239 "am dumpheap: dump the heap of a process. The given <PROCESS> argument may\n" + 240 " be either a process name or pid. Options are:\n" + 241 " -n: dump native heap instead of managed heap\n" + 242 " --user <USER_ID> | current: When supplying a process name,\n" + 243 " specify user of process to dump; uses current user if not specified.\n" + 244 "\n" + 245 "am set-debug-app: set application <PACKAGE> to debug. Options are:\n" + 246 " -w: wait for debugger when application starts\n" + 247 " --persistent: retain this value\n" + 248 "\n" + 249 "am clear-debug-app: clear the previously set-debug-app.\n" + 250 "\n" + 251 "am set-watch-heap: start monitoring pss size of <PROCESS>, if it is at or\n" + 252 " above <HEAP-LIMIT> then a heap dump is collected for the user to report\n" + 253 "\n" + 254 "am clear-watch-heap: clear the previously set-watch-heap.\n" + 255 "\n" + 256 "am bug-report: request bug report generation; will launch UI\n" + 257 " when done to select where it should be delivered.\n" + 258 "\n" + 259 "am monitor: start monitoring for crashes or ANRs.\n" + 260 " --gdb: start gdbserv on the given port at crash/ANR\n" + 261 "\n" + 262 "am hang: hang the system.\n" + 263 " --allow-restart: allow watchdog to perform normal system restart\n" + 264 "\n" + 265 "am restart: restart the user-space system.\n" + 266 "\n" + 267 "am idle-maintenance: perform idle maintenance now.\n" + 268 "\n" + 269 "am screen-compat: control screen compatibility mode of <PACKAGE>.\n" + 270 "\n" + 271 "am package-importance: print current importance of <PACKAGE>.\n" + 272 "\n" + 273 "am to-uri: print the given Intent specification as a URI.\n" + 274 "\n" + 275 "am to-intent-uri: print the given Intent specification as an intent: URI.\n" + 276 "\n" + 277 "am to-app-uri: print the given Intent specification as an android-app: URI.\n" + 278 "\n" + 279 "am switch-user: switch to put USER_ID in the foreground, starting\n" + 280 " execution of that user if it is currently stopped.\n" + 281 "\n" + 282 "am start-user: start USER_ID in background if it is currently stopped,\n" + 283 " use switch-user if you want to start the user in foreground.\n" + 284 "\n" + 285 "am stop-user: stop execution of USER_ID, not allowing it to run any\n" + 286 " code until a later explicit start or switch to it.\n" + 287 " -w: wait for stop-user to complete.\n" + 288 "\n" + 289 "am stack start: start a new activity on <DISPLAY_ID> using <INTENT>.\n" + 290 "\n" + 291 "am stack movetask: move <TASK_ID> from its current stack to the top (true) or" + 292 " bottom (false) of <STACK_ID>.\n" + 293 "\n" + 294 "am stack resize: change <STACK_ID> size and position to <LEFT,TOP,RIGHT,BOTTOM>." + 295 "\n" + 296 "am stack size-docked-stack-test: test command for sizing docked stack by\n" + 297 " <STEP_SIZE> increments from the side <l>eft, <t>op, <r>ight, or <b>ottom\n" + 298 " applying the optional [DELAY_MS] between each step.\n" + 299 "\n" + 300 "am stack split: split <STACK_ID> into 2 stacks <v>ertically or <h>orizontally\n" + 301 " starting the new stack with [INTENT] if specified. If [INTENT] isn't\n" + 302 " specified and the current stack has more than one task, then the top task\n" + 303 " of the current task will be moved to the new stack. Command will also force\n" + 304 " all current tasks in both stacks to be resizeable.\n" + 305 "\n" + 306 "am stack positiontask: place <TASK_ID> in <STACK_ID> at <POSITION>" + 307 "\n" + 308 "am stack list: list all of the activity stacks and their sizes.\n" + 309 "\n" + 310 "am stack info: display the information about activity stack <STACK_ID>.\n" + 311 "\n" + 312 "am task lock: bring <TASK_ID> to the front and don't allow other tasks to run.\n" + 313 "\n" + 314 "am task lock stop: end the current task lock.\n" + 315 "\n" + 316 "am task resizeable: change if <TASK_ID> is resizeable (true) or not (false).\n" + 317 "\n" + 318 "am task resize: makes sure <TASK_ID> is in a stack with the specified bounds.\n" + 319 " Forces the task to be resizeable and creates a stack if no existing stack\n" + 320 " has the specified bounds.\n" + 321 "\n" + 322 "am task drag-task-test: test command for dragging/moving <TASK_ID> by\n" + 323 " <STEP_SIZE> increments around the screen applying the optional [DELAY_MS]\n" + 324 " between each step.\n" + 325 "\n" + 326 "am task size-task-test: test command for sizing <TASK_ID> by <STEP_SIZE>" + 327 " increments within the screen applying the optional [DELAY_MS] between\n" + 328 " each step.\n" + 329 "\n" + 330 "am get-config: retrieve the configuration and any recent configurations\n" + 331 " of the device.\n" + 332 "am suppress-resize-config-changes: suppresses configuration changes due to\n" + 333 " user resizing an activity/task.\n" + 334 "\n" + 335 "am set-inactive: sets the inactive state of an app.\n" + 336 "\n" + 337 "am get-inactive: returns the inactive state of an app.\n" + 338 "\n" + 339 "am send-trim-memory: send a memory trim event to a <PROCESS>.\n" + 340 "\n" + 341 "am get-current-user: returns id of the current foreground user.\n" + 342 "\n" + 343 "<INTENT> specifications include these flags and arguments:\n" + 344 " [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" + 345 " [-c <CATEGORY> [-c <CATEGORY>] ...]\n" + 346 " [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]\n" + 347 " [--esn <EXTRA_KEY> ...]\n" + 348 " [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]\n" + 349 " [--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]\n" + 350 " [--el <EXTRA_KEY> <EXTRA_LONG_VALUE> ...]\n" + 351 " [--ef <EXTRA_KEY> <EXTRA_FLOAT_VALUE> ...]\n" + 352 " [--eu <EXTRA_KEY> <EXTRA_URI_VALUE> ...]\n" + 353 " [--ecn <EXTRA_KEY> <EXTRA_COMPONENT_NAME_VALUE>]\n" + 354 " [--eia <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]]\n" + 355 " (mutiple extras passed as Integer[])\n" + 356 " [--eial <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]]\n" + 357 " (mutiple extras passed as List<Integer>)\n" + 358 " [--ela <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]\n" + 359 " (mutiple extras passed as Long[])\n" + 360 " [--elal <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]\n" + 361 " (mutiple extras passed as List<Long>)\n" + 362 " [--efa <EXTRA_KEY> <EXTRA_FLOAT_VALUE>[,<EXTRA_FLOAT_VALUE...]]\n" + 363 " (mutiple extras passed as Float[])\n" + 364 " [--efal <EXTRA_KEY> <EXTRA_FLOAT_VALUE>[,<EXTRA_FLOAT_VALUE...]]\n" + 365 " (mutiple extras passed as List<Float>)\n" + 366 " [--esa <EXTRA_KEY> <EXTRA_STRING_VALUE>[,<EXTRA_STRING_VALUE...]]\n" + 367 " (mutiple extras passed as String[]; to embed a comma into a string,\n" + 368 " escape it using \"\\,\")\n" + 369 " [--esal <EXTRA_KEY> <EXTRA_STRING_VALUE>[,<EXTRA_STRING_VALUE...]]\n" + 370 " (mutiple extras passed as List<String>; to embed a comma into a string,\n" + 371 " escape it using \"\\,\")\n" + 372 " [--grant-read-uri-permission] [--grant-write-uri-permission]\n" + 373 " [--grant-persistable-uri-permission] [--grant-prefix-uri-permission]\n" + 374 " [--debug-log-resolution] [--exclude-stopped-packages]\n" + 375 " [--include-stopped-packages]\n" + 376 " [--activity-brought-to-front] [--activity-clear-top]\n" + 377 " [--activity-clear-when-task-reset] [--activity-exclude-from-recents]\n" + 378 " [--activity-launched-from-history] [--activity-multiple-task]\n" + 379 " [--activity-no-animation] [--activity-no-history]\n" + 380 " [--activity-no-user-action] [--activity-previous-is-top]\n" + 381 " [--activity-reorder-to-front] [--activity-reset-task-if-needed]\n" + 382 " [--activity-single-top] [--activity-clear-task]\n" + 383 " [--activity-task-on-home]\n" + 384 " [--receiver-registered-only] [--receiver-replace-pending]\n" + 385 " [--selector]\n" + 386 " [<URI> | <PACKAGE> | <COMPONENT>]\n" 387 ); 388 } 389 390 @Override 391 public void onRun() throws Exception { 392 393 mAm = ActivityManagerNative.getDefault(); 394 if (mAm == null) { 395 System.err.println(NO_SYSTEM_ERROR_CODE); 396 throw new AndroidException("Can't connect to activity manager; is the system running?"); 397 } 398 399 String op = nextArgRequired(); 400 401 if (op.equals("start")) { 402 runStart(); 403 } else if (op.equals("startservice")) { 404 runStartService(); 405 } else if (op.equals("stopservice")) { 406 runStopService(); 407 } else if (op.equals("force-stop")) { 408 runForceStop(); 409 } else if (op.equals("kill")) { 410 runKill(); 411 } else if (op.equals("kill-all")) { 412 runKillAll(); 413 } else if (op.equals("instrument")) { 414 runInstrument(); 415 } else if (op.equals("trace-ipc")) { 416 runTraceIpc(); 417 } else if (op.equals("broadcast")) { 418 sendBroadcast(); 419 } else if (op.equals("profile")) { 420 runProfile(); 421 } else if (op.equals("dumpheap")) { 422 runDumpHeap(); 423 } else if (op.equals("set-debug-app")) { 424 runSetDebugApp(); 425 } else if (op.equals("clear-debug-app")) { 426 runClearDebugApp(); 427 } else if (op.equals("set-watch-heap")) { 428 runSetWatchHeap(); 429 } else if (op.equals("clear-watch-heap")) { 430 runClearWatchHeap(); 431 } else if (op.equals("bug-report")) { 432 runBugReport(); 433 } else if (op.equals("monitor")) { 434 runMonitor(); 435 } else if (op.equals("hang")) { 436 runHang(); 437 } else if (op.equals("restart")) { 438 runRestart(); 439 } else if (op.equals("idle-maintenance")) { 440 runIdleMaintenance(); 441 } else if (op.equals("screen-compat")) { 442 runScreenCompat(); 443 } else if (op.equals("package-importance")) { 444 runPackageImportance(); 445 } else if (op.equals("to-uri")) { 446 runToUri(0); 447 } else if (op.equals("to-intent-uri")) { 448 runToUri(Intent.URI_INTENT_SCHEME); 449 } else if (op.equals("to-app-uri")) { 450 runToUri(Intent.URI_ANDROID_APP_SCHEME); 451 } else if (op.equals("switch-user")) { 452 runSwitchUser(); 453 } else if (op.equals("start-user")) { 454 runStartUserInBackground(); 455 } else if (op.equals("stop-user")) { 456 runStopUser(); 457 } else if (op.equals("stack")) { 458 runStack(); 459 } else if (op.equals("task")) { 460 runTask(); 461 } else if (op.equals("get-config")) { 462 runGetConfig(); 463 } else if (op.equals("suppress-resize-config-changes")) { 464 runSuppressResizeConfigChanges(); 465 } else if (op.equals("set-inactive")) { 466 runSetInactive(); 467 } else if (op.equals("get-inactive")) { 468 runGetInactive(); 469 } else if (op.equals("send-trim-memory")) { 470 runSendTrimMemory(); 471 } else if (op.equals("get-current-user")) { 472 runGetCurrentUser(); 473 } else { 474 showError("Error: unknown command '" + op + "'"); 475 } 476 } 477 478 int parseUserArg(String arg) { 479 int userId; 480 if ("all".equals(arg)) { 481 userId = UserHandle.USER_ALL; 482 } else if ("current".equals(arg) || "cur".equals(arg)) { 483 userId = UserHandle.USER_CURRENT; 484 } else { 485 userId = Integer.parseInt(arg); 486 } 487 return userId; 488 } 489 490 private Intent makeIntent(int defUser) throws URISyntaxException { 491 Intent intent = new Intent(); 492 Intent baseIntent = intent; 493 boolean hasIntentInfo = false; 494 495 mStartFlags = 0; 496 mWaitOption = false; 497 mStopOption = false; 498 mRepeat = 0; 499 mProfileFile = null; 500 mSamplingInterval = 0; 501 mAutoStop = false; 502 mUserId = defUser; 503 Uri data = null; 504 String type = null; 505 506 String opt; 507 while ((opt=nextOption()) != null) { 508 if (opt.equals("-a")) { 509 intent.setAction(nextArgRequired()); 510 if (intent == baseIntent) { 511 hasIntentInfo = true; 512 } 513 } else if (opt.equals("-d")) { 514 data = Uri.parse(nextArgRequired()); 515 if (intent == baseIntent) { 516 hasIntentInfo = true; 517 } 518 } else if (opt.equals("-t")) { 519 type = nextArgRequired(); 520 if (intent == baseIntent) { 521 hasIntentInfo = true; 522 } 523 } else if (opt.equals("-c")) { 524 intent.addCategory(nextArgRequired()); 525 if (intent == baseIntent) { 526 hasIntentInfo = true; 527 } 528 } else if (opt.equals("-e") || opt.equals("--es")) { 529 String key = nextArgRequired(); 530 String value = nextArgRequired(); 531 intent.putExtra(key, value); 532 } else if (opt.equals("--esn")) { 533 String key = nextArgRequired(); 534 intent.putExtra(key, (String) null); 535 } else if (opt.equals("--ei")) { 536 String key = nextArgRequired(); 537 String value = nextArgRequired(); 538 intent.putExtra(key, Integer.decode(value)); 539 } else if (opt.equals("--eu")) { 540 String key = nextArgRequired(); 541 String value = nextArgRequired(); 542 intent.putExtra(key, Uri.parse(value)); 543 } else if (opt.equals("--ecn")) { 544 String key = nextArgRequired(); 545 String value = nextArgRequired(); 546 ComponentName cn = ComponentName.unflattenFromString(value); 547 if (cn == null) throw new IllegalArgumentException("Bad component name: " + value); 548 intent.putExtra(key, cn); 549 } else if (opt.equals("--eia")) { 550 String key = nextArgRequired(); 551 String value = nextArgRequired(); 552 String[] strings = value.split(","); 553 int[] list = new int[strings.length]; 554 for (int i = 0; i < strings.length; i++) { 555 list[i] = Integer.decode(strings[i]); 556 } 557 intent.putExtra(key, list); 558 } else if (opt.equals("--eial")) { 559 String key = nextArgRequired(); 560 String value = nextArgRequired(); 561 String[] strings = value.split(","); 562 ArrayList<Integer> list = new ArrayList<>(strings.length); 563 for (int i = 0; i < strings.length; i++) { 564 list.add(Integer.decode(strings[i])); 565 } 566 intent.putExtra(key, list); 567 } else if (opt.equals("--el")) { 568 String key = nextArgRequired(); 569 String value = nextArgRequired(); 570 intent.putExtra(key, Long.valueOf(value)); 571 } else if (opt.equals("--ela")) { 572 String key = nextArgRequired(); 573 String value = nextArgRequired(); 574 String[] strings = value.split(","); 575 long[] list = new long[strings.length]; 576 for (int i = 0; i < strings.length; i++) { 577 list[i] = Long.valueOf(strings[i]); 578 } 579 intent.putExtra(key, list); 580 hasIntentInfo = true; 581 } else if (opt.equals("--elal")) { 582 String key = nextArgRequired(); 583 String value = nextArgRequired(); 584 String[] strings = value.split(","); 585 ArrayList<Long> list = new ArrayList<>(strings.length); 586 for (int i = 0; i < strings.length; i++) { 587 list.add(Long.valueOf(strings[i])); 588 } 589 intent.putExtra(key, list); 590 hasIntentInfo = true; 591 } else if (opt.equals("--ef")) { 592 String key = nextArgRequired(); 593 String value = nextArgRequired(); 594 intent.putExtra(key, Float.valueOf(value)); 595 hasIntentInfo = true; 596 } else if (opt.equals("--efa")) { 597 String key = nextArgRequired(); 598 String value = nextArgRequired(); 599 String[] strings = value.split(","); 600 float[] list = new float[strings.length]; 601 for (int i = 0; i < strings.length; i++) { 602 list[i] = Float.valueOf(strings[i]); 603 } 604 intent.putExtra(key, list); 605 hasIntentInfo = true; 606 } else if (opt.equals("--efal")) { 607 String key = nextArgRequired(); 608 String value = nextArgRequired(); 609 String[] strings = value.split(","); 610 ArrayList<Float> list = new ArrayList<>(strings.length); 611 for (int i = 0; i < strings.length; i++) { 612 list.add(Float.valueOf(strings[i])); 613 } 614 intent.putExtra(key, list); 615 hasIntentInfo = true; 616 } else if (opt.equals("--esa")) { 617 String key = nextArgRequired(); 618 String value = nextArgRequired(); 619 // Split on commas unless they are preceeded by an escape. 620 // The escape character must be escaped for the string and 621 // again for the regex, thus four escape characters become one. 622 String[] strings = value.split("(?<!\\\\),"); 623 intent.putExtra(key, strings); 624 hasIntentInfo = true; 625 } else if (opt.equals("--esal")) { 626 String key = nextArgRequired(); 627 String value = nextArgRequired(); 628 // Split on commas unless they are preceeded by an escape. 629 // The escape character must be escaped for the string and 630 // again for the regex, thus four escape characters become one. 631 String[] strings = value.split("(?<!\\\\),"); 632 ArrayList<String> list = new ArrayList<>(strings.length); 633 for (int i = 0; i < strings.length; i++) { 634 list.add(strings[i]); 635 } 636 intent.putExtra(key, list); 637 hasIntentInfo = true; 638 } else if (opt.equals("--ez")) { 639 String key = nextArgRequired(); 640 String value = nextArgRequired().toLowerCase(); 641 // Boolean.valueOf() results in false for anything that is not "true", which is 642 // error-prone in shell commands 643 boolean arg; 644 if ("true".equals(value) || "t".equals(value)) { 645 arg = true; 646 } else if ("false".equals(value) || "f".equals(value)) { 647 arg = false; 648 } else { 649 try { 650 arg = Integer.decode(value) != 0; 651 } catch (NumberFormatException ex) { 652 throw new IllegalArgumentException("Invalid boolean value: " + value); 653 } 654 } 655 656 intent.putExtra(key, arg); 657 } else if (opt.equals("-n")) { 658 String str = nextArgRequired(); 659 ComponentName cn = ComponentName.unflattenFromString(str); 660 if (cn == null) throw new IllegalArgumentException("Bad component name: " + str); 661 intent.setComponent(cn); 662 if (intent == baseIntent) { 663 hasIntentInfo = true; 664 } 665 } else if (opt.equals("-p")) { 666 String str = nextArgRequired(); 667 intent.setPackage(str); 668 if (intent == baseIntent) { 669 hasIntentInfo = true; 670 } 671 } else if (opt.equals("-f")) { 672 String str = nextArgRequired(); 673 intent.setFlags(Integer.decode(str).intValue()); 674 } else if (opt.equals("--grant-read-uri-permission")) { 675 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 676 } else if (opt.equals("--grant-write-uri-permission")) { 677 intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); 678 } else if (opt.equals("--grant-persistable-uri-permission")) { 679 intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION); 680 } else if (opt.equals("--grant-prefix-uri-permission")) { 681 intent.addFlags(Intent.FLAG_GRANT_PREFIX_URI_PERMISSION); 682 } else if (opt.equals("--exclude-stopped-packages")) { 683 intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES); 684 } else if (opt.equals("--include-stopped-packages")) { 685 intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); 686 } else if (opt.equals("--debug-log-resolution")) { 687 intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION); 688 } else if (opt.equals("--activity-brought-to-front")) { 689 intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT); 690 } else if (opt.equals("--activity-clear-top")) { 691 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 692 } else if (opt.equals("--activity-clear-when-task-reset")) { 693 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); 694 } else if (opt.equals("--activity-exclude-from-recents")) { 695 intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); 696 } else if (opt.equals("--activity-launched-from-history")) { 697 intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY); 698 } else if (opt.equals("--activity-multiple-task")) { 699 intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); 700 } else if (opt.equals("--activity-no-animation")) { 701 intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); 702 } else if (opt.equals("--activity-no-history")) { 703 intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); 704 } else if (opt.equals("--activity-no-user-action")) { 705 intent.addFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION); 706 } else if (opt.equals("--activity-previous-is-top")) { 707 intent.addFlags(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP); 708 } else if (opt.equals("--activity-reorder-to-front")) { 709 intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); 710 } else if (opt.equals("--activity-reset-task-if-needed")) { 711 intent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); 712 } else if (opt.equals("--activity-single-top")) { 713 intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); 714 } else if (opt.equals("--activity-clear-task")) { 715 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); 716 } else if (opt.equals("--activity-task-on-home")) { 717 intent.addFlags(Intent.FLAG_ACTIVITY_TASK_ON_HOME); 718 } else if (opt.equals("--receiver-registered-only")) { 719 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); 720 } else if (opt.equals("--receiver-replace-pending")) { 721 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); 722 } else if (opt.equals("--selector")) { 723 intent.setDataAndType(data, type); 724 intent = new Intent(); 725 } else if (opt.equals("-D")) { 726 mStartFlags |= ActivityManager.START_FLAG_DEBUG; 727 } else if (opt.equals("-W")) { 728 mWaitOption = true; 729 } else if (opt.equals("-P")) { 730 mProfileFile = nextArgRequired(); 731 mAutoStop = true; 732 } else if (opt.equals("--start-profiler")) { 733 mProfileFile = nextArgRequired(); 734 mAutoStop = false; 735 } else if (opt.equals("--sampling")) { 736 mSamplingInterval = Integer.parseInt(nextArgRequired()); 737 } else if (opt.equals("-R")) { 738 mRepeat = Integer.parseInt(nextArgRequired()); 739 } else if (opt.equals("-S")) { 740 mStopOption = true; 741 } else if (opt.equals("--track-allocation")) { 742 mStartFlags |= ActivityManager.START_FLAG_TRACK_ALLOCATION; 743 } else if (opt.equals("--user")) { 744 mUserId = parseUserArg(nextArgRequired()); 745 } else if (opt.equals("--receiver-permission")) { 746 mReceiverPermission = nextArgRequired(); 747 } else { 748 throw new IllegalArgumentException("Unknown option: " + opt); 749 } 750 } 751 intent.setDataAndType(data, type); 752 753 final boolean hasSelector = intent != baseIntent; 754 if (hasSelector) { 755 // A selector was specified; fix up. 756 baseIntent.setSelector(intent); 757 intent = baseIntent; 758 } 759 760 String arg = nextArg(); 761 baseIntent = null; 762 if (arg == null) { 763 if (hasSelector) { 764 // If a selector has been specified, and no arguments 765 // have been supplied for the main Intent, then we can 766 // assume it is ACTION_MAIN CATEGORY_LAUNCHER; we don't 767 // need to have a component name specified yet, the 768 // selector will take care of that. 769 baseIntent = new Intent(Intent.ACTION_MAIN); 770 baseIntent.addCategory(Intent.CATEGORY_LAUNCHER); 771 } 772 } else if (arg.indexOf(':') >= 0) { 773 // The argument is a URI. Fully parse it, and use that result 774 // to fill in any data not specified so far. 775 baseIntent = Intent.parseUri(arg, Intent.URI_INTENT_SCHEME 776 | Intent.URI_ANDROID_APP_SCHEME | Intent.URI_ALLOW_UNSAFE); 777 } else if (arg.indexOf('/') >= 0) { 778 // The argument is a component name. Build an Intent to launch 779 // it. 780 baseIntent = new Intent(Intent.ACTION_MAIN); 781 baseIntent.addCategory(Intent.CATEGORY_LAUNCHER); 782 baseIntent.setComponent(ComponentName.unflattenFromString(arg)); 783 } else { 784 // Assume the argument is a package name. 785 baseIntent = new Intent(Intent.ACTION_MAIN); 786 baseIntent.addCategory(Intent.CATEGORY_LAUNCHER); 787 baseIntent.setPackage(arg); 788 } 789 if (baseIntent != null) { 790 Bundle extras = intent.getExtras(); 791 intent.replaceExtras((Bundle)null); 792 Bundle uriExtras = baseIntent.getExtras(); 793 baseIntent.replaceExtras((Bundle)null); 794 if (intent.getAction() != null && baseIntent.getCategories() != null) { 795 HashSet<String> cats = new HashSet<String>(baseIntent.getCategories()); 796 for (String c : cats) { 797 baseIntent.removeCategory(c); 798 } 799 } 800 intent.fillIn(baseIntent, Intent.FILL_IN_COMPONENT | Intent.FILL_IN_SELECTOR); 801 if (extras == null) { 802 extras = uriExtras; 803 } else if (uriExtras != null) { 804 uriExtras.putAll(extras); 805 extras = uriExtras; 806 } 807 intent.replaceExtras(extras); 808 hasIntentInfo = true; 809 } 810 811 if (!hasIntentInfo) throw new IllegalArgumentException("No intent supplied"); 812 return intent; 813 } 814 815 private void runStartService() throws Exception { 816 Intent intent = makeIntent(UserHandle.USER_CURRENT); 817 if (mUserId == UserHandle.USER_ALL) { 818 System.err.println("Error: Can't start activity with user 'all'"); 819 return; 820 } 821 System.out.println("Starting service: " + intent); 822 ComponentName cn = mAm.startService(null, intent, intent.getType(), 823 SHELL_PACKAGE_NAME, mUserId); 824 if (cn == null) { 825 System.err.println("Error: Not found; no service started."); 826 } else if (cn.getPackageName().equals("!")) { 827 System.err.println("Error: Requires permission " + cn.getClassName()); 828 } else if (cn.getPackageName().equals("!!")) { 829 System.err.println("Error: " + cn.getClassName()); 830 } 831 } 832 833 private void runStopService() throws Exception { 834 Intent intent = makeIntent(UserHandle.USER_CURRENT); 835 if (mUserId == UserHandle.USER_ALL) { 836 System.err.println("Error: Can't stop activity with user 'all'"); 837 return; 838 } 839 System.out.println("Stopping service: " + intent); 840 int result = mAm.stopService(null, intent, intent.getType(), mUserId); 841 if (result == 0) { 842 System.err.println("Service not stopped: was not running."); 843 } else if (result == 1) { 844 System.err.println("Service stopped"); 845 } else if (result == -1) { 846 System.err.println("Error stopping service"); 847 } 848 } 849 850 private void runStart() throws Exception { 851 Intent intent = makeIntent(UserHandle.USER_CURRENT); 852 853 if (mUserId == UserHandle.USER_ALL) { 854 System.err.println("Error: Can't start service with user 'all'"); 855 return; 856 } 857 858 String mimeType = intent.getType(); 859 if (mimeType == null && intent.getData() != null 860 && "content".equals(intent.getData().getScheme())) { 861 mimeType = mAm.getProviderMimeType(intent.getData(), mUserId); 862 } 863 864 do { 865 if (mStopOption) { 866 String packageName; 867 if (intent.getComponent() != null) { 868 packageName = intent.getComponent().getPackageName(); 869 } else { 870 IPackageManager pm = IPackageManager.Stub.asInterface( 871 ServiceManager.getService("package")); 872 if (pm == null) { 873 System.err.println("Error: Package manager not running; aborting"); 874 return; 875 } 876 List<ResolveInfo> activities = pm.queryIntentActivities(intent, mimeType, 0, 877 mUserId); 878 if (activities == null || activities.size() <= 0) { 879 System.err.println("Error: Intent does not match any activities: " 880 + intent); 881 return; 882 } else if (activities.size() > 1) { 883 System.err.println("Error: Intent matches multiple activities; can't stop: " 884 + intent); 885 return; 886 } 887 packageName = activities.get(0).activityInfo.packageName; 888 } 889 System.out.println("Stopping: " + packageName); 890 mAm.forceStopPackage(packageName, mUserId); 891 Thread.sleep(250); 892 } 893 894 System.out.println("Starting: " + intent); 895 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 896 897 ParcelFileDescriptor fd = null; 898 ProfilerInfo profilerInfo = null; 899 900 if (mProfileFile != null) { 901 try { 902 fd = openForSystemServer( 903 new File(mProfileFile), 904 ParcelFileDescriptor.MODE_CREATE | 905 ParcelFileDescriptor.MODE_TRUNCATE | 906 ParcelFileDescriptor.MODE_READ_WRITE); 907 } catch (FileNotFoundException e) { 908 System.err.println("Error: Unable to open file: " + mProfileFile); 909 System.err.println("Consider using a file under /data/local/tmp/"); 910 return; 911 } 912 profilerInfo = new ProfilerInfo(mProfileFile, fd, mSamplingInterval, mAutoStop); 913 } 914 915 IActivityManager.WaitResult result = null; 916 int res; 917 final long startTime = SystemClock.uptimeMillis(); 918 if (mWaitOption) { 919 result = mAm.startActivityAndWait(null, null, intent, mimeType, 920 null, null, 0, mStartFlags, profilerInfo, null, mUserId); 921 res = result.result; 922 } else { 923 res = mAm.startActivityAsUser(null, null, intent, mimeType, 924 null, null, 0, mStartFlags, profilerInfo, null, mUserId); 925 } 926 final long endTime = SystemClock.uptimeMillis(); 927 PrintStream out = mWaitOption ? System.out : System.err; 928 boolean launched = false; 929 switch (res) { 930 case ActivityManager.START_SUCCESS: 931 launched = true; 932 break; 933 case ActivityManager.START_SWITCHES_CANCELED: 934 launched = true; 935 out.println( 936 "Warning: Activity not started because the " 937 + " current activity is being kept for the user."); 938 break; 939 case ActivityManager.START_DELIVERED_TO_TOP: 940 launched = true; 941 out.println( 942 "Warning: Activity not started, intent has " 943 + "been delivered to currently running " 944 + "top-most instance."); 945 break; 946 case ActivityManager.START_RETURN_INTENT_TO_CALLER: 947 launched = true; 948 out.println( 949 "Warning: Activity not started because intent " 950 + "should be handled by the caller"); 951 break; 952 case ActivityManager.START_TASK_TO_FRONT: 953 launched = true; 954 out.println( 955 "Warning: Activity not started, its current " 956 + "task has been brought to the front"); 957 break; 958 case ActivityManager.START_INTENT_NOT_RESOLVED: 959 out.println( 960 "Error: Activity not started, unable to " 961 + "resolve " + intent.toString()); 962 break; 963 case ActivityManager.START_CLASS_NOT_FOUND: 964 out.println(NO_CLASS_ERROR_CODE); 965 out.println("Error: Activity class " + 966 intent.getComponent().toShortString() 967 + " does not exist."); 968 break; 969 case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT: 970 out.println( 971 "Error: Activity not started, you requested to " 972 + "both forward and receive its result"); 973 break; 974 case ActivityManager.START_PERMISSION_DENIED: 975 out.println( 976 "Error: Activity not started, you do not " 977 + "have permission to access it."); 978 break; 979 case ActivityManager.START_NOT_VOICE_COMPATIBLE: 980 out.println( 981 "Error: Activity not started, voice control not allowed for: " 982 + intent); 983 break; 984 case ActivityManager.START_NOT_CURRENT_USER_ACTIVITY: 985 out.println( 986 "Error: Not allowed to start background user activity" 987 + " that shouldn't be displayed for all users."); 988 break; 989 default: 990 out.println( 991 "Error: Activity not started, unknown error code " + res); 992 break; 993 } 994 if (mWaitOption && launched) { 995 if (result == null) { 996 result = new IActivityManager.WaitResult(); 997 result.who = intent.getComponent(); 998 } 999 System.out.println("Status: " + (result.timeout ? "timeout" : "ok")); 1000 if (result.who != null) { 1001 System.out.println("Activity: " + result.who.flattenToShortString()); 1002 } 1003 if (result.thisTime >= 0) { 1004 System.out.println("ThisTime: " + result.thisTime); 1005 } 1006 if (result.totalTime >= 0) { 1007 System.out.println("TotalTime: " + result.totalTime); 1008 } 1009 System.out.println("WaitTime: " + (endTime-startTime)); 1010 System.out.println("Complete"); 1011 } 1012 mRepeat--; 1013 if (mRepeat > 1) { 1014 mAm.unhandledBack(); 1015 } 1016 } while (mRepeat > 1); 1017 } 1018 1019 private void runForceStop() throws Exception { 1020 int userId = UserHandle.USER_ALL; 1021 1022 String opt; 1023 while ((opt=nextOption()) != null) { 1024 if (opt.equals("--user")) { 1025 userId = parseUserArg(nextArgRequired()); 1026 } else { 1027 System.err.println("Error: Unknown option: " + opt); 1028 return; 1029 } 1030 } 1031 mAm.forceStopPackage(nextArgRequired(), userId); 1032 } 1033 1034 private void runKill() throws Exception { 1035 int userId = UserHandle.USER_ALL; 1036 1037 String opt; 1038 while ((opt=nextOption()) != null) { 1039 if (opt.equals("--user")) { 1040 userId = parseUserArg(nextArgRequired()); 1041 } else { 1042 System.err.println("Error: Unknown option: " + opt); 1043 return; 1044 } 1045 } 1046 mAm.killBackgroundProcesses(nextArgRequired(), userId); 1047 } 1048 1049 private void runKillAll() throws Exception { 1050 mAm.killAllBackgroundProcesses(); 1051 } 1052 1053 private void sendBroadcast() throws Exception { 1054 Intent intent = makeIntent(UserHandle.USER_CURRENT); 1055 IntentReceiver receiver = new IntentReceiver(); 1056 String[] requiredPermissions = mReceiverPermission == null ? null 1057 : new String[] {mReceiverPermission}; 1058 System.out.println("Broadcasting: " + intent); 1059 mAm.broadcastIntent(null, intent, null, receiver, 0, null, null, requiredPermissions, 1060 android.app.AppOpsManager.OP_NONE, null, true, false, mUserId); 1061 receiver.waitForFinish(); 1062 } 1063 1064 private void runInstrument() throws Exception { 1065 String profileFile = null; 1066 boolean wait = false; 1067 boolean rawMode = false; 1068 boolean no_window_animation = false; 1069 int userId = UserHandle.USER_CURRENT; 1070 Bundle args = new Bundle(); 1071 String argKey = null, argValue = null; 1072 IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.getService("window")); 1073 String abi = null; 1074 1075 String opt; 1076 while ((opt=nextOption()) != null) { 1077 if (opt.equals("-p")) { 1078 profileFile = nextArgRequired(); 1079 } else if (opt.equals("-w")) { 1080 wait = true; 1081 } else if (opt.equals("-r")) { 1082 rawMode = true; 1083 } else if (opt.equals("-e")) { 1084 argKey = nextArgRequired(); 1085 argValue = nextArgRequired(); 1086 args.putString(argKey, argValue); 1087 } else if (opt.equals("--no_window_animation") 1088 || opt.equals("--no-window-animation")) { 1089 no_window_animation = true; 1090 } else if (opt.equals("--user")) { 1091 userId = parseUserArg(nextArgRequired()); 1092 } else if (opt.equals("--abi")) { 1093 abi = nextArgRequired(); 1094 } else { 1095 System.err.println("Error: Unknown option: " + opt); 1096 return; 1097 } 1098 } 1099 1100 if (userId == UserHandle.USER_ALL) { 1101 System.err.println("Error: Can't start instrumentation with user 'all'"); 1102 return; 1103 } 1104 1105 String cnArg = nextArgRequired(); 1106 ComponentName cn = ComponentName.unflattenFromString(cnArg); 1107 if (cn == null) throw new IllegalArgumentException("Bad component name: " + cnArg); 1108 1109 InstrumentationWatcher watcher = null; 1110 UiAutomationConnection connection = null; 1111 if (wait) { 1112 watcher = new InstrumentationWatcher(); 1113 watcher.setRawOutput(rawMode); 1114 connection = new UiAutomationConnection(); 1115 } 1116 1117 float[] oldAnims = null; 1118 if (no_window_animation) { 1119 oldAnims = wm.getAnimationScales(); 1120 wm.setAnimationScale(0, 0.0f); 1121 wm.setAnimationScale(1, 0.0f); 1122 } 1123 1124 if (abi != null) { 1125 final String[] supportedAbis = Build.SUPPORTED_ABIS; 1126 boolean matched = false; 1127 for (String supportedAbi : supportedAbis) { 1128 if (supportedAbi.equals(abi)) { 1129 matched = true; 1130 break; 1131 } 1132 } 1133 1134 if (!matched) { 1135 throw new AndroidException( 1136 "INSTRUMENTATION_FAILED: Unsupported instruction set " + abi); 1137 } 1138 } 1139 1140 if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher, connection, userId, abi)) { 1141 throw new AndroidException("INSTRUMENTATION_FAILED: " + cn.flattenToString()); 1142 } 1143 1144 if (watcher != null) { 1145 if (!watcher.waitForFinish()) { 1146 System.out.println("INSTRUMENTATION_ABORTED: System has crashed."); 1147 } 1148 } 1149 1150 if (oldAnims != null) { 1151 wm.setAnimationScales(oldAnims); 1152 } 1153 } 1154 1155 private void runTraceIpc() throws Exception { 1156 String op = nextArgRequired(); 1157 if (op.equals("start")) { 1158 runTraceIpcStart(); 1159 } else if (op.equals("stop")) { 1160 runTraceIpcStop(); 1161 } else { 1162 showError("Error: unknown command '" + op + "'"); 1163 return; 1164 } 1165 } 1166 1167 private void runTraceIpcStart() throws Exception { 1168 System.out.println("Starting IPC tracing."); 1169 mAm.startBinderTracking(); 1170 } 1171 1172 private void runTraceIpcStop() throws Exception { 1173 String opt; 1174 String filename = null; 1175 while ((opt=nextOption()) != null) { 1176 if (opt.equals("--dump-file")) { 1177 filename = nextArgRequired(); 1178 } else { 1179 System.err.println("Error: Unknown option: " + opt); 1180 return; 1181 } 1182 } 1183 if (filename == null) { 1184 System.err.println("Error: Specify filename to dump logs to."); 1185 return; 1186 } 1187 1188 ParcelFileDescriptor fd = null; 1189 1190 try { 1191 File file = new File(filename); 1192 file.delete(); 1193 fd = openForSystemServer(file, 1194 ParcelFileDescriptor.MODE_CREATE | 1195 ParcelFileDescriptor.MODE_TRUNCATE | 1196 ParcelFileDescriptor.MODE_READ_WRITE); 1197 } catch (FileNotFoundException e) { 1198 System.err.println("Error: Unable to open file: " + filename); 1199 System.err.println("Consider using a file under /data/local/tmp/"); 1200 return; 1201 } 1202 1203 ; 1204 if (!mAm.stopBinderTrackingAndDump(fd)) { 1205 throw new AndroidException("STOP TRACE FAILED."); 1206 } 1207 1208 System.out.println("Stopped IPC tracing. Dumping logs to: " + filename); 1209 } 1210 1211 static void removeWallOption() { 1212 String props = SystemProperties.get("dalvik.vm.extra-opts"); 1213 if (props != null && props.contains("-Xprofile:wallclock")) { 1214 props = props.replace("-Xprofile:wallclock", ""); 1215 props = props.trim(); 1216 SystemProperties.set("dalvik.vm.extra-opts", props); 1217 } 1218 } 1219 1220 private void runProfile() throws Exception { 1221 String profileFile = null; 1222 boolean start = false; 1223 boolean wall = false; 1224 int userId = UserHandle.USER_CURRENT; 1225 int profileType = 0; 1226 mSamplingInterval = 0; 1227 1228 String process = null; 1229 1230 String cmd = nextArgRequired(); 1231 1232 if ("start".equals(cmd)) { 1233 start = true; 1234 String opt; 1235 while ((opt=nextOption()) != null) { 1236 if (opt.equals("--user")) { 1237 userId = parseUserArg(nextArgRequired()); 1238 } else if (opt.equals("--wall")) { 1239 wall = true; 1240 } else if (opt.equals("--sampling")) { 1241 mSamplingInterval = Integer.parseInt(nextArgRequired()); 1242 } else { 1243 System.err.println("Error: Unknown option: " + opt); 1244 return; 1245 } 1246 } 1247 process = nextArgRequired(); 1248 } else if ("stop".equals(cmd)) { 1249 String opt; 1250 while ((opt=nextOption()) != null) { 1251 if (opt.equals("--user")) { 1252 userId = parseUserArg(nextArgRequired()); 1253 } else { 1254 System.err.println("Error: Unknown option: " + opt); 1255 return; 1256 } 1257 } 1258 process = nextArg(); 1259 } else { 1260 // Compatibility with old syntax: process is specified first. 1261 process = cmd; 1262 cmd = nextArgRequired(); 1263 if ("start".equals(cmd)) { 1264 start = true; 1265 } else if (!"stop".equals(cmd)) { 1266 throw new IllegalArgumentException("Profile command " + process + " not valid"); 1267 } 1268 } 1269 1270 if (userId == UserHandle.USER_ALL) { 1271 System.err.println("Error: Can't profile with user 'all'"); 1272 return; 1273 } 1274 1275 ParcelFileDescriptor fd = null; 1276 ProfilerInfo profilerInfo = null; 1277 1278 if (start) { 1279 profileFile = nextArgRequired(); 1280 try { 1281 fd = openForSystemServer( 1282 new File(profileFile), 1283 ParcelFileDescriptor.MODE_CREATE | 1284 ParcelFileDescriptor.MODE_TRUNCATE | 1285 ParcelFileDescriptor.MODE_READ_WRITE); 1286 } catch (FileNotFoundException e) { 1287 System.err.println("Error: Unable to open file: " + profileFile); 1288 System.err.println("Consider using a file under /data/local/tmp/"); 1289 return; 1290 } 1291 profilerInfo = new ProfilerInfo(profileFile, fd, mSamplingInterval, false); 1292 } 1293 1294 try { 1295 if (wall) { 1296 // XXX doesn't work -- this needs to be set before booting. 1297 String props = SystemProperties.get("dalvik.vm.extra-opts"); 1298 if (props == null || !props.contains("-Xprofile:wallclock")) { 1299 props = props + " -Xprofile:wallclock"; 1300 //SystemProperties.set("dalvik.vm.extra-opts", props); 1301 } 1302 } else if (start) { 1303 //removeWallOption(); 1304 } 1305 if (!mAm.profileControl(process, userId, start, profilerInfo, profileType)) { 1306 wall = false; 1307 throw new AndroidException("PROFILE FAILED on process " + process); 1308 } 1309 } finally { 1310 if (!wall) { 1311 //removeWallOption(); 1312 } 1313 } 1314 } 1315 1316 private void runDumpHeap() throws Exception { 1317 boolean managed = true; 1318 int userId = UserHandle.USER_CURRENT; 1319 1320 String opt; 1321 while ((opt=nextOption()) != null) { 1322 if (opt.equals("--user")) { 1323 userId = parseUserArg(nextArgRequired()); 1324 if (userId == UserHandle.USER_ALL) { 1325 System.err.println("Error: Can't dump heap with user 'all'"); 1326 return; 1327 } 1328 } else if (opt.equals("-n")) { 1329 managed = false; 1330 } else { 1331 System.err.println("Error: Unknown option: " + opt); 1332 return; 1333 } 1334 } 1335 String process = nextArgRequired(); 1336 String heapFile = nextArgRequired(); 1337 ParcelFileDescriptor fd = null; 1338 1339 try { 1340 File file = new File(heapFile); 1341 file.delete(); 1342 fd = openForSystemServer(file, 1343 ParcelFileDescriptor.MODE_CREATE | 1344 ParcelFileDescriptor.MODE_TRUNCATE | 1345 ParcelFileDescriptor.MODE_READ_WRITE); 1346 } catch (FileNotFoundException e) { 1347 System.err.println("Error: Unable to open file: " + heapFile); 1348 System.err.println("Consider using a file under /data/local/tmp/"); 1349 return; 1350 } 1351 1352 if (!mAm.dumpHeap(process, userId, managed, heapFile, fd)) { 1353 throw new AndroidException("HEAP DUMP FAILED on process " + process); 1354 } 1355 } 1356 1357 private void runSetDebugApp() throws Exception { 1358 boolean wait = false; 1359 boolean persistent = false; 1360 1361 String opt; 1362 while ((opt=nextOption()) != null) { 1363 if (opt.equals("-w")) { 1364 wait = true; 1365 } else if (opt.equals("--persistent")) { 1366 persistent = true; 1367 } else { 1368 System.err.println("Error: Unknown option: " + opt); 1369 return; 1370 } 1371 } 1372 1373 String pkg = nextArgRequired(); 1374 mAm.setDebugApp(pkg, wait, persistent); 1375 } 1376 1377 private void runClearDebugApp() throws Exception { 1378 mAm.setDebugApp(null, false, true); 1379 } 1380 1381 private void runSetWatchHeap() throws Exception { 1382 String proc = nextArgRequired(); 1383 String limit = nextArgRequired(); 1384 mAm.setDumpHeapDebugLimit(proc, 0, Long.parseLong(limit), null); 1385 } 1386 1387 private void runClearWatchHeap() throws Exception { 1388 String proc = nextArgRequired(); 1389 mAm.setDumpHeapDebugLimit(proc, 0, -1, null); 1390 } 1391 1392 private void runBugReport() throws Exception { 1393 mAm.requestBugReport(); 1394 System.out.println("Your lovely bug report is being created; please be patient."); 1395 } 1396 1397 private void runSwitchUser() throws Exception { 1398 String user = nextArgRequired(); 1399 mAm.switchUser(Integer.parseInt(user)); 1400 } 1401 1402 private void runStartUserInBackground() throws Exception { 1403 String user = nextArgRequired(); 1404 boolean success = mAm.startUserInBackground(Integer.parseInt(user)); 1405 if (success) { 1406 System.out.println("Success: user started"); 1407 } else { 1408 System.err.println("Error: could not start user"); 1409 } 1410 } 1411 1412 private static class StopUserCallback extends IStopUserCallback.Stub { 1413 private boolean mFinished = false; 1414 1415 public synchronized void waitForFinish() { 1416 try { 1417 while (!mFinished) wait(); 1418 } catch (InterruptedException e) { 1419 throw new IllegalStateException(e); 1420 } 1421 } 1422 1423 @Override 1424 public synchronized void userStopped(int userId) { 1425 mFinished = true; 1426 notifyAll(); 1427 } 1428 1429 @Override 1430 public synchronized void userStopAborted(int userId) { 1431 mFinished = true; 1432 notifyAll(); 1433 } 1434 } 1435 1436 private void runStopUser() throws Exception { 1437 boolean wait = false; 1438 String opt = null; 1439 while ((opt = nextOption()) != null) { 1440 if ("-w".equals(opt)) { 1441 wait = true; 1442 } else { 1443 System.err.println("Error: unknown option: " + opt); 1444 return; 1445 } 1446 } 1447 int user = Integer.parseInt(nextArgRequired()); 1448 StopUserCallback callback = wait ? new StopUserCallback() : null; 1449 1450 int res = mAm.stopUser(user, callback); 1451 if (res != ActivityManager.USER_OP_SUCCESS) { 1452 String txt = ""; 1453 switch (res) { 1454 case ActivityManager.USER_OP_IS_CURRENT: 1455 txt = " (Can't stop current user)"; 1456 break; 1457 case ActivityManager.USER_OP_UNKNOWN_USER: 1458 txt = " (Unknown user " + user + ")"; 1459 break; 1460 } 1461 System.err.println("Switch failed: " + res + txt); 1462 } else if (callback != null) { 1463 callback.waitForFinish(); 1464 } 1465 } 1466 1467 class MyActivityController extends IActivityController.Stub { 1468 final String mGdbPort; 1469 1470 static final int STATE_NORMAL = 0; 1471 static final int STATE_CRASHED = 1; 1472 static final int STATE_EARLY_ANR = 2; 1473 static final int STATE_ANR = 3; 1474 1475 int mState; 1476 1477 static final int RESULT_DEFAULT = 0; 1478 1479 static final int RESULT_CRASH_DIALOG = 0; 1480 static final int RESULT_CRASH_KILL = 1; 1481 1482 static final int RESULT_EARLY_ANR_CONTINUE = 0; 1483 static final int RESULT_EARLY_ANR_KILL = 1; 1484 1485 static final int RESULT_ANR_DIALOG = 0; 1486 static final int RESULT_ANR_KILL = 1; 1487 static final int RESULT_ANR_WAIT = 1; 1488 1489 int mResult; 1490 1491 Process mGdbProcess; 1492 Thread mGdbThread; 1493 boolean mGotGdbPrint; 1494 1495 MyActivityController(String gdbPort) { 1496 mGdbPort = gdbPort; 1497 } 1498 1499 @Override 1500 public boolean activityResuming(String pkg) { 1501 synchronized (this) { 1502 System.out.println("** Activity resuming: " + pkg); 1503 } 1504 return true; 1505 } 1506 1507 @Override 1508 public boolean activityStarting(Intent intent, String pkg) { 1509 synchronized (this) { 1510 System.out.println("** Activity starting: " + pkg); 1511 } 1512 return true; 1513 } 1514 1515 @Override 1516 public boolean appCrashed(String processName, int pid, String shortMsg, String longMsg, 1517 long timeMillis, String stackTrace) { 1518 synchronized (this) { 1519 System.out.println("** ERROR: PROCESS CRASHED"); 1520 System.out.println("processName: " + processName); 1521 System.out.println("processPid: " + pid); 1522 System.out.println("shortMsg: " + shortMsg); 1523 System.out.println("longMsg: " + longMsg); 1524 System.out.println("timeMillis: " + timeMillis); 1525 System.out.println("stack:"); 1526 System.out.print(stackTrace); 1527 System.out.println("#"); 1528 int result = waitControllerLocked(pid, STATE_CRASHED); 1529 return result == RESULT_CRASH_KILL ? false : true; 1530 } 1531 } 1532 1533 @Override 1534 public int appEarlyNotResponding(String processName, int pid, String annotation) { 1535 synchronized (this) { 1536 System.out.println("** ERROR: EARLY PROCESS NOT RESPONDING"); 1537 System.out.println("processName: " + processName); 1538 System.out.println("processPid: " + pid); 1539 System.out.println("annotation: " + annotation); 1540 int result = waitControllerLocked(pid, STATE_EARLY_ANR); 1541 if (result == RESULT_EARLY_ANR_KILL) return -1; 1542 return 0; 1543 } 1544 } 1545 1546 @Override 1547 public int appNotResponding(String processName, int pid, String processStats) { 1548 synchronized (this) { 1549 System.out.println("** ERROR: PROCESS NOT RESPONDING"); 1550 System.out.println("processName: " + processName); 1551 System.out.println("processPid: " + pid); 1552 System.out.println("processStats:"); 1553 System.out.print(processStats); 1554 System.out.println("#"); 1555 int result = waitControllerLocked(pid, STATE_ANR); 1556 if (result == RESULT_ANR_KILL) return -1; 1557 if (result == RESULT_ANR_WAIT) return 1; 1558 return 0; 1559 } 1560 } 1561 1562 @Override 1563 public int systemNotResponding(String message) { 1564 synchronized (this) { 1565 System.out.println("** ERROR: PROCESS NOT RESPONDING"); 1566 System.out.println("message: " + message); 1567 System.out.println("#"); 1568 System.out.println("Allowing system to die."); 1569 return -1; 1570 } 1571 } 1572 1573 void killGdbLocked() { 1574 mGotGdbPrint = false; 1575 if (mGdbProcess != null) { 1576 System.out.println("Stopping gdbserver"); 1577 mGdbProcess.destroy(); 1578 mGdbProcess = null; 1579 } 1580 if (mGdbThread != null) { 1581 mGdbThread.interrupt(); 1582 mGdbThread = null; 1583 } 1584 } 1585 1586 int waitControllerLocked(int pid, int state) { 1587 if (mGdbPort != null) { 1588 killGdbLocked(); 1589 1590 try { 1591 System.out.println("Starting gdbserver on port " + mGdbPort); 1592 System.out.println("Do the following:"); 1593 System.out.println(" adb forward tcp:" + mGdbPort + " tcp:" + mGdbPort); 1594 System.out.println(" gdbclient app_process :" + mGdbPort); 1595 1596 mGdbProcess = Runtime.getRuntime().exec(new String[] { 1597 "gdbserver", ":" + mGdbPort, "--attach", Integer.toString(pid) 1598 }); 1599 final InputStreamReader converter = new InputStreamReader( 1600 mGdbProcess.getInputStream()); 1601 mGdbThread = new Thread() { 1602 @Override 1603 public void run() { 1604 BufferedReader in = new BufferedReader(converter); 1605 String line; 1606 int count = 0; 1607 while (true) { 1608 synchronized (MyActivityController.this) { 1609 if (mGdbThread == null) { 1610 return; 1611 } 1612 if (count == 2) { 1613 mGotGdbPrint = true; 1614 MyActivityController.this.notifyAll(); 1615 } 1616 } 1617 try { 1618 line = in.readLine(); 1619 if (line == null) { 1620 return; 1621 } 1622 System.out.println("GDB: " + line); 1623 count++; 1624 } catch (IOException e) { 1625 return; 1626 } 1627 } 1628 } 1629 }; 1630 mGdbThread.start(); 1631 1632 // Stupid waiting for .5s. Doesn't matter if we end early. 1633 try { 1634 this.wait(500); 1635 } catch (InterruptedException e) { 1636 } 1637 1638 } catch (IOException e) { 1639 System.err.println("Failure starting gdbserver: " + e); 1640 killGdbLocked(); 1641 } 1642 } 1643 mState = state; 1644 System.out.println(""); 1645 printMessageForState(); 1646 1647 while (mState != STATE_NORMAL) { 1648 try { 1649 wait(); 1650 } catch (InterruptedException e) { 1651 } 1652 } 1653 1654 killGdbLocked(); 1655 1656 return mResult; 1657 } 1658 1659 void resumeController(int result) { 1660 synchronized (this) { 1661 mState = STATE_NORMAL; 1662 mResult = result; 1663 notifyAll(); 1664 } 1665 } 1666 1667 void printMessageForState() { 1668 switch (mState) { 1669 case STATE_NORMAL: 1670 System.out.println("Monitoring activity manager... available commands:"); 1671 break; 1672 case STATE_CRASHED: 1673 System.out.println("Waiting after crash... available commands:"); 1674 System.out.println("(c)ontinue: show crash dialog"); 1675 System.out.println("(k)ill: immediately kill app"); 1676 break; 1677 case STATE_EARLY_ANR: 1678 System.out.println("Waiting after early ANR... available commands:"); 1679 System.out.println("(c)ontinue: standard ANR processing"); 1680 System.out.println("(k)ill: immediately kill app"); 1681 break; 1682 case STATE_ANR: 1683 System.out.println("Waiting after ANR... available commands:"); 1684 System.out.println("(c)ontinue: show ANR dialog"); 1685 System.out.println("(k)ill: immediately kill app"); 1686 System.out.println("(w)ait: wait some more"); 1687 break; 1688 } 1689 System.out.println("(q)uit: finish monitoring"); 1690 } 1691 1692 void run() throws RemoteException { 1693 try { 1694 printMessageForState(); 1695 1696 mAm.setActivityController(this); 1697 mState = STATE_NORMAL; 1698 1699 InputStreamReader converter = new InputStreamReader(System.in); 1700 BufferedReader in = new BufferedReader(converter); 1701 String line; 1702 1703 while ((line = in.readLine()) != null) { 1704 boolean addNewline = true; 1705 if (line.length() <= 0) { 1706 addNewline = false; 1707 } else if ("q".equals(line) || "quit".equals(line)) { 1708 resumeController(RESULT_DEFAULT); 1709 break; 1710 } else if (mState == STATE_CRASHED) { 1711 if ("c".equals(line) || "continue".equals(line)) { 1712 resumeController(RESULT_CRASH_DIALOG); 1713 } else if ("k".equals(line) || "kill".equals(line)) { 1714 resumeController(RESULT_CRASH_KILL); 1715 } else { 1716 System.out.println("Invalid command: " + line); 1717 } 1718 } else if (mState == STATE_ANR) { 1719 if ("c".equals(line) || "continue".equals(line)) { 1720 resumeController(RESULT_ANR_DIALOG); 1721 } else if ("k".equals(line) || "kill".equals(line)) { 1722 resumeController(RESULT_ANR_KILL); 1723 } else if ("w".equals(line) || "wait".equals(line)) { 1724 resumeController(RESULT_ANR_WAIT); 1725 } else { 1726 System.out.println("Invalid command: " + line); 1727 } 1728 } else if (mState == STATE_EARLY_ANR) { 1729 if ("c".equals(line) || "continue".equals(line)) { 1730 resumeController(RESULT_EARLY_ANR_CONTINUE); 1731 } else if ("k".equals(line) || "kill".equals(line)) { 1732 resumeController(RESULT_EARLY_ANR_KILL); 1733 } else { 1734 System.out.println("Invalid command: " + line); 1735 } 1736 } else { 1737 System.out.println("Invalid command: " + line); 1738 } 1739 1740 synchronized (this) { 1741 if (addNewline) { 1742 System.out.println(""); 1743 } 1744 printMessageForState(); 1745 } 1746 } 1747 1748 } catch (IOException e) { 1749 e.printStackTrace(); 1750 } finally { 1751 mAm.setActivityController(null); 1752 } 1753 } 1754 } 1755 1756 private void runMonitor() throws Exception { 1757 String opt; 1758 String gdbPort = null; 1759 while ((opt=nextOption()) != null) { 1760 if (opt.equals("--gdb")) { 1761 gdbPort = nextArgRequired(); 1762 } else { 1763 System.err.println("Error: Unknown option: " + opt); 1764 return; 1765 } 1766 } 1767 1768 MyActivityController controller = new MyActivityController(gdbPort); 1769 controller.run(); 1770 } 1771 1772 private void runHang() throws Exception { 1773 String opt; 1774 boolean allowRestart = false; 1775 while ((opt=nextOption()) != null) { 1776 if (opt.equals("--allow-restart")) { 1777 allowRestart = true; 1778 } else { 1779 System.err.println("Error: Unknown option: " + opt); 1780 return; 1781 } 1782 } 1783 1784 System.out.println("Hanging the system..."); 1785 mAm.hang(new Binder(), allowRestart); 1786 } 1787 1788 private void runRestart() throws Exception { 1789 String opt; 1790 while ((opt=nextOption()) != null) { 1791 System.err.println("Error: Unknown option: " + opt); 1792 return; 1793 } 1794 1795 System.out.println("Restart the system..."); 1796 mAm.restart(); 1797 } 1798 1799 private void runIdleMaintenance() throws Exception { 1800 String opt; 1801 while ((opt=nextOption()) != null) { 1802 System.err.println("Error: Unknown option: " + opt); 1803 return; 1804 } 1805 1806 System.out.println("Performing idle maintenance..."); 1807 Intent intent = new Intent( 1808 "com.android.server.task.controllers.IdleController.ACTION_TRIGGER_IDLE"); 1809 mAm.broadcastIntent(null, intent, null, null, 0, null, null, null, 1810 android.app.AppOpsManager.OP_NONE, null, true, false, UserHandle.USER_ALL); 1811 } 1812 1813 private void runScreenCompat() throws Exception { 1814 String mode = nextArgRequired(); 1815 boolean enabled; 1816 if ("on".equals(mode)) { 1817 enabled = true; 1818 } else if ("off".equals(mode)) { 1819 enabled = false; 1820 } else { 1821 System.err.println("Error: enabled mode must be 'on' or 'off' at " + mode); 1822 return; 1823 } 1824 1825 String packageName = nextArgRequired(); 1826 do { 1827 try { 1828 mAm.setPackageScreenCompatMode(packageName, enabled 1829 ? ActivityManager.COMPAT_MODE_ENABLED 1830 : ActivityManager.COMPAT_MODE_DISABLED); 1831 } catch (RemoteException e) { 1832 } 1833 packageName = nextArg(); 1834 } while (packageName != null); 1835 } 1836 1837 private void runPackageImportance() throws Exception { 1838 String packageName = nextArgRequired(); 1839 try { 1840 int procState = mAm.getPackageProcessState(packageName, "com.android.shell"); 1841 System.out.println( 1842 ActivityManager.RunningAppProcessInfo.procStateToImportance(procState)); 1843 } catch (RemoteException e) { 1844 } 1845 } 1846 1847 private void runToUri(int flags) throws Exception { 1848 Intent intent = makeIntent(UserHandle.USER_CURRENT); 1849 System.out.println(intent.toUri(flags)); 1850 } 1851 1852 private class IntentReceiver extends IIntentReceiver.Stub { 1853 private boolean mFinished = false; 1854 1855 @Override 1856 public void performReceive(Intent intent, int resultCode, String data, Bundle extras, 1857 boolean ordered, boolean sticky, int sendingUser) { 1858 String line = "Broadcast completed: result=" + resultCode; 1859 if (data != null) line = line + ", data=\"" + data + "\""; 1860 if (extras != null) line = line + ", extras: " + extras; 1861 System.out.println(line); 1862 synchronized (this) { 1863 mFinished = true; 1864 notifyAll(); 1865 } 1866 } 1867 1868 public synchronized void waitForFinish() { 1869 try { 1870 while (!mFinished) wait(); 1871 } catch (InterruptedException e) { 1872 throw new IllegalStateException(e); 1873 } 1874 } 1875 } 1876 1877 private class InstrumentationWatcher extends IInstrumentationWatcher.Stub { 1878 private boolean mFinished = false; 1879 private boolean mRawMode = false; 1880 1881 /** 1882 * Set or reset "raw mode". In "raw mode", all bundles are dumped. In "pretty mode", 1883 * if a bundle includes Instrumentation.REPORT_KEY_STREAMRESULT, just print that. 1884 * @param rawMode true for raw mode, false for pretty mode. 1885 */ 1886 public void setRawOutput(boolean rawMode) { 1887 mRawMode = rawMode; 1888 } 1889 1890 @Override 1891 public void instrumentationStatus(ComponentName name, int resultCode, Bundle results) { 1892 synchronized (this) { 1893 // pretty printer mode? 1894 String pretty = null; 1895 if (!mRawMode && results != null) { 1896 pretty = results.getString(Instrumentation.REPORT_KEY_STREAMRESULT); 1897 } 1898 if (pretty != null) { 1899 System.out.print(pretty); 1900 } else { 1901 if (results != null) { 1902 for (String key : results.keySet()) { 1903 System.out.println( 1904 "INSTRUMENTATION_STATUS: " + key + "=" + results.get(key)); 1905 } 1906 } 1907 System.out.println("INSTRUMENTATION_STATUS_CODE: " + resultCode); 1908 } 1909 notifyAll(); 1910 } 1911 } 1912 1913 @Override 1914 public void instrumentationFinished(ComponentName name, int resultCode, 1915 Bundle results) { 1916 synchronized (this) { 1917 // pretty printer mode? 1918 String pretty = null; 1919 if (!mRawMode && results != null) { 1920 pretty = results.getString(Instrumentation.REPORT_KEY_STREAMRESULT); 1921 } 1922 if (pretty != null) { 1923 System.out.println(pretty); 1924 } else { 1925 if (results != null) { 1926 for (String key : results.keySet()) { 1927 System.out.println( 1928 "INSTRUMENTATION_RESULT: " + key + "=" + results.get(key)); 1929 } 1930 } 1931 System.out.println("INSTRUMENTATION_CODE: " + resultCode); 1932 } 1933 mFinished = true; 1934 notifyAll(); 1935 } 1936 } 1937 1938 public boolean waitForFinish() { 1939 synchronized (this) { 1940 while (!mFinished) { 1941 try { 1942 if (!mAm.asBinder().pingBinder()) { 1943 return false; 1944 } 1945 wait(1000); 1946 } catch (InterruptedException e) { 1947 throw new IllegalStateException(e); 1948 } 1949 } 1950 } 1951 return true; 1952 } 1953 } 1954 1955 private void runStack() throws Exception { 1956 String op = nextArgRequired(); 1957 if (op.equals("start")) { 1958 runStackStart(); 1959 } else if (op.equals("movetask")) { 1960 runStackMoveTask(); 1961 } else if (op.equals("resize")) { 1962 runStackResize(); 1963 } else if (op.equals("positiontask")) { 1964 runStackPositionTask(); 1965 } else if (op.equals("list")) { 1966 runStackList(); 1967 } else if (op.equals("info")) { 1968 runStackInfo(); 1969 } else if (op.equals("split")) { 1970 runStackSplit(); 1971 } else if (op.equals("size-docked-stack-test")) { 1972 runStackSizeDockedStackTest(); 1973 } else { 1974 showError("Error: unknown command '" + op + "'"); 1975 return; 1976 } 1977 } 1978 1979 private void runStackStart() throws Exception { 1980 String displayIdStr = nextArgRequired(); 1981 int displayId = Integer.valueOf(displayIdStr); 1982 Intent intent = makeIntent(UserHandle.USER_CURRENT); 1983 1984 try { 1985 IActivityContainer container = mAm.createStackOnDisplay(displayId); 1986 if (container != null) { 1987 container.startActivity(intent); 1988 } 1989 } catch (RemoteException e) { 1990 } 1991 } 1992 1993 private void runStackMoveTask() throws Exception { 1994 String taskIdStr = nextArgRequired(); 1995 int taskId = Integer.valueOf(taskIdStr); 1996 String stackIdStr = nextArgRequired(); 1997 int stackId = Integer.valueOf(stackIdStr); 1998 String toTopStr = nextArgRequired(); 1999 final boolean toTop; 2000 if ("true".equals(toTopStr)) { 2001 toTop = true; 2002 } else if ("false".equals(toTopStr)) { 2003 toTop = false; 2004 } else { 2005 System.err.println("Error: bad toTop arg: " + toTopStr); 2006 return; 2007 } 2008 2009 try { 2010 mAm.moveTaskToStack(taskId, stackId, toTop); 2011 } catch (RemoteException e) { 2012 } 2013 } 2014 2015 private void runStackResize() throws Exception { 2016 String stackIdStr = nextArgRequired(); 2017 int stackId = Integer.valueOf(stackIdStr); 2018 final Rect bounds = getBounds(); 2019 if (bounds == null) { 2020 System.err.println("Error: invalid input bounds"); 2021 return; 2022 } 2023 resizeStack(stackId, bounds, 0); 2024 } 2025 2026 private void resizeStack(int stackId, Rect bounds, int delayMs) throws Exception { 2027 if (bounds == null) { 2028 showError("Error: invalid input bounds"); 2029 return; 2030 } 2031 2032 try { 2033 mAm.resizeStack(stackId, bounds); 2034 Thread.sleep(delayMs); 2035 } catch (RemoteException e) { 2036 showError("Error: resizing stack " + e); 2037 } catch (InterruptedException e) { 2038 } 2039 } 2040 2041 private void runStackPositionTask() throws Exception { 2042 String taskIdStr = nextArgRequired(); 2043 int taskId = Integer.valueOf(taskIdStr); 2044 String stackIdStr = nextArgRequired(); 2045 int stackId = Integer.valueOf(stackIdStr); 2046 String positionStr = nextArgRequired(); 2047 int position = Integer.valueOf(positionStr); 2048 2049 try { 2050 mAm.positionTaskInStack(taskId, stackId, position); 2051 } catch (RemoteException e) { 2052 } 2053 } 2054 2055 private void runStackList() throws Exception { 2056 try { 2057 List<StackInfo> stacks = mAm.getAllStackInfos(); 2058 for (StackInfo info : stacks) { 2059 System.out.println(info); 2060 } 2061 } catch (RemoteException e) { 2062 } 2063 } 2064 2065 private void runStackInfo() throws Exception { 2066 try { 2067 String stackIdStr = nextArgRequired(); 2068 int stackId = Integer.valueOf(stackIdStr); 2069 StackInfo info = mAm.getStackInfo(stackId); 2070 System.out.println(info); 2071 } catch (RemoteException e) { 2072 } 2073 } 2074 2075 private void runStackSplit() throws Exception { 2076 final int stackId = Integer.valueOf(nextArgRequired()); 2077 final String splitDirection = nextArgRequired(); 2078 Intent intent = null; 2079 try { 2080 intent = makeIntent(UserHandle.USER_CURRENT); 2081 } catch (IllegalArgumentException e) { 2082 // no intent supplied. 2083 } 2084 2085 try { 2086 final StackInfo currentStackInfo = mAm.getStackInfo(stackId); 2087 // Calculate bounds for new and current stack. 2088 final Rect currentStackBounds = new Rect(currentStackInfo.bounds); 2089 final Rect newStackBounds = new Rect(currentStackInfo.bounds); 2090 if ("v".equals(splitDirection)) { 2091 currentStackBounds.right = newStackBounds.left = currentStackInfo.bounds.centerX(); 2092 } else if ("h".equals(splitDirection)) { 2093 currentStackBounds.bottom = newStackBounds.top = currentStackInfo.bounds.centerY(); 2094 } else { 2095 showError("Error: unknown split direction '" + splitDirection + "'"); 2096 return; 2097 } 2098 2099 // Create new stack 2100 IActivityContainer container = mAm.createStackOnDisplay(currentStackInfo.displayId); 2101 if (container == null) { 2102 showError("Error: Unable to create new stack..."); 2103 } 2104 2105 final int newStackId = container.getStackId(); 2106 2107 if (intent != null) { 2108 container.startActivity(intent); 2109 } else if (currentStackInfo.taskIds != null && currentStackInfo.taskIds.length > 1) { 2110 // Move top task over to new stack 2111 mAm.moveTaskToStack(currentStackInfo.taskIds[currentStackInfo.taskIds.length - 1], 2112 newStackId, true); 2113 } 2114 2115 final StackInfo newStackInfo = mAm.getStackInfo(newStackId); 2116 2117 // Make all tasks in the stacks resizeable. 2118 for (int taskId : currentStackInfo.taskIds) { 2119 mAm.setTaskResizeable(taskId, true); 2120 } 2121 2122 for (int taskId : newStackInfo.taskIds) { 2123 mAm.setTaskResizeable(taskId, true); 2124 } 2125 2126 // Resize stacks 2127 mAm.resizeStack(currentStackInfo.stackId, currentStackBounds); 2128 mAm.resizeStack(newStackInfo.stackId, newStackBounds); 2129 } catch (RemoteException e) { 2130 } 2131 } 2132 2133 private void runStackSizeDockedStackTest() throws Exception { 2134 final int stepSize = Integer.valueOf(nextArgRequired()); 2135 final String side = nextArgRequired(); 2136 final String delayStr = nextArg(); 2137 final int delayMs = (delayStr != null) ? Integer.valueOf(delayStr) : 0; 2138 2139 Rect bounds; 2140 try { 2141 StackInfo info = mAm.getStackInfo(DOCKED_STACK_ID); 2142 if (info == null) { 2143 showError("Docked stack doesn't exist"); 2144 return; 2145 } 2146 if (info.bounds == null) { 2147 showError("Docked stack doesn't have a bounds"); 2148 return; 2149 } 2150 bounds = info.bounds; 2151 } catch (RemoteException e) { 2152 showError("Unable to get docked stack info:" + e); 2153 return; 2154 } 2155 2156 final boolean horizontalGrowth = "l".equals(side) || "r".equals(side); 2157 final int changeSize = (horizontalGrowth ? bounds.width() : bounds.height()) / 2; 2158 int currentPoint; 2159 switch (side) { 2160 case "l": 2161 currentPoint = bounds.left; 2162 break; 2163 case "r": 2164 currentPoint = bounds.right; 2165 break; 2166 case "t": 2167 currentPoint = bounds.top; 2168 break; 2169 case "b": 2170 currentPoint = bounds.bottom; 2171 break; 2172 default: 2173 showError("Unknown growth side: " + side); 2174 return; 2175 } 2176 2177 final int startPoint = currentPoint; 2178 final int minPoint = currentPoint - changeSize; 2179 final int maxPoint = currentPoint + changeSize; 2180 2181 int maxChange; 2182 System.out.println("Shrinking docked stack side=" + side); 2183 while (currentPoint > minPoint) { 2184 maxChange = Math.min(stepSize, currentPoint - minPoint); 2185 currentPoint -= maxChange; 2186 setBoundsSide(bounds, side, currentPoint); 2187 resizeStack(DOCKED_STACK_ID, bounds, delayMs); 2188 } 2189 2190 System.out.println("Growing docked stack side=" + side); 2191 while (currentPoint < maxPoint) { 2192 maxChange = Math.min(stepSize, maxPoint - currentPoint); 2193 currentPoint += maxChange; 2194 setBoundsSide(bounds, side, currentPoint); 2195 resizeStack(DOCKED_STACK_ID, bounds, delayMs); 2196 } 2197 2198 System.out.println("Back to Original size side=" + side); 2199 while (currentPoint > startPoint) { 2200 maxChange = Math.min(stepSize, currentPoint - startPoint); 2201 currentPoint -= maxChange; 2202 setBoundsSide(bounds, side, currentPoint); 2203 resizeStack(DOCKED_STACK_ID, bounds, delayMs); 2204 } 2205 } 2206 2207 private void setBoundsSide(Rect bounds, String side, int value) { 2208 switch (side) { 2209 case "l": 2210 bounds.left = value; 2211 break; 2212 case "r": 2213 bounds.right = value; 2214 break; 2215 case "t": 2216 bounds.top = value; 2217 break; 2218 case "b": 2219 bounds.bottom = value; 2220 break; 2221 default: 2222 showError("Unknown set side: " + side); 2223 break; 2224 } 2225 } 2226 2227 private void runTask() throws Exception { 2228 String op = nextArgRequired(); 2229 if (op.equals("lock")) { 2230 runTaskLock(); 2231 } else if (op.equals("resizeable")) { 2232 runTaskResizeable(); 2233 } else if (op.equals("resize")) { 2234 runTaskResize(); 2235 } else if (op.equals("drag-task-test")) { 2236 runTaskDragTaskTest(); 2237 } else if (op.equals("size-task-test")) { 2238 runTaskSizeTaskTest(); 2239 } else { 2240 showError("Error: unknown command '" + op + "'"); 2241 return; 2242 } 2243 } 2244 2245 private void runTaskLock() throws Exception { 2246 String taskIdStr = nextArgRequired(); 2247 try { 2248 if (taskIdStr.equals("stop")) { 2249 mAm.stopLockTaskMode(); 2250 } else { 2251 int taskId = Integer.valueOf(taskIdStr); 2252 mAm.startLockTaskMode(taskId); 2253 } 2254 System.err.println("Activity manager is " + (mAm.isInLockTaskMode() ? "" : "not ") + 2255 "in lockTaskMode"); 2256 } catch (RemoteException e) { 2257 } 2258 } 2259 2260 private void runTaskResizeable() throws Exception { 2261 final String taskIdStr = nextArgRequired(); 2262 final int taskId = Integer.valueOf(taskIdStr); 2263 final String resizeableStr = nextArgRequired(); 2264 final boolean resizeable = Boolean.valueOf(resizeableStr); 2265 2266 try { 2267 mAm.setTaskResizeable(taskId, resizeable); 2268 } catch (RemoteException e) { 2269 } 2270 } 2271 2272 private void runTaskResize() throws Exception { 2273 final String taskIdStr = nextArgRequired(); 2274 final int taskId = Integer.valueOf(taskIdStr); 2275 final Rect bounds = getBounds(); 2276 if (bounds == null) { 2277 System.err.println("Error: invalid input bounds"); 2278 return; 2279 } 2280 taskResize(taskId, bounds, 0, false); 2281 } 2282 2283 private void taskResize(int taskId, Rect bounds, int delay_ms, boolean pretendUserResize) { 2284 try { 2285 final int resizeMode = pretendUserResize ? RESIZE_MODE_USER : RESIZE_MODE_SYSTEM; 2286 mAm.resizeTask(taskId, bounds, resizeMode); 2287 Thread.sleep(delay_ms); 2288 } catch (RemoteException e) { 2289 System.err.println("Error changing task bounds: " + e); 2290 } catch (InterruptedException e) { 2291 } 2292 } 2293 2294 private void runTaskDragTaskTest() { 2295 final int taskId = Integer.valueOf(nextArgRequired()); 2296 final int stepSize = Integer.valueOf(nextArgRequired()); 2297 final String delayStr = nextArg(); 2298 final int delay_ms = (delayStr != null) ? Integer.valueOf(delayStr) : 0; 2299 final StackInfo stackInfo; 2300 Rect taskBounds; 2301 try { 2302 stackInfo = mAm.getStackInfo(mAm.getFocusedStackId()); 2303 taskBounds = mAm.getTaskBounds(taskId); 2304 } catch (RemoteException e) { 2305 System.err.println("Error getting focus stack info or task bounds: " + e); 2306 return; 2307 } 2308 final Rect stackBounds = stackInfo.bounds; 2309 int travelRight = stackBounds.width() - taskBounds.width(); 2310 int travelLeft = -travelRight; 2311 int travelDown = stackBounds.height() - taskBounds.height(); 2312 int travelUp = -travelDown; 2313 int passes = 0; 2314 2315 // We do 2 passes to get back to the original location of the task. 2316 while (passes < 2) { 2317 // Move right 2318 System.out.println("Moving right..."); 2319 travelRight = moveTask(taskId, taskBounds, stackBounds, stepSize, 2320 travelRight, MOVING_FORWARD, MOVING_HORIZONTALLY, delay_ms); 2321 System.out.println("Still need to travel right by " + travelRight); 2322 2323 // Move down 2324 System.out.println("Moving down..."); 2325 travelDown = moveTask(taskId, taskBounds, stackBounds, stepSize, 2326 travelDown, MOVING_FORWARD, !MOVING_HORIZONTALLY, delay_ms); 2327 System.out.println("Still need to travel down by " + travelDown); 2328 2329 // Move left 2330 System.out.println("Moving left..."); 2331 travelLeft = moveTask(taskId, taskBounds, stackBounds, stepSize, 2332 travelLeft, !MOVING_FORWARD, MOVING_HORIZONTALLY, delay_ms); 2333 System.out.println("Still need to travel left by " + travelLeft); 2334 2335 // Move up 2336 System.out.println("Moving up..."); 2337 travelUp = moveTask(taskId, taskBounds, stackBounds, stepSize, 2338 travelUp, !MOVING_FORWARD, !MOVING_HORIZONTALLY, delay_ms); 2339 System.out.println("Still need to travel up by " + travelUp); 2340 2341 try { 2342 taskBounds = mAm.getTaskBounds(taskId); 2343 } catch (RemoteException e) { 2344 System.err.println("Error getting task bounds: " + e); 2345 return; 2346 } 2347 passes++; 2348 } 2349 } 2350 2351 private int moveTask(int taskId, Rect taskRect, Rect stackRect, int stepSize, 2352 int maxToTravel, boolean movingForward, boolean horizontal, int delay_ms) { 2353 int maxMove; 2354 if (movingForward) { 2355 while (maxToTravel > 0 2356 && ((horizontal && taskRect.right < stackRect.right) 2357 ||(!horizontal && taskRect.bottom < stackRect.bottom))) { 2358 if (horizontal) { 2359 maxMove = Math.min(stepSize, stackRect.right - taskRect.right); 2360 maxToTravel -= maxMove; 2361 taskRect.right += maxMove; 2362 taskRect.left += maxMove; 2363 } else { 2364 maxMove = Math.min(stepSize, stackRect.bottom - taskRect.bottom); 2365 maxToTravel -= maxMove; 2366 taskRect.top += maxMove; 2367 taskRect.bottom += maxMove; 2368 } 2369 taskResize(taskId, taskRect, delay_ms, false); 2370 } 2371 } else { 2372 while (maxToTravel < 0 2373 && ((horizontal && taskRect.left > stackRect.left) 2374 ||(!horizontal && taskRect.top > stackRect.top))) { 2375 if (horizontal) { 2376 maxMove = Math.min(stepSize, taskRect.left - stackRect.left); 2377 maxToTravel -= maxMove; 2378 taskRect.right -= maxMove; 2379 taskRect.left -= maxMove; 2380 } else { 2381 maxMove = Math.min(stepSize, taskRect.top - stackRect.top); 2382 maxToTravel -= maxMove; 2383 taskRect.top -= maxMove; 2384 taskRect.bottom -= maxMove; 2385 } 2386 taskResize(taskId, taskRect, delay_ms, false); 2387 } 2388 } 2389 // Return the remaining distance we didn't travel because we reached the target location. 2390 return maxToTravel; 2391 } 2392 2393 private void runTaskSizeTaskTest() { 2394 final int taskId = Integer.valueOf(nextArgRequired()); 2395 final int stepSize = Integer.valueOf(nextArgRequired()); 2396 final String delayStr = nextArg(); 2397 final int delay_ms = (delayStr != null) ? Integer.valueOf(delayStr) : 0; 2398 final StackInfo stackInfo; 2399 final Rect initialTaskBounds; 2400 try { 2401 stackInfo = mAm.getStackInfo(mAm.getFocusedStackId()); 2402 initialTaskBounds = mAm.getTaskBounds(taskId); 2403 } catch (RemoteException e) { 2404 System.err.println("Error getting focus stack info or task bounds: " + e); 2405 return; 2406 } 2407 final Rect stackBounds = stackInfo.bounds; 2408 stackBounds.inset(STACK_BOUNDS_INSET, STACK_BOUNDS_INSET); 2409 final Rect currentTaskBounds = new Rect(initialTaskBounds); 2410 2411 // Size by top-left 2412 System.out.println("Growing top-left"); 2413 do { 2414 currentTaskBounds.top -= getStepSize( 2415 currentTaskBounds.top, stackBounds.top, stepSize, GREATER_THAN_TARGET); 2416 2417 currentTaskBounds.left -= getStepSize( 2418 currentTaskBounds.left, stackBounds.left, stepSize, GREATER_THAN_TARGET); 2419 2420 taskResize(taskId, currentTaskBounds, delay_ms, true); 2421 } while (stackBounds.top < currentTaskBounds.top 2422 || stackBounds.left < currentTaskBounds.left); 2423 2424 // Back to original size 2425 System.out.println("Shrinking top-left"); 2426 do { 2427 currentTaskBounds.top += getStepSize( 2428 currentTaskBounds.top, initialTaskBounds.top, stepSize, !GREATER_THAN_TARGET); 2429 2430 currentTaskBounds.left += getStepSize( 2431 currentTaskBounds.left, initialTaskBounds.left, stepSize, !GREATER_THAN_TARGET); 2432 2433 taskResize(taskId, currentTaskBounds, delay_ms, true); 2434 } while (initialTaskBounds.top > currentTaskBounds.top 2435 || initialTaskBounds.left > currentTaskBounds.left); 2436 2437 // Size by top-right 2438 System.out.println("Growing top-right"); 2439 do { 2440 currentTaskBounds.top -= getStepSize( 2441 currentTaskBounds.top, stackBounds.top, stepSize, GREATER_THAN_TARGET); 2442 2443 currentTaskBounds.right += getStepSize( 2444 currentTaskBounds.right, stackBounds.right, stepSize, !GREATER_THAN_TARGET); 2445 2446 taskResize(taskId, currentTaskBounds, delay_ms, true); 2447 } while (stackBounds.top < currentTaskBounds.top 2448 || stackBounds.right > currentTaskBounds.right); 2449 2450 // Back to original size 2451 System.out.println("Shrinking top-right"); 2452 do { 2453 currentTaskBounds.top += getStepSize( 2454 currentTaskBounds.top, initialTaskBounds.top, stepSize, !GREATER_THAN_TARGET); 2455 2456 currentTaskBounds.right -= getStepSize(currentTaskBounds.right, initialTaskBounds.right, 2457 stepSize, GREATER_THAN_TARGET); 2458 2459 taskResize(taskId, currentTaskBounds, delay_ms, true); 2460 } while (initialTaskBounds.top > currentTaskBounds.top 2461 || initialTaskBounds.right < currentTaskBounds.right); 2462 2463 // Size by bottom-left 2464 System.out.println("Growing bottom-left"); 2465 do { 2466 currentTaskBounds.bottom += getStepSize( 2467 currentTaskBounds.bottom, stackBounds.bottom, stepSize, !GREATER_THAN_TARGET); 2468 2469 currentTaskBounds.left -= getStepSize( 2470 currentTaskBounds.left, stackBounds.left, stepSize, GREATER_THAN_TARGET); 2471 2472 taskResize(taskId, currentTaskBounds, delay_ms, true); 2473 } while (stackBounds.bottom > currentTaskBounds.bottom 2474 || stackBounds.left < currentTaskBounds.left); 2475 2476 // Back to original size 2477 System.out.println("Shrinking bottom-left"); 2478 do { 2479 currentTaskBounds.bottom -= getStepSize(currentTaskBounds.bottom, 2480 initialTaskBounds.bottom, stepSize, GREATER_THAN_TARGET); 2481 2482 currentTaskBounds.left += getStepSize( 2483 currentTaskBounds.left, initialTaskBounds.left, stepSize, !GREATER_THAN_TARGET); 2484 2485 taskResize(taskId, currentTaskBounds, delay_ms, true); 2486 } while (initialTaskBounds.bottom < currentTaskBounds.bottom 2487 || initialTaskBounds.left > currentTaskBounds.left); 2488 2489 // Size by bottom-right 2490 System.out.println("Growing bottom-right"); 2491 do { 2492 currentTaskBounds.bottom += getStepSize( 2493 currentTaskBounds.bottom, stackBounds.bottom, stepSize, !GREATER_THAN_TARGET); 2494 2495 currentTaskBounds.right += getStepSize( 2496 currentTaskBounds.right, stackBounds.right, stepSize, !GREATER_THAN_TARGET); 2497 2498 taskResize(taskId, currentTaskBounds, delay_ms, true); 2499 } while (stackBounds.bottom > currentTaskBounds.bottom 2500 || stackBounds.right > currentTaskBounds.right); 2501 2502 // Back to original size 2503 System.out.println("Shrinking bottom-right"); 2504 do { 2505 currentTaskBounds.bottom -= getStepSize(currentTaskBounds.bottom, 2506 initialTaskBounds.bottom, stepSize, GREATER_THAN_TARGET); 2507 2508 currentTaskBounds.right -= getStepSize(currentTaskBounds.right, initialTaskBounds.right, 2509 stepSize, GREATER_THAN_TARGET); 2510 2511 taskResize(taskId, currentTaskBounds, delay_ms, true); 2512 } while (initialTaskBounds.bottom < currentTaskBounds.bottom 2513 || initialTaskBounds.right < currentTaskBounds.right); 2514 } 2515 2516 private int getStepSize(int current, int target, int inStepSize, boolean greaterThanTarget) { 2517 int stepSize = 0; 2518 if (greaterThanTarget && target < current) { 2519 current -= inStepSize; 2520 stepSize = inStepSize; 2521 if (target > current) { 2522 stepSize -= (target - current); 2523 } 2524 } 2525 if (!greaterThanTarget && target > current) { 2526 current += inStepSize; 2527 stepSize = inStepSize; 2528 if (target < current) { 2529 stepSize += (current - target); 2530 } 2531 } 2532 return stepSize; 2533 } 2534 2535 private List<Configuration> getRecentConfigurations(int days) { 2536 IUsageStatsManager usm = IUsageStatsManager.Stub.asInterface(ServiceManager.getService( 2537 Context.USAGE_STATS_SERVICE)); 2538 final long now = System.currentTimeMillis(); 2539 final long nDaysAgo = now - (days * 24 * 60 * 60 * 1000); 2540 try { 2541 @SuppressWarnings("unchecked") 2542 ParceledListSlice<ConfigurationStats> configStatsSlice = usm.queryConfigurationStats( 2543 UsageStatsManager.INTERVAL_BEST, nDaysAgo, now, "com.android.shell"); 2544 if (configStatsSlice == null) { 2545 return Collections.emptyList(); 2546 } 2547 2548 final ArrayMap<Configuration, Integer> recentConfigs = new ArrayMap<>(); 2549 final List<ConfigurationStats> configStatsList = configStatsSlice.getList(); 2550 final int configStatsListSize = configStatsList.size(); 2551 for (int i = 0; i < configStatsListSize; i++) { 2552 final ConfigurationStats stats = configStatsList.get(i); 2553 final int indexOfKey = recentConfigs.indexOfKey(stats.getConfiguration()); 2554 if (indexOfKey < 0) { 2555 recentConfigs.put(stats.getConfiguration(), stats.getActivationCount()); 2556 } else { 2557 recentConfigs.setValueAt(indexOfKey, 2558 recentConfigs.valueAt(indexOfKey) + stats.getActivationCount()); 2559 } 2560 } 2561 2562 final Comparator<Configuration> comparator = new Comparator<Configuration>() { 2563 @Override 2564 public int compare(Configuration a, Configuration b) { 2565 return recentConfigs.get(b).compareTo(recentConfigs.get(a)); 2566 } 2567 }; 2568 2569 ArrayList<Configuration> configs = new ArrayList<>(recentConfigs.size()); 2570 configs.addAll(recentConfigs.keySet()); 2571 Collections.sort(configs, comparator); 2572 return configs; 2573 2574 } catch (RemoteException e) { 2575 return Collections.emptyList(); 2576 } 2577 } 2578 2579 private void runGetConfig() throws Exception { 2580 int days = 14; 2581 String option = nextOption(); 2582 if (option != null) { 2583 if (!option.equals("--days")) { 2584 throw new IllegalArgumentException("unrecognized option " + option); 2585 } 2586 2587 days = Integer.parseInt(nextArgRequired()); 2588 if (days <= 0) { 2589 throw new IllegalArgumentException("--days must be a positive integer"); 2590 } 2591 } 2592 2593 try { 2594 Configuration config = mAm.getConfiguration(); 2595 if (config == null) { 2596 System.err.println("Activity manager has no configuration"); 2597 return; 2598 } 2599 2600 System.out.println("config: " + Configuration.resourceQualifierString(config)); 2601 System.out.println("abi: " + TextUtils.join(",", Build.SUPPORTED_ABIS)); 2602 2603 final List<Configuration> recentConfigs = getRecentConfigurations(days); 2604 final int recentConfigSize = recentConfigs.size(); 2605 if (recentConfigSize > 0) { 2606 System.out.println("recentConfigs:"); 2607 } 2608 2609 for (int i = 0; i < recentConfigSize; i++) { 2610 System.out.println(" config: " + Configuration.resourceQualifierString( 2611 recentConfigs.get(i))); 2612 } 2613 2614 } catch (RemoteException e) { 2615 } 2616 } 2617 2618 private void runSuppressResizeConfigChanges() throws Exception { 2619 boolean suppress = Boolean.valueOf(nextArgRequired()); 2620 2621 try { 2622 mAm.suppressResizeConfigChanges(suppress); 2623 } catch (RemoteException e) { 2624 System.err.println("Error suppressing resize config changes: " + e); 2625 } 2626 } 2627 2628 private void runSetInactive() throws Exception { 2629 int userId = UserHandle.USER_CURRENT; 2630 2631 String opt; 2632 while ((opt=nextOption()) != null) { 2633 if (opt.equals("--user")) { 2634 userId = parseUserArg(nextArgRequired()); 2635 } else { 2636 System.err.println("Error: Unknown option: " + opt); 2637 return; 2638 } 2639 } 2640 String packageName = nextArgRequired(); 2641 String value = nextArgRequired(); 2642 2643 IUsageStatsManager usm = IUsageStatsManager.Stub.asInterface(ServiceManager.getService( 2644 Context.USAGE_STATS_SERVICE)); 2645 usm.setAppInactive(packageName, Boolean.parseBoolean(value), userId); 2646 } 2647 2648 private void runGetInactive() throws Exception { 2649 int userId = UserHandle.USER_CURRENT; 2650 2651 String opt; 2652 while ((opt=nextOption()) != null) { 2653 if (opt.equals("--user")) { 2654 userId = parseUserArg(nextArgRequired()); 2655 } else { 2656 System.err.println("Error: Unknown option: " + opt); 2657 return; 2658 } 2659 } 2660 String packageName = nextArgRequired(); 2661 2662 IUsageStatsManager usm = IUsageStatsManager.Stub.asInterface(ServiceManager.getService( 2663 Context.USAGE_STATS_SERVICE)); 2664 boolean isIdle = usm.isAppInactive(packageName, userId); 2665 System.out.println("Idle=" + isIdle); 2666 } 2667 2668 private void runSendTrimMemory() throws Exception { 2669 int userId = UserHandle.USER_CURRENT; 2670 String opt; 2671 while ((opt = nextOption()) != null) { 2672 if (opt.equals("--user")) { 2673 userId = parseUserArg(nextArgRequired()); 2674 if (userId == UserHandle.USER_ALL) { 2675 System.err.println("Error: Can't use user 'all'"); 2676 return; 2677 } 2678 } else { 2679 System.err.println("Error: Unknown option: " + opt); 2680 return; 2681 } 2682 } 2683 2684 String proc = nextArgRequired(); 2685 String levelArg = nextArgRequired(); 2686 int level; 2687 switch (levelArg) { 2688 case "HIDDEN": 2689 level = ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN; 2690 break; 2691 case "RUNNING_MODERATE": 2692 level = ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE; 2693 break; 2694 case "BACKGROUND": 2695 level = ComponentCallbacks2.TRIM_MEMORY_BACKGROUND; 2696 break; 2697 case "RUNNING_LOW": 2698 level = ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW; 2699 break; 2700 case "MODERATE": 2701 level = ComponentCallbacks2.TRIM_MEMORY_MODERATE; 2702 break; 2703 case "RUNNING_CRITICAL": 2704 level = ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL; 2705 break; 2706 case "COMPLETE": 2707 level = ComponentCallbacks2.TRIM_MEMORY_COMPLETE; 2708 break; 2709 default: 2710 System.err.println("Error: Unknown level option: " + levelArg); 2711 return; 2712 } 2713 if (!mAm.setProcessMemoryTrimLevel(proc, userId, level)) { 2714 System.err.println("Error: Failure to set the level - probably Unknown Process: " + 2715 proc); 2716 } 2717 } 2718 2719 private void runGetCurrentUser() throws Exception { 2720 UserInfo currentUser = Preconditions.checkNotNull(mAm.getCurrentUser(), 2721 "Current user not set"); 2722 System.out.println(currentUser.id); 2723 } 2724 2725 /** 2726 * Open the given file for sending into the system process. This verifies 2727 * with SELinux that the system will have access to the file. 2728 */ 2729 private static ParcelFileDescriptor openForSystemServer(File file, int mode) 2730 throws FileNotFoundException { 2731 final ParcelFileDescriptor fd = ParcelFileDescriptor.open(file, mode); 2732 final String tcon = SELinux.getFileContext(file.getAbsolutePath()); 2733 if (!SELinux.checkSELinuxAccess("u:r:system_server:s0", tcon, "file", "read")) { 2734 throw new FileNotFoundException("System server has no access to file context " + tcon); 2735 } 2736 return fd; 2737 } 2738 2739 private Rect getBounds() { 2740 String leftStr = nextArgRequired(); 2741 int left = Integer.valueOf(leftStr); 2742 String topStr = nextArgRequired(); 2743 int top = Integer.valueOf(topStr); 2744 String rightStr = nextArgRequired(); 2745 int right = Integer.valueOf(rightStr); 2746 String bottomStr = nextArgRequired(); 2747 int bottom = Integer.valueOf(bottomStr); 2748 if (left < 0) { 2749 System.err.println("Error: bad left arg: " + leftStr); 2750 return null; 2751 } 2752 if (top < 0) { 2753 System.err.println("Error: bad top arg: " + topStr); 2754 return null; 2755 } 2756 if (right <= 0) { 2757 System.err.println("Error: bad right arg: " + rightStr); 2758 return null; 2759 } 2760 if (bottom <= 0) { 2761 System.err.println("Error: bad bottom arg: " + bottomStr); 2762 return null; 2763 } 2764 return new Rect(left, top, right, bottom); 2765 } 2766} 2767