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