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