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