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