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