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