OSDN Git Service

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