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