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