Am.java revision dfed4bc99f9f3d48ee7bf9e8ea051a8d5bc4f299
1/*
2**
3** Copyright 2007, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9**     http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18
19package com.android.commands.am;
20
21import android.app.ActivityManager;
22import android.app.ActivityManager.StackInfo;
23import android.app.ActivityManagerNative;
24import android.app.IActivityContainer;
25import android.app.IActivityController;
26import android.app.IActivityManager;
27import android.app.IInstrumentationWatcher;
28import android.app.Instrumentation;
29import android.app.UiAutomationConnection;
30import android.content.ComponentName;
31import android.content.IIntentReceiver;
32import android.content.Intent;
33import android.content.pm.IPackageManager;
34import android.content.pm.ResolveInfo;
35import android.graphics.Rect;
36import android.net.Uri;
37import android.os.Binder;
38import android.os.Build;
39import android.os.Bundle;
40import android.os.IBinder;
41import android.os.ParcelFileDescriptor;
42import android.os.RemoteException;
43import android.os.ServiceManager;
44import android.os.SystemProperties;
45import android.os.UserHandle;
46import android.util.AndroidException;
47import android.view.IWindowManager;
48import com.android.internal.os.BaseCommand;
49
50import dalvik.system.VMRuntime;
51
52import java.io.BufferedReader;
53import java.io.File;
54import java.io.FileNotFoundException;
55import java.io.IOException;
56import java.io.InputStreamReader;
57import java.io.PrintStream;
58import java.net.URISyntaxException;
59import java.util.HashSet;
60import java.util.List;
61
62public class Am extends BaseCommand {
63
64    private IActivityManager mAm;
65
66    private int mStartFlags = 0;
67    private boolean mWaitOption = false;
68    private boolean mStopOption = false;
69
70    private int mRepeat = 0;
71    private int mUserId;
72    private String mReceiverPermission;
73
74    private String mProfileFile;
75
76    /**
77     * Command-line entry point.
78     *
79     * @param args The command-line arguments
80     */
81    public static void main(String[] args) {
82        (new Am()).run(args);
83    }
84
85    @Override
86    public void onShowUsage(PrintStream out) {
87        out.println(
88                "usage: am [subcommand] [options]\n" +
89                "usage: am start [-D] [-W] [-P <FILE>] [--start-profiler <FILE>]\n" +
90                "               [--R COUNT] [-S] [--opengl-trace]\n" +
91                "               [--user <USER_ID> | current] <INTENT>\n" +
92                "       am startservice [--user <USER_ID> | current] <INTENT>\n" +
93                "       am stopservice [--user <USER_ID> | current] <INTENT>\n" +
94                "       am force-stop [--user <USER_ID> | all | current] <PACKAGE>\n" +
95                "       am kill [--user <USER_ID> | all | current] <PACKAGE>\n" +
96                "       am kill-all\n" +
97                "       am broadcast [--user <USER_ID> | all | current] <INTENT>\n" +
98                "       am instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]\n" +
99                "               [--user <USER_ID> | current]\n" +
100                "               [--no-window-animation]\n" +
101                "               [--abi <ABI>]\n : Launch the instrumented process with the "  +
102                "                   selected ABI. This assumes that the process supports the" +
103                "                   selected ABI." +
104                "               <COMPONENT>\n" +
105                "       am profile start [--user <USER_ID> current] <PROCESS> <FILE>\n" +
106                "       am profile stop [--user <USER_ID> current] [<PROCESS>]\n" +
107                "       am dumpheap [--user <USER_ID> current] [-n] <PROCESS> <FILE>\n" +
108                "       am set-debug-app [-w] [--persistent] <PACKAGE>\n" +
109                "       am clear-debug-app\n" +
110                "       am monitor [--gdb <port>]\n" +
111                "       am hang [--allow-restart]\n" +
112                "       am restart\n" +
113                "       am idle-maintenance\n" +
114                "       am screen-compat [on|off] <PACKAGE>\n" +
115                "       am to-uri [INTENT]\n" +
116                "       am to-intent-uri [INTENT]\n" +
117                "       am switch-user <USER_ID>\n" +
118                "       am stop-user <USER_ID>\n" +
119                "       am stack start <DISPLAY_ID> <INTENT>\n" +
120                "       am stack movetask <TASK_ID> <STACK_ID> [true|false]\n" +
121                "       am stack resize <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" +
122                "       am stack list\n" +
123                "       am stack info <STACK_ID>\n" +
124                "       am lock-task <TASK_ID>\n" +
125                "       am lock-task stop\n" +
126                "\n" +
127                "am start: start an Activity.  Options are:\n" +
128                "    -D: enable debugging\n" +
129                "    -W: wait for launch to complete\n" +
130                "    --start-profiler <FILE>: start profiler and send results to <FILE>\n" +
131                "    -P <FILE>: like above, but profiling stops when app goes idle\n" +
132                "    -R: repeat the activity launch <COUNT> times.  Prior to each repeat,\n" +
133                "        the top activity will be finished.\n" +
134                "    -S: force stop the target app before starting the activity\n" +
135                "    --opengl-trace: enable tracing of OpenGL functions\n" +
136                "    --user <USER_ID> | current: Specify which user to run as; if not\n" +
137                "        specified then run as the current user.\n" +
138                "\n" +
139                "am startservice: start a Service.  Options are:\n" +
140                "    --user <USER_ID> | current: Specify which user to run as; if not\n" +
141                "        specified then run as the current user.\n" +
142                "\n" +
143                "am stopservice: stop a Service.  Options are:\n" +
144                "    --user <USER_ID> | current: Specify which user to run as; if not\n" +
145                "        specified then run as the current user.\n" +
146                "\n" +
147                "am force-stop: force stop everything associated with <PACKAGE>.\n" +
148                "    --user <USER_ID> | all | current: Specify user to force stop;\n" +
149                "        all users if not specified.\n" +
150                "\n" +
151                "am kill: Kill all processes associated with <PACKAGE>.  Only kills.\n" +
152                "  processes that are safe to kill -- that is, will not impact the user\n" +
153                "  experience.\n" +
154                "    --user <USER_ID> | all | current: Specify user whose processes to kill;\n" +
155                "        all users if not specified.\n" +
156                "\n" +
157                "am kill-all: Kill all background processes.\n" +
158                "\n" +
159                "am broadcast: send a broadcast Intent.  Options are:\n" +
160                "    --user <USER_ID> | all | current: Specify which user to send to; if not\n" +
161                "        specified then send to all users.\n" +
162                "    --receiver-permission <PERMISSION>: Require receiver to hold permission.\n" +
163                "\n" +
164                "am instrument: start an Instrumentation.  Typically this target <COMPONENT>\n" +
165                "  is the form <TEST_PACKAGE>/<RUNNER_CLASS>.  Options are:\n" +
166                "    -r: print raw results (otherwise decode REPORT_KEY_STREAMRESULT).  Use with\n" +
167                "        [-e perf true] to generate raw output for performance measurements.\n" +
168                "    -e <NAME> <VALUE>: set argument <NAME> to <VALUE>.  For test runners a\n" +
169                "        common form is [-e <testrunner_flag> <value>[,<value>...]].\n" +
170                "    -p <FILE>: write profiling data to <FILE>\n" +
171                "    -w: wait for instrumentation to finish before returning.  Required for\n" +
172                "        test runners.\n" +
173                "    --user <USER_ID> | current: Specify user instrumentation runs in;\n" +
174                "        current user if not specified.\n" +
175                "    --no-window-animation: turn off window animations while running.\n" +
176                "\n" +
177                "am profile: start and stop profiler on a process.  The given <PROCESS> argument\n" +
178                "  may be either a process name or pid.  Options are:\n" +
179                "    --user <USER_ID> | current: When supplying a process name,\n" +
180                "        specify user of process to profile; uses current user if not specified.\n" +
181                "\n" +
182                "am dumpheap: dump the heap of a process.  The given <PROCESS> argument may\n" +
183                "  be either a process name or pid.  Options are:\n" +
184                "    -n: dump native heap instead of managed heap\n" +
185                "    --user <USER_ID> | current: When supplying a process name,\n" +
186                "        specify user of process to dump; uses current user if not specified.\n" +
187                "\n" +
188                "am set-debug-app: set application <PACKAGE> to debug.  Options are:\n" +
189                "    -w: wait for debugger when application starts\n" +
190                "    --persistent: retain this value\n" +
191                "\n" +
192                "am clear-debug-app: clear the previously set-debug-app.\n" +
193                "\n" +
194                "am bug-report: request bug report generation; will launch UI\n" +
195                "    when done to select where it should be delivered.\n" +
196                "\n" +
197                "am monitor: start monitoring for crashes or ANRs.\n" +
198                "    --gdb: start gdbserv on the given port at crash/ANR\n" +
199                "\n" +
200                "am hang: hang the system.\n" +
201                "    --allow-restart: allow watchdog to perform normal system restart\n" +
202                "\n" +
203                "am restart: restart the user-space system.\n" +
204                "\n" +
205                "am idle-maintenance: perform idle maintenance now.\n" +
206                "\n" +
207                "am screen-compat: control screen compatibility mode of <PACKAGE>.\n" +
208                "\n" +
209                "am to-uri: print the given Intent specification as a URI.\n" +
210                "\n" +
211                "am to-intent-uri: print the given Intent specification as an intent: URI.\n" +
212                "\n" +
213                "am switch-user: switch to put USER_ID in the foreground, starting\n" +
214                "  execution of that user if it is currently stopped.\n" +
215                "\n" +
216                "am stop-user: stop execution of USER_ID, not allowing it to run any\n" +
217                "  code until a later explicit switch to it.\n" +
218                "\n" +
219                "am stack start: start a new activity on <DISPLAY_ID> using <INTENT>.\n" +
220                "\n" +
221                "am stack movetask: move <TASK_ID> from its current stack to the top (true) or" +
222                "   bottom (false) of <STACK_ID>.\n" +
223                "\n" +
224                "am stack resize: change <STACK_ID> size and position to <LEFT,TOP,RIGHT,BOTTOM>.\n" +
225                "\n" +
226                "am stack list: list all of the activity stacks and their sizes.\n" +
227                "\n" +
228                "am stack info: display the information about activity stack <STACK_ID>.\n" +
229                "\n" +
230                "am lock-task: bring <TASK_ID> to the front and don't allow other tasks to run\n" +
231                "\n" +
232                "<INTENT> specifications include these flags and arguments:\n" +
233                "    [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" +
234                "    [-c <CATEGORY> [-c <CATEGORY>] ...]\n" +
235                "    [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]\n" +
236                "    [--esn <EXTRA_KEY> ...]\n" +
237                "    [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]\n" +
238                "    [--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]\n" +
239                "    [--el <EXTRA_KEY> <EXTRA_LONG_VALUE> ...]\n" +
240                "    [--ef <EXTRA_KEY> <EXTRA_FLOAT_VALUE> ...]\n" +
241                "    [--eu <EXTRA_KEY> <EXTRA_URI_VALUE> ...]\n" +
242                "    [--ecn <EXTRA_KEY> <EXTRA_COMPONENT_NAME_VALUE>]\n" +
243                "    [--eia <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]]\n" +
244                "    [--ela <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]\n" +
245                "    [--efa <EXTRA_KEY> <EXTRA_FLOAT_VALUE>[,<EXTRA_FLOAT_VALUE...]]\n" +
246                "    [--esa <EXTRA_KEY> <EXTRA_STRING_VALUE>[,<EXTRA_STRING_VALUE...]]\n" +
247                "        (to embed a comma into a string escape it using \"\\,\")\n" +
248                "    [-n <COMPONENT>] [-f <FLAGS>]\n" +
249                "    [--grant-read-uri-permission] [--grant-write-uri-permission]\n" +
250                "    [--grant-persistable-uri-permission] [--grant-prefix-uri-permission]\n" +
251                "    [--debug-log-resolution] [--exclude-stopped-packages]\n" +
252                "    [--include-stopped-packages]\n" +
253                "    [--activity-brought-to-front] [--activity-clear-top]\n" +
254                "    [--activity-clear-when-task-reset] [--activity-exclude-from-recents]\n" +
255                "    [--activity-launched-from-history] [--activity-multiple-task]\n" +
256                "    [--activity-no-animation] [--activity-no-history]\n" +
257                "    [--activity-no-user-action] [--activity-previous-is-top]\n" +
258                "    [--activity-reorder-to-front] [--activity-reset-task-if-needed]\n" +
259                "    [--activity-single-top] [--activity-clear-task]\n" +
260                "    [--activity-task-on-home]\n" +
261                "    [--receiver-registered-only] [--receiver-replace-pending]\n" +
262                "    [--selector]\n" +
263                "    [<URI> | <PACKAGE> | <COMPONENT>]\n"
264                );
265    }
266
267    @Override
268    public void onRun() throws Exception {
269
270        mAm = ActivityManagerNative.getDefault();
271        if (mAm == null) {
272            System.err.println(NO_SYSTEM_ERROR_CODE);
273            throw new AndroidException("Can't connect to activity manager; is the system running?");
274        }
275
276        String op = nextArgRequired();
277
278        if (op.equals("start")) {
279            runStart();
280        } else if (op.equals("startservice")) {
281            runStartService();
282        } else if (op.equals("stopservice")) {
283            runStopService();
284        } else if (op.equals("force-stop")) {
285            runForceStop();
286        } else if (op.equals("kill")) {
287            runKill();
288        } else if (op.equals("kill-all")) {
289            runKillAll();
290        } else if (op.equals("instrument")) {
291            runInstrument();
292        } else if (op.equals("broadcast")) {
293            sendBroadcast();
294        } else if (op.equals("profile")) {
295            runProfile();
296        } else if (op.equals("dumpheap")) {
297            runDumpHeap();
298        } else if (op.equals("set-debug-app")) {
299            runSetDebugApp();
300        } else if (op.equals("clear-debug-app")) {
301            runClearDebugApp();
302        } else if (op.equals("bug-report")) {
303            runBugReport();
304        } else if (op.equals("monitor")) {
305            runMonitor();
306        } else if (op.equals("hang")) {
307            runHang();
308        } else if (op.equals("restart")) {
309            runRestart();
310        } else if (op.equals("idle-maintenance")) {
311            runIdleMaintenance();
312        } else if (op.equals("screen-compat")) {
313            runScreenCompat();
314        } else if (op.equals("to-uri")) {
315            runToUri(false);
316        } else if (op.equals("to-intent-uri")) {
317            runToUri(true);
318        } else if (op.equals("switch-user")) {
319            runSwitchUser();
320        } else if (op.equals("stop-user")) {
321            runStopUser();
322        } else if (op.equals("stack")) {
323            runStack();
324        } else if (op.equals("lock-task")) {
325            runLockTask();
326        } else {
327            showError("Error: unknown command '" + op + "'");
328        }
329    }
330
331    int parseUserArg(String arg) {
332        int userId;
333        if ("all".equals(arg)) {
334            userId = UserHandle.USER_ALL;
335        } else if ("current".equals(arg) || "cur".equals(arg)) {
336            userId = UserHandle.USER_CURRENT;
337        } else {
338            userId = Integer.parseInt(arg);
339        }
340        return userId;
341    }
342
343    private Intent makeIntent(int defUser) throws URISyntaxException {
344        Intent intent = new Intent();
345        Intent baseIntent = intent;
346        boolean hasIntentInfo = false;
347
348        mStartFlags = 0;
349        mWaitOption = false;
350        mStopOption = false;
351        mRepeat = 0;
352        mProfileFile = null;
353        mUserId = defUser;
354        Uri data = null;
355        String type = null;
356
357        String opt;
358        while ((opt=nextOption()) != null) {
359            if (opt.equals("-a")) {
360                intent.setAction(nextArgRequired());
361                if (intent == baseIntent) {
362                    hasIntentInfo = true;
363                }
364            } else if (opt.equals("-d")) {
365                data = Uri.parse(nextArgRequired());
366                if (intent == baseIntent) {
367                    hasIntentInfo = true;
368                }
369            } else if (opt.equals("-t")) {
370                type = nextArgRequired();
371                if (intent == baseIntent) {
372                    hasIntentInfo = true;
373                }
374            } else if (opt.equals("-c")) {
375                intent.addCategory(nextArgRequired());
376                if (intent == baseIntent) {
377                    hasIntentInfo = true;
378                }
379            } else if (opt.equals("-e") || opt.equals("--es")) {
380                String key = nextArgRequired();
381                String value = nextArgRequired();
382                intent.putExtra(key, value);
383            } else if (opt.equals("--esn")) {
384                String key = nextArgRequired();
385                intent.putExtra(key, (String) null);
386            } else if (opt.equals("--ei")) {
387                String key = nextArgRequired();
388                String value = nextArgRequired();
389                intent.putExtra(key, Integer.valueOf(value));
390            } else if (opt.equals("--eu")) {
391                String key = nextArgRequired();
392                String value = nextArgRequired();
393                intent.putExtra(key, Uri.parse(value));
394            } else if (opt.equals("--ecn")) {
395                String key = nextArgRequired();
396                String value = nextArgRequired();
397                ComponentName cn = ComponentName.unflattenFromString(value);
398                if (cn == null) throw new IllegalArgumentException("Bad component name: " + value);
399                intent.putExtra(key, cn);
400            } else if (opt.equals("--eia")) {
401                String key = nextArgRequired();
402                String value = nextArgRequired();
403                String[] strings = value.split(",");
404                int[] list = new int[strings.length];
405                for (int i = 0; i < strings.length; i++) {
406                    list[i] = Integer.valueOf(strings[i]);
407                }
408                intent.putExtra(key, list);
409            } else if (opt.equals("--el")) {
410                String key = nextArgRequired();
411                String value = nextArgRequired();
412                intent.putExtra(key, Long.valueOf(value));
413            } else if (opt.equals("--ela")) {
414                String key = nextArgRequired();
415                String value = nextArgRequired();
416                String[] strings = value.split(",");
417                long[] list = new long[strings.length];
418                for (int i = 0; i < strings.length; i++) {
419                    list[i] = Long.valueOf(strings[i]);
420                }
421                intent.putExtra(key, list);
422                hasIntentInfo = true;
423            } else if (opt.equals("--ef")) {
424                String key = nextArgRequired();
425                String value = nextArgRequired();
426                intent.putExtra(key, Float.valueOf(value));
427                hasIntentInfo = true;
428            } else if (opt.equals("--efa")) {
429                String key = nextArgRequired();
430                String value = nextArgRequired();
431                String[] strings = value.split(",");
432                float[] list = new float[strings.length];
433                for (int i = 0; i < strings.length; i++) {
434                    list[i] = Float.valueOf(strings[i]);
435                }
436                intent.putExtra(key, list);
437                hasIntentInfo = true;
438            } else if (opt.equals("--esa")) {
439                String key = nextArgRequired();
440                String value = nextArgRequired();
441                // Split on commas unless they are preceeded by an escape.
442                // The escape character must be escaped for the string and
443                // again for the regex, thus four escape characters become one.
444                String[] strings = value.split("(?<!\\\\),");
445                intent.putExtra(key, strings);
446                hasIntentInfo = true;
447            } else if (opt.equals("--ez")) {
448                String key = nextArgRequired();
449                String value = nextArgRequired();
450                intent.putExtra(key, Boolean.valueOf(value));
451            } else if (opt.equals("-n")) {
452                String str = nextArgRequired();
453                ComponentName cn = ComponentName.unflattenFromString(str);
454                if (cn == null) throw new IllegalArgumentException("Bad component name: " + str);
455                intent.setComponent(cn);
456                if (intent == baseIntent) {
457                    hasIntentInfo = true;
458                }
459            } else if (opt.equals("-f")) {
460                String str = nextArgRequired();
461                intent.setFlags(Integer.decode(str).intValue());
462            } else if (opt.equals("--grant-read-uri-permission")) {
463                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
464            } else if (opt.equals("--grant-write-uri-permission")) {
465                intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
466            } else if (opt.equals("--grant-persistable-uri-permission")) {
467                intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
468            } else if (opt.equals("--grant-prefix-uri-permission")) {
469                intent.addFlags(Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
470            } else if (opt.equals("--exclude-stopped-packages")) {
471                intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
472            } else if (opt.equals("--include-stopped-packages")) {
473                intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
474            } else if (opt.equals("--debug-log-resolution")) {
475                intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION);
476            } else if (opt.equals("--activity-brought-to-front")) {
477                intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
478            } else if (opt.equals("--activity-clear-top")) {
479                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
480            } else if (opt.equals("--activity-clear-when-task-reset")) {
481                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
482            } else if (opt.equals("--activity-exclude-from-recents")) {
483                intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
484            } else if (opt.equals("--activity-launched-from-history")) {
485                intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
486            } else if (opt.equals("--activity-multiple-task")) {
487                intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
488            } else if (opt.equals("--activity-no-animation")) {
489                intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
490            } else if (opt.equals("--activity-no-history")) {
491                intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
492            } else if (opt.equals("--activity-no-user-action")) {
493                intent.addFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION);
494            } else if (opt.equals("--activity-previous-is-top")) {
495                intent.addFlags(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
496            } else if (opt.equals("--activity-reorder-to-front")) {
497                intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
498            } else if (opt.equals("--activity-reset-task-if-needed")) {
499                intent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
500            } else if (opt.equals("--activity-single-top")) {
501                intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
502            } else if (opt.equals("--activity-clear-task")) {
503                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
504            } else if (opt.equals("--activity-task-on-home")) {
505                intent.addFlags(Intent.FLAG_ACTIVITY_TASK_ON_HOME);
506            } else if (opt.equals("--receiver-registered-only")) {
507                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
508            } else if (opt.equals("--receiver-replace-pending")) {
509                intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
510            } else if (opt.equals("--selector")) {
511                intent.setDataAndType(data, type);
512                intent = new Intent();
513            } else if (opt.equals("-D")) {
514                mStartFlags |= ActivityManager.START_FLAG_DEBUG;
515            } else if (opt.equals("-W")) {
516                mWaitOption = true;
517            } else if (opt.equals("-P")) {
518                mProfileFile = nextArgRequired();
519                mStartFlags |= ActivityManager.START_FLAG_AUTO_STOP_PROFILER;
520            } else if (opt.equals("--start-profiler")) {
521                mProfileFile = nextArgRequired();
522                mStartFlags &= ~ActivityManager.START_FLAG_AUTO_STOP_PROFILER;
523            } else if (opt.equals("-R")) {
524                mRepeat = Integer.parseInt(nextArgRequired());
525            } else if (opt.equals("-S")) {
526                mStopOption = true;
527            } else if (opt.equals("--opengl-trace")) {
528                mStartFlags |= ActivityManager.START_FLAG_OPENGL_TRACES;
529            } else if (opt.equals("--user")) {
530                mUserId = parseUserArg(nextArgRequired());
531            } else if (opt.equals("--receiver-permission")) {
532                mReceiverPermission = nextArgRequired();
533            } else {
534                System.err.println("Error: Unknown option: " + opt);
535                return null;
536            }
537        }
538        intent.setDataAndType(data, type);
539
540        final boolean hasSelector = intent != baseIntent;
541        if (hasSelector) {
542            // A selector was specified; fix up.
543            baseIntent.setSelector(intent);
544            intent = baseIntent;
545        }
546
547        String arg = nextArg();
548        baseIntent = null;
549        if (arg == null) {
550            if (hasSelector) {
551                // If a selector has been specified, and no arguments
552                // have been supplied for the main Intent, then we can
553                // assume it is ACTION_MAIN CATEGORY_LAUNCHER; we don't
554                // need to have a component name specified yet, the
555                // selector will take care of that.
556                baseIntent = new Intent(Intent.ACTION_MAIN);
557                baseIntent.addCategory(Intent.CATEGORY_LAUNCHER);
558            }
559        } else if (arg.indexOf(':') >= 0) {
560            // The argument is a URI.  Fully parse it, and use that result
561            // to fill in any data not specified so far.
562            baseIntent = Intent.parseUri(arg, Intent.URI_INTENT_SCHEME);
563        } else if (arg.indexOf('/') >= 0) {
564            // The argument is a component name.  Build an Intent to launch
565            // it.
566            baseIntent = new Intent(Intent.ACTION_MAIN);
567            baseIntent.addCategory(Intent.CATEGORY_LAUNCHER);
568            baseIntent.setComponent(ComponentName.unflattenFromString(arg));
569        } else {
570            // Assume the argument is a package name.
571            baseIntent = new Intent(Intent.ACTION_MAIN);
572            baseIntent.addCategory(Intent.CATEGORY_LAUNCHER);
573            baseIntent.setPackage(arg);
574        }
575        if (baseIntent != null) {
576            Bundle extras = intent.getExtras();
577            intent.replaceExtras((Bundle)null);
578            Bundle uriExtras = baseIntent.getExtras();
579            baseIntent.replaceExtras((Bundle)null);
580            if (intent.getAction() != null && baseIntent.getCategories() != null) {
581                HashSet<String> cats = new HashSet<String>(baseIntent.getCategories());
582                for (String c : cats) {
583                    baseIntent.removeCategory(c);
584                }
585            }
586            intent.fillIn(baseIntent, Intent.FILL_IN_COMPONENT | Intent.FILL_IN_SELECTOR);
587            if (extras == null) {
588                extras = uriExtras;
589            } else if (uriExtras != null) {
590                uriExtras.putAll(extras);
591                extras = uriExtras;
592            }
593            intent.replaceExtras(extras);
594            hasIntentInfo = true;
595        }
596
597        if (!hasIntentInfo) throw new IllegalArgumentException("No intent supplied");
598        return intent;
599    }
600
601    private void runStartService() throws Exception {
602        Intent intent = makeIntent(UserHandle.USER_CURRENT);
603        if (mUserId == UserHandle.USER_ALL) {
604            System.err.println("Error: Can't start activity with user 'all'");
605            return;
606        }
607        System.out.println("Starting service: " + intent);
608        ComponentName cn = mAm.startService(null, intent, intent.getType(), mUserId);
609        if (cn == null) {
610            System.err.println("Error: Not found; no service started.");
611        } else if (cn.getPackageName().equals("!")) {
612            System.err.println("Error: Requires permission " + cn.getClassName());
613        } else if (cn.getPackageName().equals("!!")) {
614            System.err.println("Error: " + cn.getClassName());
615        }
616    }
617
618    private void runStopService() throws Exception {
619        Intent intent = makeIntent(UserHandle.USER_CURRENT);
620        if (mUserId == UserHandle.USER_ALL) {
621            System.err.println("Error: Can't stop activity with user 'all'");
622            return;
623        }
624        System.out.println("Stopping service: " + intent);
625        int result = mAm.stopService(null, intent, intent.getType(), mUserId);
626        if (result == 0) {
627            System.err.println("Service not stopped: was not running.");
628        } else if (result == 1) {
629            System.err.println("Service stopped");
630        } else if (result == -1) {
631            System.err.println("Error stopping service");
632        }
633    }
634
635    private void runStart() throws Exception {
636        Intent intent = makeIntent(UserHandle.USER_CURRENT);
637
638        if (mUserId == UserHandle.USER_ALL) {
639            System.err.println("Error: Can't start service with user 'all'");
640            return;
641        }
642
643        String mimeType = intent.getType();
644        if (mimeType == null && intent.getData() != null
645                && "content".equals(intent.getData().getScheme())) {
646            mimeType = mAm.getProviderMimeType(intent.getData(), mUserId);
647        }
648
649        do {
650            if (mStopOption) {
651                String packageName;
652                if (intent.getComponent() != null) {
653                    packageName = intent.getComponent().getPackageName();
654                } else {
655                    IPackageManager pm = IPackageManager.Stub.asInterface(
656                            ServiceManager.getService("package"));
657                    if (pm == null) {
658                        System.err.println("Error: Package manager not running; aborting");
659                        return;
660                    }
661                    List<ResolveInfo> activities = pm.queryIntentActivities(intent, mimeType, 0,
662                            mUserId);
663                    if (activities == null || activities.size() <= 0) {
664                        System.err.println("Error: Intent does not match any activities: "
665                                + intent);
666                        return;
667                    } else if (activities.size() > 1) {
668                        System.err.println("Error: Intent matches multiple activities; can't stop: "
669                                + intent);
670                        return;
671                    }
672                    packageName = activities.get(0).activityInfo.packageName;
673                }
674                System.out.println("Stopping: " + packageName);
675                mAm.forceStopPackage(packageName, mUserId);
676                Thread.sleep(250);
677            }
678
679            System.out.println("Starting: " + intent);
680            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
681
682            ParcelFileDescriptor fd = null;
683
684            if (mProfileFile != null) {
685                try {
686                    fd = ParcelFileDescriptor.open(
687                            new File(mProfileFile),
688                            ParcelFileDescriptor.MODE_CREATE |
689                            ParcelFileDescriptor.MODE_TRUNCATE |
690                            ParcelFileDescriptor.MODE_READ_WRITE);
691                } catch (FileNotFoundException e) {
692                    System.err.println("Error: Unable to open file: " + mProfileFile);
693                    return;
694                }
695            }
696
697            IActivityManager.WaitResult result = null;
698            int res;
699            if (mWaitOption) {
700                result = mAm.startActivityAndWait(null, null, intent, mimeType,
701                            null, null, 0, mStartFlags, mProfileFile, fd, null, mUserId);
702                res = result.result;
703            } else {
704                res = mAm.startActivityAsUser(null, null, intent, mimeType,
705                        null, null, 0, mStartFlags, mProfileFile, fd, null, mUserId);
706            }
707            PrintStream out = mWaitOption ? System.out : System.err;
708            boolean launched = false;
709            switch (res) {
710                case ActivityManager.START_SUCCESS:
711                    launched = true;
712                    break;
713                case ActivityManager.START_SWITCHES_CANCELED:
714                    launched = true;
715                    out.println(
716                            "Warning: Activity not started because the "
717                            + " current activity is being kept for the user.");
718                    break;
719                case ActivityManager.START_DELIVERED_TO_TOP:
720                    launched = true;
721                    out.println(
722                            "Warning: Activity not started, intent has "
723                            + "been delivered to currently running "
724                            + "top-most instance.");
725                    break;
726                case ActivityManager.START_RETURN_INTENT_TO_CALLER:
727                    launched = true;
728                    out.println(
729                            "Warning: Activity not started because intent "
730                            + "should be handled by the caller");
731                    break;
732                case ActivityManager.START_TASK_TO_FRONT:
733                    launched = true;
734                    out.println(
735                            "Warning: Activity not started, its current "
736                            + "task has been brought to the front");
737                    break;
738                case ActivityManager.START_INTENT_NOT_RESOLVED:
739                    out.println(
740                            "Error: Activity not started, unable to "
741                            + "resolve " + intent.toString());
742                    break;
743                case ActivityManager.START_CLASS_NOT_FOUND:
744                    out.println(NO_CLASS_ERROR_CODE);
745                    out.println("Error: Activity class " +
746                            intent.getComponent().toShortString()
747                            + " does not exist.");
748                    break;
749                case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
750                    out.println(
751                            "Error: Activity not started, you requested to "
752                            + "both forward and receive its result");
753                    break;
754                case ActivityManager.START_PERMISSION_DENIED:
755                    out.println(
756                            "Error: Activity not started, you do not "
757                            + "have permission to access it.");
758                    break;
759                case ActivityManager.START_NOT_VOICE_COMPATIBLE:
760                    out.println(
761                            "Error: Activity not started, voice control not allowed for: "
762                                    + intent);
763                    break;
764                default:
765                    out.println(
766                            "Error: Activity not started, unknown error code " + res);
767                    break;
768            }
769            if (mWaitOption && launched) {
770                if (result == null) {
771                    result = new IActivityManager.WaitResult();
772                    result.who = intent.getComponent();
773                }
774                System.out.println("Status: " + (result.timeout ? "timeout" : "ok"));
775                if (result.who != null) {
776                    System.out.println("Activity: " + result.who.flattenToShortString());
777                }
778                if (result.thisTime >= 0) {
779                    System.out.println("ThisTime: " + result.thisTime);
780                }
781                if (result.totalTime >= 0) {
782                    System.out.println("TotalTime: " + result.totalTime);
783                }
784                System.out.println("Complete");
785            }
786            mRepeat--;
787            if (mRepeat > 1) {
788                mAm.unhandledBack();
789            }
790        } while (mRepeat > 1);
791    }
792
793    private void runForceStop() throws Exception {
794        int userId = UserHandle.USER_ALL;
795
796        String opt;
797        while ((opt=nextOption()) != null) {
798            if (opt.equals("--user")) {
799                userId = parseUserArg(nextArgRequired());
800            } else {
801                System.err.println("Error: Unknown option: " + opt);
802                return;
803            }
804        }
805        mAm.forceStopPackage(nextArgRequired(), userId);
806    }
807
808    private void runKill() throws Exception {
809        int userId = UserHandle.USER_ALL;
810
811        String opt;
812        while ((opt=nextOption()) != null) {
813            if (opt.equals("--user")) {
814                userId = parseUserArg(nextArgRequired());
815            } else {
816                System.err.println("Error: Unknown option: " + opt);
817                return;
818            }
819        }
820        mAm.killBackgroundProcesses(nextArgRequired(), userId);
821    }
822
823    private void runKillAll() throws Exception {
824        mAm.killAllBackgroundProcesses();
825    }
826
827    private void sendBroadcast() throws Exception {
828        Intent intent = makeIntent(UserHandle.USER_ALL);
829        IntentReceiver receiver = new IntentReceiver();
830        System.out.println("Broadcasting: " + intent);
831        mAm.broadcastIntent(null, intent, null, receiver, 0, null, null, mReceiverPermission,
832                android.app.AppOpsManager.OP_NONE, true, false, mUserId);
833        receiver.waitForFinish();
834    }
835
836    private void runInstrument() throws Exception {
837        String profileFile = null;
838        boolean wait = false;
839        boolean rawMode = false;
840        boolean no_window_animation = false;
841        int userId = UserHandle.USER_CURRENT;
842        Bundle args = new Bundle();
843        String argKey = null, argValue = null;
844        IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
845        String abi = null;
846
847        String opt;
848        while ((opt=nextOption()) != null) {
849            if (opt.equals("-p")) {
850                profileFile = nextArgRequired();
851            } else if (opt.equals("-w")) {
852                wait = true;
853            } else if (opt.equals("-r")) {
854                rawMode = true;
855            } else if (opt.equals("-e")) {
856                argKey = nextArgRequired();
857                argValue = nextArgRequired();
858                args.putString(argKey, argValue);
859            } else if (opt.equals("--no_window_animation")
860                    || opt.equals("--no-window-animation")) {
861                no_window_animation = true;
862            } else if (opt.equals("--user")) {
863                userId = parseUserArg(nextArgRequired());
864            } else if (opt.equals("--abi")) {
865                abi = nextArgRequired();
866            } else {
867                System.err.println("Error: Unknown option: " + opt);
868                return;
869            }
870        }
871
872        if (userId == UserHandle.USER_ALL) {
873            System.err.println("Error: Can't start instrumentation with user 'all'");
874            return;
875        }
876
877        String cnArg = nextArgRequired();
878        ComponentName cn = ComponentName.unflattenFromString(cnArg);
879        if (cn == null) throw new IllegalArgumentException("Bad component name: " + cnArg);
880
881        InstrumentationWatcher watcher = null;
882        UiAutomationConnection connection = null;
883        if (wait) {
884            watcher = new InstrumentationWatcher();
885            watcher.setRawOutput(rawMode);
886            connection = new UiAutomationConnection();
887        }
888
889        float[] oldAnims = null;
890        if (no_window_animation) {
891            oldAnims = wm.getAnimationScales();
892            wm.setAnimationScale(0, 0.0f);
893            wm.setAnimationScale(1, 0.0f);
894        }
895
896        if (abi != null) {
897            final String[] supportedAbis = Build.SUPPORTED_ABIS;
898            boolean matched = false;
899            for (String supportedAbi : supportedAbis) {
900                if (supportedAbi.equals(abi)) {
901                    matched = true;
902                    break;
903                }
904            }
905
906            if (!matched) {
907                throw new AndroidException(
908                        "INSTRUMENTATION_FAILED: Unsupported instruction set " + abi);
909            }
910        }
911
912        if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher, connection, userId,
913                abi)) {
914            throw new AndroidException("INSTRUMENTATION_FAILED: " + cn.flattenToString());
915        }
916
917        if (watcher != null) {
918            if (!watcher.waitForFinish()) {
919                System.out.println("INSTRUMENTATION_ABORTED: System has crashed.");
920            }
921        }
922
923        if (oldAnims != null) {
924            wm.setAnimationScales(oldAnims);
925        }
926    }
927
928    static void removeWallOption() {
929        String props = SystemProperties.get("dalvik.vm.extra-opts");
930        if (props != null && props.contains("-Xprofile:wallclock")) {
931            props = props.replace("-Xprofile:wallclock", "");
932            props = props.trim();
933            SystemProperties.set("dalvik.vm.extra-opts", props);
934        }
935    }
936
937    private void runProfile() throws Exception {
938        String profileFile = null;
939        boolean start = false;
940        boolean wall = false;
941        int userId = UserHandle.USER_CURRENT;
942        int profileType = 0;
943
944        String process = null;
945
946        String cmd = nextArgRequired();
947
948        if ("start".equals(cmd)) {
949            start = true;
950            String opt;
951            while ((opt=nextOption()) != null) {
952                if (opt.equals("--user")) {
953                    userId = parseUserArg(nextArgRequired());
954                } else if (opt.equals("--wall")) {
955                    wall = true;
956                } else {
957                    System.err.println("Error: Unknown option: " + opt);
958                    return;
959                }
960            }
961            process = nextArgRequired();
962        } else if ("stop".equals(cmd)) {
963            String opt;
964            while ((opt=nextOption()) != null) {
965                if (opt.equals("--user")) {
966                    userId = parseUserArg(nextArgRequired());
967                } else {
968                    System.err.println("Error: Unknown option: " + opt);
969                    return;
970                }
971            }
972            process = nextArg();
973        } else {
974            // Compatibility with old syntax: process is specified first.
975            process = cmd;
976            cmd = nextArgRequired();
977            if ("start".equals(cmd)) {
978                start = true;
979            } else if (!"stop".equals(cmd)) {
980                throw new IllegalArgumentException("Profile command " + process + " not valid");
981            }
982        }
983
984        if (userId == UserHandle.USER_ALL) {
985            System.err.println("Error: Can't profile with user 'all'");
986            return;
987        }
988
989        ParcelFileDescriptor fd = null;
990
991        if (start) {
992            profileFile = nextArgRequired();
993            try {
994                fd = ParcelFileDescriptor.open(
995                        new File(profileFile),
996                        ParcelFileDescriptor.MODE_CREATE |
997                        ParcelFileDescriptor.MODE_TRUNCATE |
998                        ParcelFileDescriptor.MODE_READ_WRITE);
999            } catch (FileNotFoundException e) {
1000                System.err.println("Error: Unable to open file: " + profileFile);
1001                return;
1002            }
1003        }
1004
1005        try {
1006            if (wall) {
1007                // XXX doesn't work -- this needs to be set before booting.
1008                String props = SystemProperties.get("dalvik.vm.extra-opts");
1009                if (props == null || !props.contains("-Xprofile:wallclock")) {
1010                    props = props + " -Xprofile:wallclock";
1011                    //SystemProperties.set("dalvik.vm.extra-opts", props);
1012                }
1013            } else if (start) {
1014                //removeWallOption();
1015            }
1016            if (!mAm.profileControl(process, userId, start, profileFile, fd, profileType)) {
1017                wall = false;
1018                throw new AndroidException("PROFILE FAILED on process " + process);
1019            }
1020        } finally {
1021            if (!wall) {
1022                //removeWallOption();
1023            }
1024        }
1025    }
1026
1027    private void runDumpHeap() throws Exception {
1028        boolean managed = true;
1029        int userId = UserHandle.USER_CURRENT;
1030
1031        String opt;
1032        while ((opt=nextOption()) != null) {
1033            if (opt.equals("--user")) {
1034                userId = parseUserArg(nextArgRequired());
1035                if (userId == UserHandle.USER_ALL) {
1036                    System.err.println("Error: Can't dump heap with user 'all'");
1037                    return;
1038                }
1039            } else if (opt.equals("-n")) {
1040                managed = false;
1041            } else {
1042                System.err.println("Error: Unknown option: " + opt);
1043                return;
1044            }
1045        }
1046        String process = nextArgRequired();
1047        String heapFile = nextArgRequired();
1048        ParcelFileDescriptor fd = null;
1049
1050        try {
1051            File file = new File(heapFile);
1052            file.delete();
1053            fd = ParcelFileDescriptor.open(file,
1054                    ParcelFileDescriptor.MODE_CREATE |
1055                    ParcelFileDescriptor.MODE_TRUNCATE |
1056                    ParcelFileDescriptor.MODE_READ_WRITE);
1057        } catch (FileNotFoundException e) {
1058            System.err.println("Error: Unable to open file: " + heapFile);
1059            return;
1060        }
1061
1062        if (!mAm.dumpHeap(process, userId, managed, heapFile, fd)) {
1063            throw new AndroidException("HEAP DUMP FAILED on process " + process);
1064        }
1065    }
1066
1067    private void runSetDebugApp() throws Exception {
1068        boolean wait = false;
1069        boolean persistent = false;
1070
1071        String opt;
1072        while ((opt=nextOption()) != null) {
1073            if (opt.equals("-w")) {
1074                wait = true;
1075            } else if (opt.equals("--persistent")) {
1076                persistent = true;
1077            } else {
1078                System.err.println("Error: Unknown option: " + opt);
1079                return;
1080            }
1081        }
1082
1083        String pkg = nextArgRequired();
1084        mAm.setDebugApp(pkg, wait, persistent);
1085    }
1086
1087    private void runClearDebugApp() throws Exception {
1088        mAm.setDebugApp(null, false, true);
1089    }
1090
1091    private void runBugReport() throws Exception {
1092        mAm.requestBugReport();
1093        System.out.println("Your lovely bug report is being created; please be patient.");
1094    }
1095
1096    private void runSwitchUser() throws Exception {
1097        String user = nextArgRequired();
1098        mAm.switchUser(Integer.parseInt(user));
1099    }
1100
1101    private void runStopUser() throws Exception {
1102        String user = nextArgRequired();
1103        int res = mAm.stopUser(Integer.parseInt(user), null);
1104        if (res != ActivityManager.USER_OP_SUCCESS) {
1105            String txt = "";
1106            switch (res) {
1107                case ActivityManager.USER_OP_IS_CURRENT:
1108                    txt = " (Can't stop current user)";
1109                    break;
1110                case ActivityManager.USER_OP_UNKNOWN_USER:
1111                    txt = " (Unknown user " + user + ")";
1112                    break;
1113            }
1114            System.err.println("Switch failed: " + res + txt);
1115        }
1116    }
1117
1118    class MyActivityController extends IActivityController.Stub {
1119        final String mGdbPort;
1120
1121        static final int STATE_NORMAL = 0;
1122        static final int STATE_CRASHED = 1;
1123        static final int STATE_EARLY_ANR = 2;
1124        static final int STATE_ANR = 3;
1125
1126        int mState;
1127
1128        static final int RESULT_DEFAULT = 0;
1129
1130        static final int RESULT_CRASH_DIALOG = 0;
1131        static final int RESULT_CRASH_KILL = 1;
1132
1133        static final int RESULT_EARLY_ANR_CONTINUE = 0;
1134        static final int RESULT_EARLY_ANR_KILL = 1;
1135
1136        static final int RESULT_ANR_DIALOG = 0;
1137        static final int RESULT_ANR_KILL = 1;
1138        static final int RESULT_ANR_WAIT = 1;
1139
1140        int mResult;
1141
1142        Process mGdbProcess;
1143        Thread mGdbThread;
1144        boolean mGotGdbPrint;
1145
1146        MyActivityController(String gdbPort) {
1147            mGdbPort = gdbPort;
1148        }
1149
1150        @Override
1151        public boolean activityResuming(String pkg) {
1152            synchronized (this) {
1153                System.out.println("** Activity resuming: " + pkg);
1154            }
1155            return true;
1156        }
1157
1158        @Override
1159        public boolean activityStarting(Intent intent, String pkg) {
1160            synchronized (this) {
1161                System.out.println("** Activity starting: " + pkg);
1162            }
1163            return true;
1164        }
1165
1166        @Override
1167        public boolean appCrashed(String processName, int pid, String shortMsg, String longMsg,
1168                long timeMillis, String stackTrace) {
1169            synchronized (this) {
1170                System.out.println("** ERROR: PROCESS CRASHED");
1171                System.out.println("processName: " + processName);
1172                System.out.println("processPid: " + pid);
1173                System.out.println("shortMsg: " + shortMsg);
1174                System.out.println("longMsg: " + longMsg);
1175                System.out.println("timeMillis: " + timeMillis);
1176                System.out.println("stack:");
1177                System.out.print(stackTrace);
1178                System.out.println("#");
1179                int result = waitControllerLocked(pid, STATE_CRASHED);
1180                return result == RESULT_CRASH_KILL ? false : true;
1181            }
1182        }
1183
1184        @Override
1185        public int appEarlyNotResponding(String processName, int pid, String annotation) {
1186            synchronized (this) {
1187                System.out.println("** ERROR: EARLY PROCESS NOT RESPONDING");
1188                System.out.println("processName: " + processName);
1189                System.out.println("processPid: " + pid);
1190                System.out.println("annotation: " + annotation);
1191                int result = waitControllerLocked(pid, STATE_EARLY_ANR);
1192                if (result == RESULT_EARLY_ANR_KILL) return -1;
1193                return 0;
1194            }
1195        }
1196
1197        @Override
1198        public int appNotResponding(String processName, int pid, String processStats) {
1199            synchronized (this) {
1200                System.out.println("** ERROR: PROCESS NOT RESPONDING");
1201                System.out.println("processName: " + processName);
1202                System.out.println("processPid: " + pid);
1203                System.out.println("processStats:");
1204                System.out.print(processStats);
1205                System.out.println("#");
1206                int result = waitControllerLocked(pid, STATE_ANR);
1207                if (result == RESULT_ANR_KILL) return -1;
1208                if (result == RESULT_ANR_WAIT) return 1;
1209                return 0;
1210            }
1211        }
1212
1213        @Override
1214        public int systemNotResponding(String message) {
1215            synchronized (this) {
1216                System.out.println("** ERROR: PROCESS NOT RESPONDING");
1217                System.out.println("message: " + message);
1218                System.out.println("#");
1219                System.out.println("Allowing system to die.");
1220                return -1;
1221            }
1222        }
1223
1224        void killGdbLocked() {
1225            mGotGdbPrint = false;
1226            if (mGdbProcess != null) {
1227                System.out.println("Stopping gdbserver");
1228                mGdbProcess.destroy();
1229                mGdbProcess = null;
1230            }
1231            if (mGdbThread != null) {
1232                mGdbThread.interrupt();
1233                mGdbThread = null;
1234            }
1235        }
1236
1237        int waitControllerLocked(int pid, int state) {
1238            if (mGdbPort != null) {
1239                killGdbLocked();
1240
1241                try {
1242                    System.out.println("Starting gdbserver on port " + mGdbPort);
1243                    System.out.println("Do the following:");
1244                    System.out.println("  adb forward tcp:" + mGdbPort + " tcp:" + mGdbPort);
1245                    System.out.println("  gdbclient app_process :" + mGdbPort);
1246
1247                    mGdbProcess = Runtime.getRuntime().exec(new String[] {
1248                            "gdbserver", ":" + mGdbPort, "--attach", Integer.toString(pid)
1249                    });
1250                    final InputStreamReader converter = new InputStreamReader(
1251                            mGdbProcess.getInputStream());
1252                    mGdbThread = new Thread() {
1253                        @Override
1254                        public void run() {
1255                            BufferedReader in = new BufferedReader(converter);
1256                            String line;
1257                            int count = 0;
1258                            while (true) {
1259                                synchronized (MyActivityController.this) {
1260                                    if (mGdbThread == null) {
1261                                        return;
1262                                    }
1263                                    if (count == 2) {
1264                                        mGotGdbPrint = true;
1265                                        MyActivityController.this.notifyAll();
1266                                    }
1267                                }
1268                                try {
1269                                    line = in.readLine();
1270                                    if (line == null) {
1271                                        return;
1272                                    }
1273                                    System.out.println("GDB: " + line);
1274                                    count++;
1275                                } catch (IOException e) {
1276                                    return;
1277                                }
1278                            }
1279                        }
1280                    };
1281                    mGdbThread.start();
1282
1283                    // Stupid waiting for .5s.  Doesn't matter if we end early.
1284                    try {
1285                        this.wait(500);
1286                    } catch (InterruptedException e) {
1287                    }
1288
1289                } catch (IOException e) {
1290                    System.err.println("Failure starting gdbserver: " + e);
1291                    killGdbLocked();
1292                }
1293            }
1294            mState = state;
1295            System.out.println("");
1296            printMessageForState();
1297
1298            while (mState != STATE_NORMAL) {
1299                try {
1300                    wait();
1301                } catch (InterruptedException e) {
1302                }
1303            }
1304
1305            killGdbLocked();
1306
1307            return mResult;
1308        }
1309
1310        void resumeController(int result) {
1311            synchronized (this) {
1312                mState = STATE_NORMAL;
1313                mResult = result;
1314                notifyAll();
1315            }
1316        }
1317
1318        void printMessageForState() {
1319            switch (mState) {
1320                case STATE_NORMAL:
1321                    System.out.println("Monitoring activity manager...  available commands:");
1322                    break;
1323                case STATE_CRASHED:
1324                    System.out.println("Waiting after crash...  available commands:");
1325                    System.out.println("(c)ontinue: show crash dialog");
1326                    System.out.println("(k)ill: immediately kill app");
1327                    break;
1328                case STATE_EARLY_ANR:
1329                    System.out.println("Waiting after early ANR...  available commands:");
1330                    System.out.println("(c)ontinue: standard ANR processing");
1331                    System.out.println("(k)ill: immediately kill app");
1332                    break;
1333                case STATE_ANR:
1334                    System.out.println("Waiting after ANR...  available commands:");
1335                    System.out.println("(c)ontinue: show ANR dialog");
1336                    System.out.println("(k)ill: immediately kill app");
1337                    System.out.println("(w)ait: wait some more");
1338                    break;
1339            }
1340            System.out.println("(q)uit: finish monitoring");
1341        }
1342
1343        void run() throws RemoteException {
1344            try {
1345                printMessageForState();
1346
1347                mAm.setActivityController(this);
1348                mState = STATE_NORMAL;
1349
1350                InputStreamReader converter = new InputStreamReader(System.in);
1351                BufferedReader in = new BufferedReader(converter);
1352                String line;
1353
1354                while ((line = in.readLine()) != null) {
1355                    boolean addNewline = true;
1356                    if (line.length() <= 0) {
1357                        addNewline = false;
1358                    } else if ("q".equals(line) || "quit".equals(line)) {
1359                        resumeController(RESULT_DEFAULT);
1360                        break;
1361                    } else if (mState == STATE_CRASHED) {
1362                        if ("c".equals(line) || "continue".equals(line)) {
1363                            resumeController(RESULT_CRASH_DIALOG);
1364                        } else if ("k".equals(line) || "kill".equals(line)) {
1365                            resumeController(RESULT_CRASH_KILL);
1366                        } else {
1367                            System.out.println("Invalid command: " + line);
1368                        }
1369                    } else if (mState == STATE_ANR) {
1370                        if ("c".equals(line) || "continue".equals(line)) {
1371                            resumeController(RESULT_ANR_DIALOG);
1372                        } else if ("k".equals(line) || "kill".equals(line)) {
1373                            resumeController(RESULT_ANR_KILL);
1374                        } else if ("w".equals(line) || "wait".equals(line)) {
1375                            resumeController(RESULT_ANR_WAIT);
1376                        } else {
1377                            System.out.println("Invalid command: " + line);
1378                        }
1379                    } else if (mState == STATE_EARLY_ANR) {
1380                        if ("c".equals(line) || "continue".equals(line)) {
1381                            resumeController(RESULT_EARLY_ANR_CONTINUE);
1382                        } else if ("k".equals(line) || "kill".equals(line)) {
1383                            resumeController(RESULT_EARLY_ANR_KILL);
1384                        } else {
1385                            System.out.println("Invalid command: " + line);
1386                        }
1387                    } else {
1388                        System.out.println("Invalid command: " + line);
1389                    }
1390
1391                    synchronized (this) {
1392                        if (addNewline) {
1393                            System.out.println("");
1394                        }
1395                        printMessageForState();
1396                    }
1397                }
1398
1399            } catch (IOException e) {
1400                e.printStackTrace();
1401            } finally {
1402                mAm.setActivityController(null);
1403            }
1404        }
1405    }
1406
1407    private void runMonitor() throws Exception {
1408        String opt;
1409        String gdbPort = null;
1410        while ((opt=nextOption()) != null) {
1411            if (opt.equals("--gdb")) {
1412                gdbPort = nextArgRequired();
1413            } else {
1414                System.err.println("Error: Unknown option: " + opt);
1415                return;
1416            }
1417        }
1418
1419        MyActivityController controller = new MyActivityController(gdbPort);
1420        controller.run();
1421    }
1422
1423    private void runHang() throws Exception {
1424        String opt;
1425        boolean allowRestart = false;
1426        while ((opt=nextOption()) != null) {
1427            if (opt.equals("--allow-restart")) {
1428                allowRestart = true;
1429            } else {
1430                System.err.println("Error: Unknown option: " + opt);
1431                return;
1432            }
1433        }
1434
1435        System.out.println("Hanging the system...");
1436        mAm.hang(new Binder(), allowRestart);
1437    }
1438
1439    private void runRestart() throws Exception {
1440        String opt;
1441        while ((opt=nextOption()) != null) {
1442            System.err.println("Error: Unknown option: " + opt);
1443            return;
1444        }
1445
1446        System.out.println("Restart the system...");
1447        mAm.restart();
1448    }
1449
1450    private void runIdleMaintenance() throws Exception {
1451        String opt;
1452        while ((opt=nextOption()) != null) {
1453            System.err.println("Error: Unknown option: " + opt);
1454            return;
1455        }
1456
1457        System.out.println("Performing idle maintenance...");
1458        Intent intent = new Intent(
1459                "com.android.server.IdleMaintenanceService.action.FORCE_IDLE_MAINTENANCE");
1460        mAm.broadcastIntent(null, intent, null, null, 0, null, null, null,
1461                android.app.AppOpsManager.OP_NONE, true, false, UserHandle.USER_ALL);
1462    }
1463
1464    private void runScreenCompat() throws Exception {
1465        String mode = nextArgRequired();
1466        boolean enabled;
1467        if ("on".equals(mode)) {
1468            enabled = true;
1469        } else if ("off".equals(mode)) {
1470            enabled = false;
1471        } else {
1472            System.err.println("Error: enabled mode must be 'on' or 'off' at " + mode);
1473            return;
1474        }
1475
1476        String packageName = nextArgRequired();
1477        do {
1478            try {
1479                mAm.setPackageScreenCompatMode(packageName, enabled
1480                        ? ActivityManager.COMPAT_MODE_ENABLED
1481                        : ActivityManager.COMPAT_MODE_DISABLED);
1482            } catch (RemoteException e) {
1483            }
1484            packageName = nextArg();
1485        } while (packageName != null);
1486    }
1487
1488    private void runToUri(boolean intentScheme) throws Exception {
1489        Intent intent = makeIntent(UserHandle.USER_CURRENT);
1490        System.out.println(intent.toUri(intentScheme ? Intent.URI_INTENT_SCHEME : 0));
1491    }
1492
1493    private class IntentReceiver extends IIntentReceiver.Stub {
1494        private boolean mFinished = false;
1495
1496        @Override
1497        public void performReceive(Intent intent, int resultCode, String data, Bundle extras,
1498                boolean ordered, boolean sticky, int sendingUser) {
1499            String line = "Broadcast completed: result=" + resultCode;
1500            if (data != null) line = line + ", data=\"" + data + "\"";
1501            if (extras != null) line = line + ", extras: " + extras;
1502            System.out.println(line);
1503            synchronized (this) {
1504              mFinished = true;
1505              notifyAll();
1506            }
1507        }
1508
1509        public synchronized void waitForFinish() {
1510            try {
1511                while (!mFinished) wait();
1512            } catch (InterruptedException e) {
1513                throw new IllegalStateException(e);
1514            }
1515        }
1516    }
1517
1518    private class InstrumentationWatcher extends IInstrumentationWatcher.Stub {
1519        private boolean mFinished = false;
1520        private boolean mRawMode = false;
1521
1522        /**
1523         * Set or reset "raw mode".  In "raw mode", all bundles are dumped.  In "pretty mode",
1524         * if a bundle includes Instrumentation.REPORT_KEY_STREAMRESULT, just print that.
1525         * @param rawMode true for raw mode, false for pretty mode.
1526         */
1527        public void setRawOutput(boolean rawMode) {
1528            mRawMode = rawMode;
1529        }
1530
1531        @Override
1532        public void instrumentationStatus(ComponentName name, int resultCode, Bundle results) {
1533            synchronized (this) {
1534                // pretty printer mode?
1535                String pretty = null;
1536                if (!mRawMode && results != null) {
1537                    pretty = results.getString(Instrumentation.REPORT_KEY_STREAMRESULT);
1538                }
1539                if (pretty != null) {
1540                    System.out.print(pretty);
1541                } else {
1542                    if (results != null) {
1543                        for (String key : results.keySet()) {
1544                            System.out.println(
1545                                    "INSTRUMENTATION_STATUS: " + key + "=" + results.get(key));
1546                        }
1547                    }
1548                    System.out.println("INSTRUMENTATION_STATUS_CODE: " + resultCode);
1549                }
1550                notifyAll();
1551            }
1552        }
1553
1554        @Override
1555        public void instrumentationFinished(ComponentName name, int resultCode,
1556                Bundle results) {
1557            synchronized (this) {
1558                // pretty printer mode?
1559                String pretty = null;
1560                if (!mRawMode && results != null) {
1561                    pretty = results.getString(Instrumentation.REPORT_KEY_STREAMRESULT);
1562                }
1563                if (pretty != null) {
1564                    System.out.println(pretty);
1565                } else {
1566                    if (results != null) {
1567                        for (String key : results.keySet()) {
1568                            System.out.println(
1569                                    "INSTRUMENTATION_RESULT: " + key + "=" + results.get(key));
1570                        }
1571                    }
1572                    System.out.println("INSTRUMENTATION_CODE: " + resultCode);
1573                }
1574                mFinished = true;
1575                notifyAll();
1576            }
1577        }
1578
1579        public boolean waitForFinish() {
1580            synchronized (this) {
1581                while (!mFinished) {
1582                    try {
1583                        if (!mAm.asBinder().pingBinder()) {
1584                            return false;
1585                        }
1586                        wait(1000);
1587                    } catch (InterruptedException e) {
1588                        throw new IllegalStateException(e);
1589                    }
1590                }
1591            }
1592            return true;
1593        }
1594    }
1595
1596    private void runStack() throws Exception {
1597        String op = nextArgRequired();
1598        if (op.equals("start")) {
1599            runStackStart();
1600        } else if (op.equals("movetask")) {
1601            runStackMoveTask();
1602        } else if (op.equals("resize")) {
1603            runStackResize();
1604        } else if (op.equals("list")) {
1605            runStackList();
1606        } else if (op.equals("info")) {
1607            runStackInfo();
1608        } else {
1609            showError("Error: unknown command '" + op + "'");
1610            return;
1611        }
1612    }
1613
1614    private void runStackStart() throws Exception {
1615        String displayIdStr = nextArgRequired();
1616        int displayId = Integer.valueOf(displayIdStr);
1617        Intent intent = makeIntent(UserHandle.USER_CURRENT);
1618
1619        try {
1620            IBinder homeActivityToken = mAm.getHomeActivityToken();
1621            IActivityContainer container = mAm.createActivityContainer(homeActivityToken, null);
1622            container.attachToDisplay(displayId);
1623            container.startActivity(intent);
1624        } catch (RemoteException e) {
1625        }
1626    }
1627
1628    private void runStackMoveTask() throws Exception {
1629        String taskIdStr = nextArgRequired();
1630        int taskId = Integer.valueOf(taskIdStr);
1631        String stackIdStr = nextArgRequired();
1632        int stackId = Integer.valueOf(stackIdStr);
1633        String toTopStr = nextArgRequired();
1634        final boolean toTop;
1635        if ("true".equals(toTopStr)) {
1636            toTop = true;
1637        } else if ("false".equals(toTopStr)) {
1638            toTop = false;
1639        } else {
1640            System.err.println("Error: bad toTop arg: " + toTopStr);
1641            return;
1642        }
1643
1644        try {
1645            mAm.moveTaskToStack(taskId, stackId, toTop);
1646        } catch (RemoteException e) {
1647        }
1648    }
1649
1650    private void runStackResize() throws Exception {
1651        String stackIdStr = nextArgRequired();
1652        int stackId = Integer.valueOf(stackIdStr);
1653        String leftStr = nextArgRequired();
1654        int left = Integer.valueOf(leftStr);
1655        String topStr = nextArgRequired();
1656        int top = Integer.valueOf(topStr);
1657        String rightStr = nextArgRequired();
1658        int right = Integer.valueOf(rightStr);
1659        String bottomStr = nextArgRequired();
1660        int bottom = Integer.valueOf(bottomStr);
1661
1662        try {
1663            mAm.resizeStack(stackId, new Rect(left, top, right, bottom));
1664        } catch (RemoteException e) {
1665        }
1666    }
1667
1668    private void runStackList() throws Exception {
1669        try {
1670            List<StackInfo> stacks = mAm.getAllStackInfos();
1671            for (StackInfo info : stacks) {
1672                System.out.println(info);
1673            }
1674        } catch (RemoteException e) {
1675        }
1676    }
1677
1678    private void runStackInfo() throws Exception {
1679        try {
1680            String stackIdStr = nextArgRequired();
1681            int stackId = Integer.valueOf(stackIdStr);
1682            StackInfo info = mAm.getStackInfo(stackId);
1683            System.out.println(info);
1684        } catch (RemoteException e) {
1685        }
1686    }
1687
1688    private void runLockTask() throws Exception {
1689        String taskIdStr = nextArgRequired();
1690        try {
1691            if (taskIdStr.equals("stop")) {
1692                mAm.stopLockTaskMode();
1693            } else {
1694                int taskId = Integer.valueOf(taskIdStr);
1695                mAm.startLockTaskMode(taskId);
1696            }
1697            System.err.println("Activity manager is " + (mAm.isInLockTaskMode() ? "" : "not ") +
1698                    "in lockTaskMode");
1699        } catch (RemoteException e) {
1700        }
1701    }
1702}
1703