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 
17 package com.android.server.pm;
18 
19 import static android.Manifest.permission.GET_APP_METADATA;
20 import static android.content.pm.PackageInstaller.LOCATION_DATA_APP;
21 import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
22 import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKED_COMPAT;
23 import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_WHEN_REQUESTED;
24 import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
25 import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
26 import static android.content.pm.PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS;
27 import static android.content.pm.PackageManager.RESTRICTION_HIDE_NOTIFICATIONS;
28 import static android.content.pm.PackageManager.RESTRICTION_NONE;
29 
30 import static com.android.server.LocalManagerRegistry.ManagerNotFoundException;
31 
32 import android.accounts.IAccountManager;
33 import android.annotation.NonNull;
34 import android.annotation.UserIdInt;
35 import android.app.ActivityManager;
36 import android.app.ActivityManagerInternal;
37 import android.app.role.RoleManager;
38 import android.app.usage.StorageStats;
39 import android.app.usage.StorageStatsManager;
40 import android.content.ComponentName;
41 import android.content.Context;
42 import android.content.IIntentReceiver;
43 import android.content.IIntentSender;
44 import android.content.Intent;
45 import android.content.IntentSender;
46 import android.content.pm.ApplicationInfo;
47 import android.content.pm.ArchivedPackageParcel;
48 import android.content.pm.FeatureInfo;
49 import android.content.pm.Flags;
50 import android.content.pm.IPackageDataObserver;
51 import android.content.pm.IPackageInstaller;
52 import android.content.pm.IPackageManager;
53 import android.content.pm.InstrumentationInfo;
54 import android.content.pm.ModuleInfo;
55 import android.content.pm.PackageInfo;
56 import android.content.pm.PackageInstaller;
57 import android.content.pm.PackageInstaller.SessionInfo;
58 import android.content.pm.PackageInstaller.SessionParams;
59 import android.content.pm.PackageItemInfo;
60 import android.content.pm.PackageManager;
61 import android.content.pm.PackageManager.NameNotFoundException;
62 import android.content.pm.PackageManagerInternal;
63 import android.content.pm.ParceledListSlice;
64 import android.content.pm.PermissionGroupInfo;
65 import android.content.pm.PermissionInfo;
66 import android.content.pm.ResolveInfo;
67 import android.content.pm.SharedLibraryInfo;
68 import android.content.pm.SuspendDialogInfo;
69 import android.content.pm.UserInfo;
70 import android.content.pm.VersionedPackage;
71 import android.content.pm.dex.DexMetadataHelper;
72 import android.content.pm.dex.ISnapshotRuntimeProfileCallback;
73 import android.content.pm.parsing.ApkLite;
74 import android.content.pm.parsing.ApkLiteParseUtils;
75 import android.content.pm.parsing.PackageLite;
76 import android.content.pm.parsing.result.ParseResult;
77 import android.content.pm.parsing.result.ParseTypeImpl;
78 import android.content.res.AssetManager;
79 import android.content.res.Resources;
80 import android.content.rollback.PackageRollbackInfo;
81 import android.content.rollback.RollbackInfo;
82 import android.content.rollback.RollbackManager;
83 import android.net.Uri;
84 import android.os.Binder;
85 import android.os.Build;
86 import android.os.Bundle;
87 import android.os.IBinder;
88 import android.os.IUserManager;
89 import android.os.Parcel;
90 import android.os.ParcelFileDescriptor;
91 import android.os.ParcelFileDescriptor.AutoCloseInputStream;
92 import android.os.PersistableBundle;
93 import android.os.Process;
94 import android.os.RemoteException;
95 import android.os.ServiceManager;
96 import android.os.ServiceSpecificException;
97 import android.os.ShellCommand;
98 import android.os.SystemClock;
99 import android.os.Trace;
100 import android.os.UserHandle;
101 import android.os.UserManager;
102 import android.os.incremental.V4Signature;
103 import android.os.storage.StorageManager;
104 import android.permission.PermissionManager;
105 import android.text.TextUtils;
106 import android.text.format.DateUtils;
107 import android.util.ArrayMap;
108 import android.util.ArraySet;
109 import android.util.IntArray;
110 import android.util.Pair;
111 import android.util.PrintWriterPrinter;
112 import android.util.Slog;
113 import android.util.SparseArray;
114 
115 import com.android.internal.content.InstallLocationUtils;
116 import com.android.internal.util.ArrayUtils;
117 import com.android.internal.util.IndentingPrintWriter;
118 import com.android.internal.util.Preconditions;
119 import com.android.server.FgThread;
120 import com.android.server.LocalManagerRegistry;
121 import com.android.server.LocalServices;
122 import com.android.server.SystemConfig;
123 import com.android.server.art.ArtManagerLocal;
124 import com.android.server.art.ReasonMapping;
125 import com.android.server.art.model.DexoptParams;
126 import com.android.server.pm.PackageManagerShellCommandDataLoader.Metadata;
127 import com.android.server.pm.permission.LegacyPermissionManagerInternal;
128 import com.android.server.pm.permission.PermissionAllowlist;
129 import com.android.server.pm.verify.domain.DomainVerificationShell;
130 
131 import libcore.io.IoUtils;
132 import libcore.io.Streams;
133 import libcore.util.HexEncoding;
134 
135 import java.io.BufferedReader;
136 import java.io.File;
137 import java.io.IOException;
138 import java.io.InputStream;
139 import java.io.InputStreamReader;
140 import java.io.PrintWriter;
141 import java.net.URISyntaxException;
142 import java.security.SecureRandom;
143 import java.text.DecimalFormat;
144 import java.util.ArrayList;
145 import java.util.Arrays;
146 import java.util.Base64;
147 import java.util.Collection;
148 import java.util.Collections;
149 import java.util.Comparator;
150 import java.util.HashMap;
151 import java.util.List;
152 import java.util.Map;
153 import java.util.Set;
154 import java.util.WeakHashMap;
155 import java.util.concurrent.CompletableFuture;
156 import java.util.concurrent.CountDownLatch;
157 import java.util.concurrent.LinkedBlockingQueue;
158 import java.util.concurrent.TimeUnit;
159 
160 class PackageManagerShellCommand extends ShellCommand {
161     /** Path for streaming APK content */
162     private static final String STDIN_PATH = "-";
163     /** Path where ART profiles snapshots are dumped for the shell user */
164     private final static String ART_PROFILE_SNAPSHOT_DEBUG_LOCATION = "/data/misc/profman/";
165     private static final int DEFAULT_STAGED_READY_TIMEOUT_MS = 60 * 1000;
166     private static final String TAG = "PackageManagerShellCommand";
167     private static final Set<String> UNSUPPORTED_INSTALL_CMD_OPTS = Set.of(
168             "--multi-package"
169     );
170     private static final Set<String> UNSUPPORTED_SESSION_CREATE_OPTS = Collections.emptySet();
171     private static final Map<String, Integer> SUPPORTED_PERMISSION_FLAGS = new ArrayMap<>();
172     private static final List<String> SUPPORTED_PERMISSION_FLAGS_LIST;
173     static {
174         SUPPORTED_PERMISSION_FLAGS_LIST = List.of("review-required", "revoked-compat",
175                 "revoke-when-requested", "user-fixed", "user-set");
176         SUPPORTED_PERMISSION_FLAGS.put("user-set", FLAG_PERMISSION_USER_SET);
177         SUPPORTED_PERMISSION_FLAGS.put("user-fixed", FLAG_PERMISSION_USER_FIXED);
178         SUPPORTED_PERMISSION_FLAGS.put("revoked-compat", FLAG_PERMISSION_REVOKED_COMPAT);
179         SUPPORTED_PERMISSION_FLAGS.put("review-required", FLAG_PERMISSION_REVIEW_REQUIRED);
180         SUPPORTED_PERMISSION_FLAGS.put("revoke-when-requested",
181                 FLAG_PERMISSION_REVOKE_WHEN_REQUESTED);
182     }
183     // For backward compatibility. DO NOT add new commands here. New ART Service commands should be
184     // added under the "art" namespace.
185     private static final Set<String> ART_SERVICE_COMMANDS = Set.of("compile",
186             "reconcile-secondary-dex-files", "force-dex-opt", "bg-dexopt-job",
187             "cancel-bg-dexopt-job", "delete-dexopt", "dump-profiles", "snapshot-profile", "art");
188 
189     final IPackageManager mInterface;
190     private final PackageManagerInternal mPm;
191     final LegacyPermissionManagerInternal mLegacyPermissionManager;
192     final PermissionManager mPermissionManager;
193     final Context mContext;
194     final DomainVerificationShell mDomainVerificationShell;
195     final private WeakHashMap<String, Resources> mResourceCache =
196             new WeakHashMap<String, Resources>();
197     int mTargetUser;
198     boolean mBrief;
199     boolean mComponents;
200     int mQueryFlags;
201 
202     private static final SecureRandom RANDOM = new SecureRandom();
203 
PackageManagerShellCommand(@onNull IPackageManager packageManager, @NonNull Context context, @NonNull DomainVerificationShell domainVerificationShell)204     PackageManagerShellCommand(@NonNull IPackageManager packageManager,
205             @NonNull Context context, @NonNull DomainVerificationShell domainVerificationShell) {
206         mInterface = packageManager;
207         mPm = LocalServices.getService(PackageManagerInternal.class);
208         mLegacyPermissionManager = LocalServices.getService(LegacyPermissionManagerInternal.class);
209         mPermissionManager = context.getSystemService(PermissionManager.class);
210         mContext = context;
211         mDomainVerificationShell = domainVerificationShell;
212     }
213 
214     @Override
onCommand(String cmd)215     public int onCommand(String cmd) {
216         if (cmd == null) {
217             return handleDefaultCommands(cmd);
218         }
219 
220         final PrintWriter pw = getOutPrintWriter();
221         try {
222             switch (cmd) {
223                 case "help":
224                     onHelp();
225                     return 0;
226                 case "path":
227                     return runPath();
228                 case "dump":
229                     return runDump();
230                 case "dump-package":
231                     return runDumpPackage();
232                 case "list":
233                     return runList();
234                 case "gc":
235                     return runGc();
236                 case "resolve-activity":
237                     return runResolveActivity();
238                 case "query-activities":
239                     return runQueryIntentActivities();
240                 case "query-services":
241                     return runQueryIntentServices();
242                 case "query-receivers":
243                     return runQueryIntentReceivers();
244                 case "install":
245                     return runInstall();
246                 case "install-streaming":
247                     return runStreamingInstall();
248                 case "install-incremental":
249                     return runIncrementalInstall();
250                 case "install-abandon":
251                 case "install-destroy":
252                     return runInstallAbandon();
253                 case "install-commit":
254                     return runInstallCommit();
255                 case "install-create":
256                     return runInstallCreate();
257                 case "install-remove":
258                     return runInstallRemove();
259                 case "install-write":
260                     return runInstallWrite();
261                 case "install-existing":
262                     return runInstallExisting();
263                 case "set-install-location":
264                     return runSetInstallLocation();
265                 case "get-install-location":
266                     return runGetInstallLocation();
267                 case "install-add-session":
268                     return runInstallAddSession();
269                 case "install-set-pre-verified-domains":
270                     return runInstallSetPreVerifiedDomains();
271                 case "install-get-pre-verified-domains":
272                     return runInstallGetPreVerifiedDomains();
273                 case "move-package":
274                     return runMovePackage();
275                 case "move-primary-storage":
276                     return runMovePrimaryStorage();
277                 case "uninstall":
278                     return runUninstall();
279                 case "clear":
280                     return runClear();
281                 case "get-archived-package-metadata":
282                     return runGetArchivedPackageMetadata();
283                 case "get-package-storage-stats":
284                     return runGetPackageStorageStats();
285                 case "install-archived":
286                     return runArchivedInstall();
287                 case "enable":
288                     return runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
289                 case "disable":
290                     return runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
291                 case "disable-user":
292                     return runSetEnabledSetting(
293                             PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER);
294                 case "disable-until-used":
295                     return runSetEnabledSetting(
296                             PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED);
297                 case "default-state":
298                     return runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT);
299                 case "hide":
300                     return runSetHiddenSetting(true);
301                 case "unhide":
302                     return runSetHiddenSetting(false);
303                 case "unstop":
304                     return runSetStoppedState(false);
305                 case "suspend":
306                     return runSuspend(true, 0);
307                 case "suspend-quarantine":
308                     return runSuspend(true, PackageManager.FLAG_SUSPEND_QUARANTINED);
309                 case "unsuspend":
310                     return runSuspend(false, 0);
311                 case "set-distracting-restriction":
312                     return runSetDistractingRestriction();
313                 case "get-distracting-restriction":
314                     return runGetDistractingRestriction();
315                 case "grant":
316                     return runGrantRevokePermission(true);
317                 case "revoke":
318                     return runGrantRevokePermission(false);
319                 case "reset-permissions":
320                     return runResetPermissions();
321                 case "set-permission-flags":
322                     return setOrClearPermissionFlags(true);
323                 case "clear-permission-flags":
324                     return setOrClearPermissionFlags(false);
325                 case "set-permission-enforced":
326                     return runSetPermissionEnforced();
327                 case "get-privapp-permissions":
328                     return runGetPrivappPermissions();
329                 case "get-privapp-deny-permissions":
330                     return runGetPrivappDenyPermissions();
331                 case "get-oem-permissions":
332                     return runGetOemPermissions();
333                 case "get-signature-permission-allowlist":
334                     return runGetSignaturePermissionAllowlist();
335                 case "get-shared-uid-allowlist":
336                     return runGetSharedUidAllowlist();
337                 case "trim-caches":
338                     return runTrimCaches();
339                 case "create-user":
340                     return runCreateUser();
341                 case "remove-user":
342                     return runRemoveUser();
343                 case "mark-guest-for-deletion":
344                     return runMarkGuestForDeletion();
345                 case "rename-user":
346                     return runRenameUser();
347                 case "set-user-restriction":
348                     return runSetUserRestriction();
349                 case "get-user-restriction":
350                     return runGetUserRestriction();
351                 case "supports-multiple-users":
352                     return runSupportsMultipleUsers();
353                 case "get-max-users":
354                     return runGetMaxUsers();
355                 case "get-max-running-users":
356                     return runGetMaxRunningUsers();
357                 case "set-home-activity":
358                     return runSetHomeActivity();
359                 case "set-installer":
360                     return runSetInstaller();
361                 case "get-instantapp-resolver":
362                     return runGetInstantAppResolver();
363                 case "has-feature":
364                     return runHasFeature();
365                 case "set-harmful-app-warning":
366                     return runSetHarmfulAppWarning();
367                 case "get-harmful-app-warning":
368                     return runGetHarmfulAppWarning();
369                 case "get-stagedsessions":
370                     return runListStagedSessions();
371                 case "uninstall-system-updates":
372                     String packageName = getNextArg();
373                     return uninstallSystemUpdates(packageName);
374                 case "rollback-app":
375                     return runRollbackApp();
376                 case "get-moduleinfo":
377                     return runGetModuleInfo();
378                 case "log-visibility":
379                     return runLogVisibility();
380                 case "bypass-staged-installer-check":
381                     return runBypassStagedInstallerCheck();
382                 case "bypass-allowed-apex-update-check":
383                     return runBypassAllowedApexUpdateCheck();
384                 case "disable-verification-for-uid":
385                     return runDisableVerificationForUid();
386                 case "set-silent-updates-policy":
387                     return runSetSilentUpdatesPolicy();
388                 case "get-app-metadata":
389                     return runGetAppMetadata();
390                 case "clear-package-preferred-activities":
391                     return runClearPackagePreferredActivities();
392                 case "wait-for-handler":
393                     return runWaitForHandler(/* forBackgroundHandler= */ false);
394                 case "wait-for-background-handler":
395                     return runWaitForHandler(/* forBackgroundHandler= */ true);
396                 case "archive":
397                     return runArchive();
398                 case "request-unarchive":
399                     return runUnarchive();
400                 case "get-domain-verification-agent":
401                     return runGetDomainVerificationAgent();
402                 default: {
403                     if (ART_SERVICE_COMMANDS.contains(cmd)) {
404                         return runArtServiceCommand();
405                     }
406 
407                     Boolean domainVerificationResult =
408                             mDomainVerificationShell.runCommand(this, cmd);
409                     if (domainVerificationResult != null) {
410                         return domainVerificationResult ? 0 : 1;
411                     }
412 
413                     String nextArg = getNextArg();
414                     if (nextArg == null) {
415                         if (cmd.equalsIgnoreCase("-l")) {
416                             return runListPackages(false);
417                         } else if (cmd.equalsIgnoreCase("-lf")) {
418                             return runListPackages(true);
419                         }
420                     } else if (getNextArg() == null) {
421                         if (cmd.equalsIgnoreCase("-p")) {
422                             return displayPackageFilePath(nextArg, UserHandle.USER_SYSTEM);
423                         }
424                     }
425                     return handleDefaultCommands(cmd);
426                 }
427             }
428         } catch (RemoteException e) {
429             pw.println("Remote exception: " + e);
430         }
431         return -1;
432     }
433 
434     /**
435      * Shows module info
436      *
437      * Usage: get-moduleinfo [--all | --installed] [module-name]
438      * Example: get-moduleinfo, get-moduleinfo --all, get-moduleinfo xyz
439      */
runGetModuleInfo()440     private int runGetModuleInfo() {
441         final PrintWriter pw = getOutPrintWriter();
442         int flags = 0;
443 
444         String opt;
445         while ((opt = getNextOption()) != null) {
446             switch (opt) {
447                 case "--all":
448                     flags |= PackageManager.MATCH_ALL;
449                     break;
450                 case "--installed":
451                     break;
452                 default:
453                     pw.println("Error: Unknown option: " + opt);
454                     return -1;
455             }
456         }
457 
458         String moduleName = getNextArg();
459         try {
460             if (moduleName != null) {
461                 ModuleInfo m = mInterface.getModuleInfo(moduleName, flags);
462                 pw.println(m.toString() + " packageName: " + m.getPackageName());
463 
464             } else {
465                 List<ModuleInfo> modules = mInterface.getInstalledModules(flags);
466                 for (ModuleInfo m: modules) {
467                     pw.println(m.toString() + " packageName: " + m.getPackageName());
468                 }
469             }
470         } catch (RemoteException e) {
471             pw.println("Failure [" + e.getClass().getName() + " - " + e.getMessage() + "]");
472             return -1;
473         }
474         return 1;
475     }
476 
runLogVisibility()477     private int runLogVisibility() {
478         final PrintWriter pw = getOutPrintWriter();
479         boolean enable = true;
480 
481         String opt;
482         while ((opt = getNextOption()) != null) {
483             switch (opt) {
484                 case "--disable":
485                     enable = false;
486                     break;
487                 case "--enable":
488                     enable = true;
489                     break;
490                 default:
491                     pw.println("Error: Unknown option: " + opt);
492                     return -1;
493             }
494         }
495 
496         String packageName = getNextArg();
497         if (packageName != null) {
498             LocalServices.getService(PackageManagerInternal.class)
499                     .setVisibilityLogging(packageName, enable);
500         } else {
501             getErrPrintWriter().println("Error: no package specified");
502             return -1;
503         }
504         return 1;
505     }
506 
runBypassStagedInstallerCheck()507     private int runBypassStagedInstallerCheck() {
508         final PrintWriter pw = getOutPrintWriter();
509         try {
510             mInterface.getPackageInstaller()
511                     .bypassNextStagedInstallerCheck(Boolean.parseBoolean(getNextArg()));
512             return 0;
513         } catch (RemoteException e) {
514             pw.println("Failure ["
515                     + e.getClass().getName() + " - "
516                     + e.getMessage() + "]");
517             return -1;
518         }
519     }
520 
runBypassAllowedApexUpdateCheck()521     private int runBypassAllowedApexUpdateCheck() {
522         final PrintWriter pw = getOutPrintWriter();
523         try {
524             mInterface.getPackageInstaller()
525                     .bypassNextAllowedApexUpdateCheck(Boolean.parseBoolean(getNextArg()));
526             return 0;
527         } catch (RemoteException e) {
528             pw.println("Failure ["
529                     + e.getClass().getName() + " - "
530                     + e.getMessage() + "]");
531             return -1;
532         }
533     }
534 
runDisableVerificationForUid()535     private int runDisableVerificationForUid() {
536         final PrintWriter pw = getOutPrintWriter();
537         try {
538             int uid = Integer.parseInt(getNextArgRequired());
539             var amInternal = LocalServices.getService(ActivityManagerInternal.class);
540             boolean isInstrumented =
541                     amInternal.getInstrumentationSourceUid(uid) != Process.INVALID_UID;
542             if (isInstrumented) {
543                 mInterface.getPackageInstaller().disableVerificationForUid(uid);
544                 return 0;
545             } else {
546                 // Only available for testing
547                 pw.println("Error: must specify an instrumented uid");
548                 return -1;
549             }
550         } catch (RemoteException e) {
551             pw.println("Failure ["
552                     + e.getClass().getName() + " - "
553                     + e.getMessage() + "]");
554             return -1;
555         }
556     }
557 
uninstallSystemUpdates(String packageName)558     private int uninstallSystemUpdates(String packageName) {
559         final PrintWriter pw = getOutPrintWriter();
560         boolean failedUninstalls = false;
561         try {
562             final IPackageInstaller installer = mInterface.getPackageInstaller();
563             final List<ApplicationInfo> list;
564             if (packageName == null) {
565                 final ParceledListSlice<ApplicationInfo> packages =
566                         mInterface.getInstalledApplications(PackageManager.MATCH_SYSTEM_ONLY
567                                         | PackageManager.MATCH_UNINSTALLED_PACKAGES,
568                                 UserHandle.USER_SYSTEM);
569                 list = packages.getList();
570             } else {
571                 list = new ArrayList<>(1);
572                 list.add(mInterface.getApplicationInfo(packageName, PackageManager.MATCH_SYSTEM_ONLY
573                                 | PackageManager.MATCH_UNINSTALLED_PACKAGES,
574                         UserHandle.USER_SYSTEM));
575             }
576             for (ApplicationInfo info : list) {
577                 if (info.isUpdatedSystemApp()) {
578                     pw.println("Uninstalling updates to " + info.packageName + "...");
579                     final LocalIntentReceiver receiver = new LocalIntentReceiver();
580                     installer.uninstall(new VersionedPackage(info.packageName,
581                                     info.versionCode), null /*callerPackageName*/, 0 /* flags */,
582                             receiver.getIntentSender(), 0);
583 
584                     final Intent result = receiver.getResult();
585                     final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
586                             PackageInstaller.STATUS_FAILURE);
587                     if (status != PackageInstaller.STATUS_SUCCESS) {
588                         failedUninstalls = true;
589                         pw.println("Couldn't uninstall package: " + info.packageName);
590                     }
591                 }
592             }
593         } catch (RemoteException e) {
594             pw.println("Failure ["
595                     + e.getClass().getName() + " - "
596                     + e.getMessage() + "]");
597             return 0;
598         }
599         if (failedUninstalls) {
600             return 0;
601         }
602         pw.println("Success");
603         return 1;
604     }
605 
runRollbackApp()606     private int runRollbackApp() throws RemoteException {
607         final PrintWriter pw = getOutPrintWriter();
608 
609         String opt;
610         long stagedReadyTimeoutMs = DEFAULT_STAGED_READY_TIMEOUT_MS;
611         while ((opt = getNextOption()) != null) {
612             switch (opt) {
613                 case "--staged-ready-timeout":
614                     stagedReadyTimeoutMs = Long.parseLong(getNextArgRequired());
615                     break;
616                 default:
617                     throw new IllegalArgumentException("Unknown option: " + opt);
618             }
619         }
620         final String packageName = getNextArgRequired();
621         if (packageName == null) {
622             pw.println("Error: package name not specified");
623             return 1;
624         }
625 
626         final Context shellPackageContext;
627         try {
628             shellPackageContext = mContext.createPackageContextAsUser(
629                     "com.android.shell", 0, Binder.getCallingUserHandle());
630         } catch (NameNotFoundException e) {
631             // should not happen
632             throw new RuntimeException(e);
633         }
634 
635         final LocalIntentReceiver receiver = new LocalIntentReceiver();
636         RollbackManager rm = shellPackageContext.getSystemService(RollbackManager.class);
637         RollbackInfo rollback = null;
638         for (RollbackInfo r : rm.getAvailableRollbacks()) {
639             for (PackageRollbackInfo info : r.getPackages()) {
640                 if (packageName.equals(info.getPackageName())) {
641                     rollback = r;
642                     break;
643                 }
644             }
645         }
646 
647         if (rollback == null) {
648             pw.println("No available rollbacks for: " + packageName);
649             return 1;
650         }
651 
652         rm.commitRollback(rollback.getRollbackId(),
653                 Collections.emptyList(), receiver.getIntentSender());
654 
655         final Intent result = receiver.getResult();
656         final int status = result.getIntExtra(RollbackManager.EXTRA_STATUS,
657                 RollbackManager.STATUS_FAILURE);
658 
659         if (status != RollbackManager.STATUS_SUCCESS) {
660             pw.println("Failure ["
661                     + result.getStringExtra(RollbackManager.EXTRA_STATUS_MESSAGE) + "]");
662             return 1;
663         }
664 
665         if (rollback.isStaged() && stagedReadyTimeoutMs > 0) {
666             final int committedSessionId = rollback.getCommittedSessionId();
667             return doWaitForStagedSessionReady(committedSessionId, stagedReadyTimeoutMs, pw);
668         }
669 
670         pw.println("Success");
671         return 0;
672 
673     }
674 
setParamsSize(InstallParams params, List<String> inPaths)675     private void setParamsSize(InstallParams params, List<String> inPaths) {
676         if (params.sessionParams.sizeBytes != -1 || STDIN_PATH.equals(inPaths.get(0))) {
677             return;
678         }
679 
680         long sessionSize = 0;
681 
682         ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
683         for (String inPath : inPaths) {
684             final ParcelFileDescriptor fd = openFileForSystem(inPath, "r");
685             if (fd == null) {
686                 getErrPrintWriter().println("Error: Can't open file: " + inPath);
687                 throw new IllegalArgumentException("Error: Can't open file: " + inPath);
688             }
689             try {
690                 ParseResult<ApkLite> apkLiteResult = ApkLiteParseUtils.parseApkLite(
691                         input.reset(), fd.getFileDescriptor(), inPath, 0);
692                 if (apkLiteResult.isError()) {
693                     throw new IllegalArgumentException(
694                             "Error: Failed to parse APK file: " + inPath + ": "
695                                     + apkLiteResult.getErrorMessage(),
696                             apkLiteResult.getException());
697                 }
698                 final ApkLite apkLite = apkLiteResult.getResult();
699                 final PackageLite pkgLite = new PackageLite(null, apkLite.getPath(), apkLite,
700                         null /* splitNames */, null /* isFeatureSplits */,
701                         null /* usesSplitNames */, null /* configForSplit */,
702                         null /* splitApkPaths */, null /* splitRevisionCodes */,
703                         apkLite.getTargetSdkVersion(), null /* requiredSplitTypes */,
704                         null /* splitTypes */);
705                 sessionSize += InstallLocationUtils.calculateInstalledSize(pkgLite,
706                         params.sessionParams.abiOverride, fd.getFileDescriptor());
707             } catch (IOException e) {
708                 getErrPrintWriter().println("Error: Failed to parse APK file: " + inPath);
709                 throw new IllegalArgumentException(
710                         "Error: Failed to parse APK file: " + inPath, e);
711             } finally {
712                 try {
713                     fd.close();
714                 } catch (IOException e) {
715                 }
716             }
717         }
718 
719         params.sessionParams.setSize(sessionSize);
720     }
721     /**
722      * Displays the package file for a package.
723      * @param pckg
724      */
displayPackageFilePath(String pckg, int userId)725     private int displayPackageFilePath(String pckg, int userId) throws RemoteException {
726         PackageInfo info = mInterface.getPackageInfo(pckg, PackageManager.MATCH_APEX, userId);
727         if (info != null && info.applicationInfo != null) {
728             final PrintWriter pw = getOutPrintWriter();
729             pw.print("package:");
730             pw.println(info.applicationInfo.sourceDir);
731             if (!ArrayUtils.isEmpty(info.applicationInfo.splitSourceDirs)) {
732                 for (String splitSourceDir : info.applicationInfo.splitSourceDirs) {
733                     pw.print("package:");
734                     pw.println(splitSourceDir);
735                 }
736             }
737             return 0;
738         }
739         return 1;
740     }
741 
runPath()742     private int runPath() throws RemoteException {
743         int userId = UserHandle.USER_SYSTEM;
744         String option = getNextOption();
745         if (option != null && option.equals("--user")) {
746             userId = UserHandle.parseUserArg(getNextArgRequired());
747         }
748 
749         String pkg = getNextArgRequired();
750         if (pkg == null) {
751             getErrPrintWriter().println("Error: no package specified");
752             return 1;
753         }
754         final int translatedUserId =
755                 translateUserId(userId, UserHandle.USER_NULL, "runPath");
756         return displayPackageFilePath(pkg, translatedUserId);
757     }
758 
runList()759     private int runList() throws RemoteException {
760         final PrintWriter pw = getOutPrintWriter();
761         final String type = getNextArg();
762         if (type == null) {
763             pw.println("Error: didn't specify type of data to list");
764             return -1;
765         }
766         switch(type) {
767             case "features":
768                 return runListFeatures();
769             case "instrumentation":
770                 return runListInstrumentation();
771             case "libraries":
772                 return runListLibraries();
773             case "package":
774             case "packages":
775                 return runListPackages(false /*showSourceDir*/);
776             case "permission-groups":
777                 return runListPermissionGroups();
778             case "permissions":
779                 return runListPermissions();
780             case "staged-sessions":
781                 return runListStagedSessions();
782             case "sdks":
783                 return runListSdks();
784             case "users":
785                 ServiceManager.getService("user").shellCommand(
786                         getInFileDescriptor(), getOutFileDescriptor(), getErrFileDescriptor(),
787                         new String[] { "list" }, getShellCallback(), adoptResultReceiver());
788                 return 0;
789             case "initial-non-stopped-system-packages":
790                 return runListInitialNonStoppedSystemPackages();
791         }
792         pw.println("Error: unknown list type '" + type + "'");
793         return -1;
794     }
795 
runGc()796     private int runGc() throws RemoteException {
797         Runtime.getRuntime().gc();
798         final PrintWriter pw = getOutPrintWriter();
799         pw.println("Ok");
800         return 0;
801     }
802 
runListInitialNonStoppedSystemPackages()803     private int runListInitialNonStoppedSystemPackages() throws RemoteException {
804         final PrintWriter pw = getOutPrintWriter();
805         final List<String> list = mInterface.getInitialNonStoppedSystemPackages();
806 
807         Collections.sort(list);
808 
809         for (String pkgName : list) {
810             pw.print("package:");
811             pw.print(pkgName);
812             pw.println();
813         }
814 
815         return 0;
816     }
817 
runListFeatures()818     private int runListFeatures() throws RemoteException {
819         final PrintWriter pw = getOutPrintWriter();
820         final List<FeatureInfo> list = mInterface.getSystemAvailableFeatures().getList();
821 
822         // sort by name
823         Collections.sort(list, new Comparator<FeatureInfo>() {
824             public int compare(FeatureInfo o1, FeatureInfo o2) {
825                 if (o1.name == o2.name) return 0;
826                 if (o1.name == null) return -1;
827                 if (o2.name == null) return 1;
828                 return o1.name.compareTo(o2.name);
829             }
830         });
831 
832         final int count = (list != null) ? list.size() : 0;
833         for (int p = 0; p < count; p++) {
834             FeatureInfo fi = list.get(p);
835             pw.print("feature:");
836             if (fi.name != null) {
837                 pw.print(fi.name);
838                 if (fi.version > 0) {
839                     pw.print("=");
840                     pw.print(fi.version);
841                 }
842                 pw.println();
843             } else {
844                 pw.println("reqGlEsVersion=0x"
845                         + Integer.toHexString(fi.reqGlEsVersion));
846             }
847         }
848         return 0;
849     }
850 
runListInstrumentation()851     private int runListInstrumentation() throws RemoteException {
852         final PrintWriter pw = getOutPrintWriter();
853         boolean showSourceDir = false;
854         String targetPackage = null;
855 
856         try {
857             String opt;
858             while ((opt = getNextArg()) != null) {
859                 switch (opt) {
860                     case "-f":
861                         showSourceDir = true;
862                         break;
863                     default:
864                         if (opt.charAt(0) != '-') {
865                             targetPackage = opt;
866                         } else {
867                             pw.println("Error: Unknown option: " + opt);
868                             return -1;
869                         }
870                         break;
871                 }
872             }
873         } catch (RuntimeException ex) {
874             pw.println("Error: " + ex.toString());
875             return -1;
876         }
877 
878         final List<InstrumentationInfo> list =
879                 mInterface.queryInstrumentationAsUser(
880                         targetPackage, PackageManager.MATCH_KNOWN_PACKAGES, UserHandle.USER_SYSTEM)
881                         .getList();
882 
883         // sort by target package
884         Collections.sort(list, new Comparator<InstrumentationInfo>() {
885             public int compare(InstrumentationInfo o1, InstrumentationInfo o2) {
886                 return o1.targetPackage.compareTo(o2.targetPackage);
887             }
888         });
889 
890         final int count = (list != null) ? list.size() : 0;
891         for (int p = 0; p < count; p++) {
892             final InstrumentationInfo ii = list.get(p);
893             pw.print("instrumentation:");
894             if (showSourceDir) {
895                 pw.print(ii.sourceDir);
896                 pw.print("=");
897             }
898             final ComponentName cn = new ComponentName(ii.packageName, ii.name);
899             pw.print(cn.flattenToShortString());
900             pw.print(" (target=");
901             pw.print(ii.targetPackage);
902             pw.println(")");
903         }
904         return 0;
905     }
906 
runListLibraries()907     private int runListLibraries() throws RemoteException {
908         final PrintWriter pw = getOutPrintWriter();
909         boolean verbose = false;
910         String opt;
911         while ((opt = getNextArg()) != null) {
912             switch (opt) {
913                 case "-v":
914                     verbose = true;
915                     break;
916                 default:
917                     pw.println("Error: Unknown option: " + opt);
918                     return -1;
919             }
920         }
921 
922         final Map<String, String> namesAndPaths = mInterface.getSystemSharedLibraryNamesAndPaths();
923         if (namesAndPaths.isEmpty()) {
924             return 0;
925         }
926 
927         // sort by name
928         final List<String> libs = new ArrayList<>(namesAndPaths.keySet());
929         Collections.sort(libs, (o1, o2) -> {
930                 if (o1 == o2) return 0;
931                 if (o1 == null) return -1;
932                 if (o2 == null) return 1;
933                 return o1.compareTo(o2);
934         });
935 
936         for (int i = 0; i < libs.size(); i++) {
937             String lib = libs.get(i);
938             pw.print("library:");
939             pw.print(lib);
940             if (verbose) {
941                 pw.print(" path:");
942                 pw.print(namesAndPaths.get(lib));
943             }
944             pw.println();
945         }
946         return 0;
947     }
948 
runListPackages(boolean showSourceDir)949     private int runListPackages(boolean showSourceDir) throws RemoteException {
950         return runListPackages(showSourceDir, false);
951     }
952 
runListSdks()953     private int runListSdks() throws RemoteException {
954         return runListPackages(false, true);
955     }
956 
runListPackages(boolean showSourceDir, boolean showSdks)957     private int runListPackages(boolean showSourceDir, boolean showSdks) throws RemoteException {
958         final String prefix = showSdks ? "sdk:" : "package:";
959         final PrintWriter pw = getOutPrintWriter();
960         int getFlags = 0;
961         boolean listDisabled = false, listEnabled = false;
962         boolean listSystem = false, listThirdParty = false;
963         boolean listInstaller = false;
964         boolean showUid = false;
965         boolean showVersionCode = false;
966         boolean listQuarantinedOnly = false;
967         boolean listApexOnly = false;
968         boolean showStopped = false;
969         int uid = -1;
970         int defaultUserId = UserHandle.USER_ALL;
971         try {
972             String opt;
973             while ((opt = getNextOption()) != null) {
974                 switch (opt) {
975                     case "-d":
976                         listDisabled = true;
977                         break;
978                     case "-e":
979                         listEnabled = true;
980                         break;
981                     case "-a":
982                         getFlags |= PackageManager.MATCH_KNOWN_PACKAGES;
983                         getFlags |= PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS;
984                         break;
985                     case "-f":
986                         showSourceDir = true;
987                         break;
988                     case "-i":
989                         listInstaller = true;
990                         break;
991                     case "-l":
992                         // old compat
993                         break;
994                     case "-s":
995                         listSystem = true;
996                         break;
997                     case "-q":
998                         listQuarantinedOnly = true;
999                         break;
1000                     case "-U":
1001                         showUid = true;
1002                         break;
1003                     case "-u":
1004                         getFlags |= PackageManager.MATCH_UNINSTALLED_PACKAGES;
1005                         break;
1006                     case "-3":
1007                         listThirdParty = true;
1008                         break;
1009                     case "--show-versioncode":
1010                         showVersionCode = true;
1011                         break;
1012                     case "--apex-only":
1013                         getFlags |= PackageManager.MATCH_APEX;
1014                         listApexOnly = true;
1015                         break;
1016                     case "--factory-only":
1017                         getFlags |= PackageManager.MATCH_FACTORY_ONLY;
1018                         break;
1019                     case "--user":
1020                         defaultUserId = UserHandle.parseUserArg(getNextArgRequired());
1021                         break;
1022                     case "--uid":
1023                         showUid = true;
1024                         uid = Integer.parseInt(getNextArgRequired());
1025                         break;
1026                     case "--match-libraries":
1027                         getFlags |= PackageManager.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES;
1028                         break;
1029                     case "--show-stopped":
1030                         showStopped = true;
1031                         break;
1032                     default:
1033                         pw.println("Error: Unknown option: " + opt);
1034                         return -1;
1035                 }
1036             }
1037         } catch (RuntimeException ex) {
1038             pw.println("Error: " + ex.toString());
1039             return -1;
1040         }
1041 
1042         final String filter = getNextArg();
1043 
1044         int[] userIds = {defaultUserId};
1045         if (defaultUserId == UserHandle.USER_ALL) {
1046             final UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class);
1047             userIds = umi.getUserIds();
1048         }
1049         if (showSdks) {
1050             getFlags |= PackageManager.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES;
1051         }
1052 
1053         // Build a map of packages to a list of corresponding uids. Keys are strings containing
1054         // the sdk or package name along with optional additional information based on opt.
1055         final Map<String, List<String>> out = new HashMap<>();
1056         for (int userId : userIds) {
1057             final int translatedUserId;
1058             try {
1059                 translatedUserId =
1060                     translateUserId(userId, UserHandle.USER_SYSTEM, "runListPackages");
1061             } catch (RuntimeException ex) {
1062                 getErrPrintWriter().println("Error: " + ex.toString());
1063                 continue;
1064             }
1065             @SuppressWarnings("unchecked") final ParceledListSlice<PackageInfo> slice =
1066                     mInterface.getInstalledPackages(getFlags, translatedUserId);
1067             final List<PackageInfo> packages = slice.getList();
1068 
1069             final int count = packages.size();
1070             for (int p = 0; p < count; p++) {
1071                 final PackageInfo info = packages.get(p);
1072                 final StringBuilder stringBuilder = new StringBuilder();
1073                 if (filter != null && !info.packageName.contains(filter)) {
1074                     continue;
1075                 }
1076                 final boolean isApex = info.isApex;
1077                 if (uid != -1 && !isApex && info.applicationInfo.uid != uid) {
1078                     continue;
1079                 }
1080 
1081                 final boolean isSystem = !isApex
1082                         && (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
1083                 final boolean isEnabled = !isApex && info.applicationInfo.enabled;
1084                 if ((listDisabled && isEnabled)
1085                         || (listEnabled && !isEnabled)
1086                         || (listSystem && !isSystem)
1087                         || (listThirdParty && isSystem)
1088                         || (listApexOnly && !isApex)) {
1089                     continue;
1090                 }
1091                 if (listQuarantinedOnly && !mInterface.isPackageQuarantinedForUser(info.packageName,
1092                         translatedUserId)) {
1093                     continue;
1094                 }
1095 
1096                 String name = null;
1097                 if (showSdks) {
1098                     final ParceledListSlice<SharedLibraryInfo> libsSlice =
1099                             mInterface.getDeclaredSharedLibraries(
1100                                 info.packageName, getFlags, userId
1101                             );
1102                     if (libsSlice == null) {
1103                         continue;
1104                     }
1105                     final List<SharedLibraryInfo> libs = libsSlice.getList();
1106                     for (int l = 0, lsize = libs.size(); l < lsize; ++l) {
1107                         SharedLibraryInfo lib = libs.get(l);
1108                         if (lib.getType() == SharedLibraryInfo.TYPE_SDK_PACKAGE) {
1109                             name = lib.getName() + ":" + lib.getLongVersion();
1110                             break;
1111                         }
1112                     }
1113                     if (name == null) {
1114                         continue;
1115                     }
1116                 } else {
1117                     name = info.packageName;
1118                 }
1119 
1120                 stringBuilder.append(prefix);
1121                 if (showSourceDir) {
1122                     stringBuilder.append(info.applicationInfo.sourceDir);
1123                     stringBuilder.append("=");
1124                 }
1125                 stringBuilder.append(name);
1126                 if (showVersionCode) {
1127                     stringBuilder.append(" versionCode:");
1128                     if (info.applicationInfo != null) {
1129                         stringBuilder.append(info.applicationInfo.longVersionCode);
1130                     } else {
1131                         stringBuilder.append(info.getLongVersionCode());
1132                     }
1133                 }
1134                 if (showStopped) {
1135                     stringBuilder.append(" stopped=");
1136                     stringBuilder.append(
1137                             ((info.applicationInfo.flags & ApplicationInfo.FLAG_STOPPED) != 0)
1138                             ? "true" : "false");
1139                 }
1140                 if (listInstaller) {
1141                     stringBuilder.append("  installer=");
1142                     stringBuilder.append(mInterface.getInstallerPackageName(info.packageName));
1143                 }
1144                 List<String> uids = out.computeIfAbsent(
1145                         stringBuilder.toString(), k -> new ArrayList<>()
1146                 );
1147                 if (showUid && !isApex) {
1148                     uids.add(String.valueOf(info.applicationInfo.uid));
1149                 }
1150             }
1151         }
1152         for (Map.Entry<String, List<String>> entry : out.entrySet()) {
1153             pw.print(entry.getKey());
1154             List<String> uids = entry.getValue();
1155             if (!uids.isEmpty()) {
1156                 pw.print(" uid:");
1157                 pw.print(String.join(",", uids));
1158             }
1159             pw.println();
1160         }
1161         return 0;
1162     }
1163 
runListPermissionGroups()1164     private int runListPermissionGroups() throws RemoteException {
1165         final PrintWriter pw = getOutPrintWriter();
1166         final List<PermissionGroupInfo> pgs = mPermissionManager.getAllPermissionGroups(0);
1167 
1168         final int count = pgs.size();
1169         for (int p = 0; p < count ; p++) {
1170             final PermissionGroupInfo pgi = pgs.get(p);
1171             pw.print("permission group:");
1172             pw.println(pgi.name);
1173         }
1174         return 0;
1175     }
1176 
runListPermissions()1177     private int runListPermissions() throws RemoteException {
1178         final PrintWriter pw = getOutPrintWriter();
1179         boolean labels = false;
1180         boolean groups = false;
1181         boolean userOnly = false;
1182         boolean summary = false;
1183         boolean dangerousOnly = false;
1184         String opt;
1185         while ((opt = getNextOption()) != null) {
1186             switch (opt) {
1187                 case "-d":
1188                     dangerousOnly = true;
1189                     break;
1190                 case "-f":
1191                     labels = true;
1192                     break;
1193                 case "-g":
1194                     groups = true;
1195                     break;
1196                 case "-s":
1197                     groups = true;
1198                     labels = true;
1199                     summary = true;
1200                     break;
1201                 case "-u":
1202                     userOnly = true;
1203                     break;
1204                 default:
1205                     pw.println("Error: Unknown option: " + opt);
1206                     return 1;
1207             }
1208         }
1209 
1210         final ArrayList<String> groupList = new ArrayList<String>();
1211         if (groups) {
1212             final List<PermissionGroupInfo> infos =
1213                     mPermissionManager.getAllPermissionGroups(0 /*flags*/);
1214             final int count = infos.size();
1215             for (int i = 0; i < count; i++) {
1216                 groupList.add(infos.get(i).name);
1217             }
1218             groupList.add(null);
1219         } else {
1220             final String grp = getNextArg();
1221             groupList.add(grp);
1222         }
1223 
1224         if (dangerousOnly) {
1225             pw.println("Dangerous Permissions:");
1226             pw.println("");
1227             doListPermissions(groupList, groups, labels, summary,
1228                     PermissionInfo.PROTECTION_DANGEROUS,
1229                     PermissionInfo.PROTECTION_DANGEROUS);
1230             if (userOnly) {
1231                 pw.println("Normal Permissions:");
1232                 pw.println("");
1233                 doListPermissions(groupList, groups, labels, summary,
1234                         PermissionInfo.PROTECTION_NORMAL,
1235                         PermissionInfo.PROTECTION_NORMAL);
1236             }
1237         } else if (userOnly) {
1238             pw.println("Dangerous and Normal Permissions:");
1239             pw.println("");
1240             doListPermissions(groupList, groups, labels, summary,
1241                     PermissionInfo.PROTECTION_NORMAL,
1242                     PermissionInfo.PROTECTION_DANGEROUS);
1243         } else {
1244             pw.println("All Permissions:");
1245             pw.println("");
1246             doListPermissions(groupList, groups, labels, summary,
1247                     -10000, 10000);
1248         }
1249         return 0;
1250     }
1251 
1252     private static class SessionDump {
1253         boolean onlyParent; // Show parent sessions only
1254         boolean onlyReady; // Show only staged sessions that are in ready state
1255         boolean onlySessionId; // Show sessionId only
1256     }
1257 
1258     // Returns true if the provided flag is a session flag and given SessionDump was updated
setSessionFlag(String flag, SessionDump sessionDump)1259     private boolean setSessionFlag(String flag, SessionDump sessionDump) {
1260         switch (flag) {
1261             case "--only-parent":
1262                 sessionDump.onlyParent = true;
1263                 break;
1264             case "--only-ready":
1265                 sessionDump.onlyReady = true;
1266                 break;
1267             case "--only-sessionid":
1268                 sessionDump.onlySessionId = true;
1269                 break;
1270             default:
1271                 return false;
1272         }
1273         return true;
1274     }
1275 
runListStagedSessions()1276     private int runListStagedSessions() {
1277         try (IndentingPrintWriter pw = new IndentingPrintWriter(
1278                 getOutPrintWriter(), /* singleIndent */ "  ", /* wrapLength */ 120)) {
1279             final SessionDump sessionDump = new SessionDump();
1280             String opt;
1281             while ((opt = getNextOption()) != null) {
1282                 if (!setSessionFlag(opt, sessionDump)) {
1283                     pw.println("Error: Unknown option: " + opt);
1284                     return -1;
1285                 }
1286             }
1287 
1288             try {
1289                 final List<SessionInfo> stagedSessions =
1290                         mInterface.getPackageInstaller().getStagedSessions().getList();
1291                 printSessionList(pw, stagedSessions, sessionDump);
1292             } catch (RemoteException e) {
1293                 pw.println("Failure ["
1294                         + e.getClass().getName() + " - "
1295                         + e.getMessage() + "]");
1296                 return -1;
1297             }
1298             return 1;
1299         }
1300     }
1301 
printSessionList(IndentingPrintWriter pw, List<SessionInfo> stagedSessions, SessionDump sessionDump)1302     private void printSessionList(IndentingPrintWriter pw, List<SessionInfo> stagedSessions,
1303             SessionDump sessionDump) {
1304         final SparseArray<SessionInfo> sessionById = new SparseArray<>(stagedSessions.size());
1305         for (SessionInfo session : stagedSessions) {
1306             sessionById.put(session.getSessionId(), session);
1307         }
1308         for (SessionInfo session: stagedSessions) {
1309             if (sessionDump.onlyReady && !session.isStagedSessionReady()) {
1310                 continue;
1311             }
1312             if (session.getParentSessionId() != SessionInfo.INVALID_ID) {
1313                 continue;
1314             }
1315             printSession(pw, session, sessionDump);
1316             if (session.isMultiPackage() && !sessionDump.onlyParent) {
1317                 pw.increaseIndent();
1318                 final int[] childIds = session.getChildSessionIds();
1319                 for (int i = 0; i < childIds.length; i++) {
1320                     final SessionInfo childSession = sessionById.get(childIds[i]);
1321                     if (childSession == null) {
1322                         if (sessionDump.onlySessionId) {
1323                             pw.println(childIds[i]);
1324                         } else {
1325                             pw.println("sessionId = " + childIds[i] + "; not found");
1326                         }
1327                     } else {
1328                         printSession(pw, childSession, sessionDump);
1329                     }
1330                 }
1331                 pw.decreaseIndent();
1332             }
1333         }
1334     }
1335 
printSession(PrintWriter pw, SessionInfo session, SessionDump sessionDump)1336     private static void printSession(PrintWriter pw, SessionInfo session, SessionDump sessionDump) {
1337         if (sessionDump.onlySessionId) {
1338             pw.println(session.getSessionId());
1339             return;
1340         }
1341         pw.println("sessionId = " + session.getSessionId()
1342                 + "; appPackageName = " + session.getAppPackageName()
1343                 + "; isStaged = " + session.isStaged()
1344                 + "; isReady = " + session.isStagedSessionReady()
1345                 + "; isApplied = " + session.isStagedSessionApplied()
1346                 + "; isFailed = " + session.isStagedSessionFailed()
1347                 + "; errorMsg = " + session.getStagedSessionErrorMessage()
1348                 + ";");
1349     }
1350 
parseIntentAndUser()1351     private Intent parseIntentAndUser() throws URISyntaxException {
1352         mTargetUser = UserHandle.USER_CURRENT;
1353         mBrief = false;
1354         mComponents = false;
1355         Intent intent = Intent.parseCommandArgs(this, new Intent.CommandOptionHandler() {
1356             @Override
1357             public boolean handleOption(String opt, ShellCommand cmd) {
1358                 if ("--user".equals(opt)) {
1359                     mTargetUser = UserHandle.parseUserArg(cmd.getNextArgRequired());
1360                     return true;
1361                 } else if ("--brief".equals(opt)) {
1362                     mBrief = true;
1363                     return true;
1364                 } else if ("--components".equals(opt)) {
1365                     mComponents = true;
1366                     return true;
1367                 } else if ("--query-flags".equals(opt)) {
1368                     mQueryFlags = Integer.decode(cmd.getNextArgRequired());
1369                     return true;
1370                 }
1371                 return false;
1372             }
1373         });
1374         mTargetUser = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1375                 Binder.getCallingUid(), mTargetUser, false, false, null, null);
1376         return intent;
1377     }
1378 
printResolveInfo(PrintWriterPrinter pr, String prefix, ResolveInfo ri, boolean brief, boolean components)1379     private void printResolveInfo(PrintWriterPrinter pr, String prefix, ResolveInfo ri,
1380             boolean brief, boolean components) {
1381         if (brief || components) {
1382             final ComponentName comp;
1383             if (ri.activityInfo != null) {
1384                 comp = new ComponentName(ri.activityInfo.packageName, ri.activityInfo.name);
1385             } else if (ri.serviceInfo != null) {
1386                 comp = new ComponentName(ri.serviceInfo.packageName, ri.serviceInfo.name);
1387             } else if (ri.providerInfo != null) {
1388                 comp = new ComponentName(ri.providerInfo.packageName, ri.providerInfo.name);
1389             } else {
1390                 comp = null;
1391             }
1392             if (comp != null) {
1393                 if (!components) {
1394                     pr.println(prefix + "priority=" + ri.priority
1395                             + " preferredOrder=" + ri.preferredOrder
1396                             + " match=0x" + Integer.toHexString(ri.match)
1397                             + " specificIndex=" + ri.specificIndex
1398                             + " isDefault=" + ri.isDefault);
1399                 }
1400                 pr.println(prefix + comp.flattenToShortString());
1401                 return;
1402             }
1403         }
1404         ri.dump(pr, prefix);
1405     }
1406 
runResolveActivity()1407     private int runResolveActivity() {
1408         Intent intent;
1409         try {
1410             intent = parseIntentAndUser();
1411         } catch (URISyntaxException e) {
1412             throw new RuntimeException(e.getMessage(), e);
1413         }
1414         try {
1415             ResolveInfo ri = mInterface.resolveIntent(intent, intent.getType(), mQueryFlags,
1416                     mTargetUser);
1417             PrintWriter pw = getOutPrintWriter();
1418             if (ri == null) {
1419                 pw.println("No activity found");
1420             } else {
1421                 PrintWriterPrinter pr = new PrintWriterPrinter(pw);
1422                 printResolveInfo(pr, "", ri, mBrief, mComponents);
1423             }
1424         } catch (RemoteException e) {
1425             throw new RuntimeException("Failed calling service", e);
1426         }
1427         return 0;
1428     }
1429 
runQueryIntentActivities()1430     private int runQueryIntentActivities() {
1431         Intent intent;
1432         try {
1433             intent = parseIntentAndUser();
1434         } catch (URISyntaxException e) {
1435             throw new RuntimeException(e.getMessage(), e);
1436         }
1437         try {
1438             List<ResolveInfo> result = mInterface.queryIntentActivities(intent, intent.getType(),
1439                     mQueryFlags, mTargetUser).getList();
1440             PrintWriter pw = getOutPrintWriter();
1441             if (result == null || result.size() <= 0) {
1442                 pw.println("No activities found");
1443             } else {
1444                 if (!mComponents) {
1445                     pw.print(result.size()); pw.println(" activities found:");
1446                     PrintWriterPrinter pr = new PrintWriterPrinter(pw);
1447                     for (int i = 0; i < result.size(); i++) {
1448                         pw.print("  Activity #"); pw.print(i); pw.println(":");
1449                         printResolveInfo(pr, "    ", result.get(i), mBrief, mComponents);
1450                     }
1451                 } else {
1452                     PrintWriterPrinter pr = new PrintWriterPrinter(pw);
1453                     for (int i = 0; i < result.size(); i++) {
1454                         printResolveInfo(pr, "", result.get(i), mBrief, mComponents);
1455                     }
1456                 }
1457             }
1458         } catch (RemoteException e) {
1459             throw new RuntimeException("Failed calling service", e);
1460         }
1461         return 0;
1462     }
1463 
runQueryIntentServices()1464     private int runQueryIntentServices() {
1465         Intent intent;
1466         try {
1467             intent = parseIntentAndUser();
1468         } catch (URISyntaxException e) {
1469             throw new RuntimeException(e.getMessage(), e);
1470         }
1471         try {
1472             List<ResolveInfo> result = mInterface.queryIntentServices(intent, intent.getType(),
1473                     mQueryFlags, mTargetUser).getList();
1474             PrintWriter pw = getOutPrintWriter();
1475             if (result == null || result.size() <= 0) {
1476                 pw.println("No services found");
1477             } else {
1478                 if (!mComponents) {
1479                     pw.print(result.size()); pw.println(" services found:");
1480                     PrintWriterPrinter pr = new PrintWriterPrinter(pw);
1481                     for (int i = 0; i < result.size(); i++) {
1482                         pw.print("  Service #"); pw.print(i); pw.println(":");
1483                         printResolveInfo(pr, "    ", result.get(i), mBrief, mComponents);
1484                     }
1485                 } else {
1486                     PrintWriterPrinter pr = new PrintWriterPrinter(pw);
1487                     for (int i = 0; i < result.size(); i++) {
1488                         printResolveInfo(pr, "", result.get(i), mBrief, mComponents);
1489                     }
1490                 }
1491             }
1492         } catch (RemoteException e) {
1493             throw new RuntimeException("Failed calling service", e);
1494         }
1495         return 0;
1496     }
1497 
runQueryIntentReceivers()1498     private int runQueryIntentReceivers() {
1499         Intent intent;
1500         try {
1501             intent = parseIntentAndUser();
1502         } catch (URISyntaxException e) {
1503             throw new RuntimeException(e.getMessage(), e);
1504         }
1505         try {
1506             List<ResolveInfo> result = mInterface.queryIntentReceivers(intent, intent.getType(),
1507                     mQueryFlags, mTargetUser).getList();
1508             PrintWriter pw = getOutPrintWriter();
1509             if (result == null || result.size() <= 0) {
1510                 pw.println("No receivers found");
1511             } else {
1512                 if (!mComponents) {
1513                     pw.print(result.size()); pw.println(" receivers found:");
1514                     PrintWriterPrinter pr = new PrintWriterPrinter(pw);
1515                     for (int i = 0; i < result.size(); i++) {
1516                         pw.print("  Receiver #"); pw.print(i); pw.println(":");
1517                         printResolveInfo(pr, "    ", result.get(i), mBrief, mComponents);
1518                     }
1519                 } else {
1520                     PrintWriterPrinter pr = new PrintWriterPrinter(pw);
1521                     for (int i = 0; i < result.size(); i++) {
1522                         printResolveInfo(pr, "", result.get(i), mBrief, mComponents);
1523                     }
1524                 }
1525             }
1526         } catch (RemoteException e) {
1527             throw new RuntimeException("Failed calling service", e);
1528         }
1529         return 0;
1530     }
1531 
runStreamingInstall()1532     private int runStreamingInstall() throws RemoteException {
1533         final InstallParams params = makeInstallParams(UNSUPPORTED_INSTALL_CMD_OPTS);
1534         if (params.sessionParams.dataLoaderParams == null) {
1535             params.sessionParams.setDataLoaderParams(
1536                     PackageManagerShellCommandDataLoader.getStreamingDataLoaderParams(this));
1537         }
1538         return doRunInstall(params);
1539     }
1540 
runArchivedInstall()1541     private int runArchivedInstall() throws RemoteException {
1542         final InstallParams params = makeInstallParams(UNSUPPORTED_INSTALL_CMD_OPTS);
1543         params.sessionParams.installFlags |= PackageManager.INSTALL_ARCHIVED;
1544         if (params.sessionParams.dataLoaderParams == null) {
1545             params.sessionParams.setDataLoaderParams(
1546                     PackageManagerShellCommandDataLoader.getStreamingDataLoaderParams(this));
1547         }
1548         return doRunInstall(params);
1549     }
1550 
runIncrementalInstall()1551     private int runIncrementalInstall() throws RemoteException {
1552         final InstallParams params = makeInstallParams(UNSUPPORTED_INSTALL_CMD_OPTS);
1553         if (params.sessionParams.dataLoaderParams == null) {
1554             params.sessionParams.setDataLoaderParams(
1555                     PackageManagerShellCommandDataLoader.getIncrementalDataLoaderParams(this));
1556         }
1557         return doRunInstall(params);
1558     }
1559 
runInstall()1560     private int runInstall() throws RemoteException {
1561         return doRunInstall(makeInstallParams(UNSUPPORTED_INSTALL_CMD_OPTS));
1562     }
1563 
doRunInstall(final InstallParams params)1564     private int doRunInstall(final InstallParams params) throws RemoteException {
1565         final PrintWriter pw = getOutPrintWriter();
1566 
1567         int requestUserId = params.userId;
1568         if (requestUserId != UserHandle.USER_ALL && requestUserId != UserHandle.USER_CURRENT) {
1569             UserManagerInternal umi =
1570                     LocalServices.getService(UserManagerInternal.class);
1571             UserInfo userInfo = umi.getUserInfo(requestUserId);
1572             if (userInfo == null) {
1573                 pw.println("Failure [user " + requestUserId + " doesn't exist]");
1574                 return 1;
1575             }
1576         }
1577 
1578         final boolean isStreaming = params.sessionParams.dataLoaderParams != null;
1579         final boolean isApex =
1580                 (params.sessionParams.installFlags & PackageManager.INSTALL_APEX) != 0;
1581         final boolean installArchived =
1582                 (params.sessionParams.installFlags & PackageManager.INSTALL_ARCHIVED) != 0;
1583 
1584         ArrayList<String> args = getRemainingArgs();
1585 
1586         final boolean fromStdIn = args.isEmpty() || STDIN_PATH.equals(args.get(0));
1587         final boolean hasSplits = args.size() > 1;
1588 
1589         if (fromStdIn && params.sessionParams.sizeBytes == -1) {
1590             pw.println("Error: must either specify a package size or an APK file");
1591             return 1;
1592         }
1593 
1594         if (isApex && hasSplits) {
1595             pw.println("Error: can't specify SPLIT(s) for APEX");
1596             return 1;
1597         }
1598 
1599         if (installArchived) {
1600             if (hasSplits) {
1601                 pw.println("Error: can't have SPLIT(s) for Archival install");
1602                 return 1;
1603             }
1604         }
1605 
1606         if (!isStreaming) {
1607             if (fromStdIn && hasSplits) {
1608                 pw.println("Error: can't specify SPLIT(s) along with STDIN");
1609                 return 1;
1610             }
1611 
1612             if (args.isEmpty()) {
1613                 args.add(STDIN_PATH);
1614             } else {
1615                 setParamsSize(params, args);
1616             }
1617         }
1618 
1619         final int sessionId = doCreateSession(params.sessionParams,
1620                 params.installerPackageName, params.userId);
1621         boolean abandonSession = true;
1622         try {
1623             if (isStreaming) {
1624                 if (doAddFiles(sessionId, args, params.sessionParams.sizeBytes, isApex,
1625                         installArchived) != PackageInstaller.STATUS_SUCCESS) {
1626                     return 1;
1627                 }
1628             } else {
1629                 if (doWriteSplits(sessionId, args, params.sessionParams.sizeBytes, isApex)
1630                         != PackageInstaller.STATUS_SUCCESS) {
1631                     return 1;
1632                 }
1633             }
1634             if (doCommitSession(sessionId, false /*logSuccess*/)
1635                     != PackageInstaller.STATUS_SUCCESS) {
1636                 return 1;
1637             }
1638             abandonSession = false;
1639 
1640             if (params.sessionParams.isStaged && params.stagedReadyTimeoutMs > 0) {
1641                 return doWaitForStagedSessionReady(sessionId, params.stagedReadyTimeoutMs, pw);
1642             }
1643 
1644             pw.println("Success");
1645             return 0;
1646         } finally {
1647             if (abandonSession) {
1648                 try {
1649                     doAbandonSession(sessionId, false /*logSuccess*/);
1650                 } catch (Exception ignore) {
1651                 }
1652             }
1653         }
1654     }
1655 
doWaitForStagedSessionReady(int sessionId, long timeoutMs, PrintWriter pw)1656     private int doWaitForStagedSessionReady(int sessionId, long timeoutMs, PrintWriter pw)
1657               throws RemoteException {
1658         Preconditions.checkArgument(timeoutMs > 0);
1659         PackageInstaller.SessionInfo si = mInterface.getPackageInstaller()
1660                 .getSessionInfo(sessionId);
1661         if (si == null) {
1662             pw.println("Failure [Unknown session " + sessionId + "]");
1663             return 1;
1664         }
1665         if (!si.isStaged()) {
1666             pw.println("Failure [Session " + sessionId + " is not a staged session]");
1667             return 1;
1668         }
1669         long currentTime = System.currentTimeMillis();
1670         long endTime = currentTime + timeoutMs;
1671         // Using a loop instead of BroadcastReceiver since we can receive session update
1672         // broadcast only if packageInstallerName is "android". We can't always force
1673         // "android" as packageIntallerName, e.g, rollback auto implies
1674         // "-i com.android.shell".
1675         while (si != null && currentTime < endTime) {
1676             if (si.isStagedSessionReady() || si.isStagedSessionFailed()) {
1677                 break;
1678             }
1679             SystemClock.sleep(Math.min(endTime - currentTime, 100));
1680             currentTime = System.currentTimeMillis();
1681             si = mInterface.getPackageInstaller().getSessionInfo(sessionId);
1682         }
1683         if (si == null) {
1684             pw.println("Failure [failed to retrieve SessionInfo]");
1685             return 1;
1686         }
1687         if (!si.isStagedSessionReady() && !si.isStagedSessionFailed()) {
1688             pw.println("Failure [timed out after " + timeoutMs + " ms]");
1689             return 1;
1690         }
1691         if (!si.isStagedSessionReady()) {
1692             pw.println("Error [" + si.getStagedSessionErrorCode() + "] ["
1693                     + si.getStagedSessionErrorMessage() + "]");
1694             return 1;
1695         }
1696         pw.println("Success. Reboot device to apply staged session");
1697         return 0;
1698     }
1699 
runInstallAbandon()1700     private int runInstallAbandon() throws RemoteException {
1701         final int sessionId = Integer.parseInt(getNextArg());
1702         return doAbandonSession(sessionId, true /*logSuccess*/);
1703     }
1704 
runInstallCommit()1705     private int runInstallCommit() throws RemoteException {
1706         final PrintWriter pw = getOutPrintWriter();
1707         String opt;
1708         long stagedReadyTimeoutMs = DEFAULT_STAGED_READY_TIMEOUT_MS;
1709         while ((opt = getNextOption()) != null) {
1710             switch (opt) {
1711                 case "--staged-ready-timeout":
1712                     stagedReadyTimeoutMs = Long.parseLong(getNextArgRequired());
1713                     break;
1714                 default:
1715                     throw new IllegalArgumentException("Unknown option: " + opt);
1716             }
1717         }
1718         final int sessionId = Integer.parseInt(getNextArg());
1719         if (doCommitSession(sessionId, false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {
1720             return 1;
1721         }
1722         final PackageInstaller.SessionInfo si = mInterface.getPackageInstaller()
1723                 .getSessionInfo(sessionId);
1724         if (si != null && si.isStaged() && stagedReadyTimeoutMs > 0) {
1725             return doWaitForStagedSessionReady(sessionId, stagedReadyTimeoutMs, pw);
1726         }
1727         pw.println("Success");
1728         return 0;
1729     }
1730 
runInstallCreate()1731     private int runInstallCreate() throws RemoteException {
1732         final PrintWriter pw = getOutPrintWriter();
1733         final InstallParams installParams = makeInstallParams(UNSUPPORTED_SESSION_CREATE_OPTS);
1734         final int sessionId = doCreateSession(installParams.sessionParams,
1735                 installParams.installerPackageName, installParams.userId);
1736 
1737         // NOTE: adb depends on parsing this string
1738         pw.println("Success: created install session [" + sessionId + "]");
1739         return 0;
1740     }
1741 
runInstallWrite()1742     private int runInstallWrite() throws RemoteException {
1743         long sizeBytes = -1;
1744 
1745         String opt;
1746         while ((opt = getNextOption()) != null) {
1747             if (opt.equals("-S")) {
1748                 sizeBytes = Long.parseLong(getNextArg());
1749             } else {
1750                 throw new IllegalArgumentException("Unknown option: " + opt);
1751             }
1752         }
1753 
1754         final int sessionId = Integer.parseInt(getNextArg());
1755         final String splitName = getNextArg();
1756         final String path = getNextArg();
1757         return doWriteSplit(sessionId, path, sizeBytes, splitName, true /*logSuccess*/);
1758     }
1759 
runInstallAddSession()1760     private int runInstallAddSession() throws RemoteException {
1761         final PrintWriter pw = getOutPrintWriter();
1762         final int parentSessionId = Integer.parseInt(getNextArg());
1763 
1764         IntArray otherSessionIds = new IntArray();
1765         String opt;
1766         while ((opt = getNextArg()) != null) {
1767             otherSessionIds.add(Integer.parseInt(opt));
1768         }
1769         if (otherSessionIds.size() == 0) {
1770             pw.println("Error: At least two sessions are required.");
1771             return 1;
1772         }
1773         return doInstallAddSession(parentSessionId, otherSessionIds.toArray(),
1774                 true /*logSuccess*/);
1775     }
1776 
runInstallSetPreVerifiedDomains()1777     private int runInstallSetPreVerifiedDomains() throws RemoteException {
1778         final PrintWriter pw = getOutPrintWriter();
1779         final int sessionId = Integer.parseInt(getNextArg());
1780         final String preVerifiedDomainsStr = getNextArg();
1781         final String[] preVerifiedDomains = preVerifiedDomainsStr.split(",");
1782         PackageInstaller.Session session = null;
1783         try {
1784             session = new PackageInstaller.Session(
1785                     mInterface.getPackageInstaller().openSession(sessionId));
1786             session.setPreVerifiedDomains(new ArraySet<>(preVerifiedDomains));
1787         } finally {
1788             IoUtils.closeQuietly(session);
1789         }
1790         return 0;
1791     }
1792 
runInstallGetPreVerifiedDomains()1793     private int runInstallGetPreVerifiedDomains() throws RemoteException {
1794         final PrintWriter pw = getOutPrintWriter();
1795         final int sessionId = Integer.parseInt(getNextArg());
1796         PackageInstaller.Session session = null;
1797         try {
1798             session = new PackageInstaller.Session(
1799                     mInterface.getPackageInstaller().openSession(sessionId));
1800             Set<String> preVerifiedDomains = session.getPreVerifiedDomains();
1801             if (preVerifiedDomains.isEmpty()) {
1802                 pw.println("The session doesn't have any pre-verified domains specified.");
1803             } else {
1804                 pw.println(String.join(",", preVerifiedDomains));
1805             }
1806         } finally {
1807             IoUtils.closeQuietly(session);
1808         }
1809         return 0;
1810     }
1811 
runInstallRemove()1812     private int runInstallRemove() throws RemoteException {
1813         final PrintWriter pw = getOutPrintWriter();
1814 
1815         final int sessionId = Integer.parseInt(getNextArg());
1816 
1817         ArrayList<String> splitNames = getRemainingArgs();
1818         if (splitNames.isEmpty()) {
1819             pw.println("Error: split name not specified");
1820             return 1;
1821         }
1822         return doRemoveSplits(sessionId, splitNames, true /*logSuccess*/);
1823     }
1824 
runGetArchivedPackageMetadata()1825     private int runGetArchivedPackageMetadata() throws RemoteException {
1826         final PrintWriter pw = getOutPrintWriter();
1827         int userId = UserHandle.USER_CURRENT;
1828 
1829         String opt;
1830         while ((opt = getNextOption()) != null) {
1831             switch (opt) {
1832                 case "--user":
1833                     userId = UserHandle.parseUserArg(getNextArgRequired());
1834                     break;
1835                 default:
1836                     pw.println("Error: Unknown option: " + opt);
1837                     return 1;
1838             }
1839         }
1840 
1841         final String packageName = getNextArg();
1842         if (packageName == null) {
1843             pw.println("Error: package name not specified");
1844             return 1;
1845         }
1846         final int translatedUserId = translateUserId(userId, UserHandle.USER_NULL,
1847                 "runGetArchivedPackageMetadata");
1848 
1849         try {
1850             var archivedPackage = mInterface.getArchivedPackage(packageName, translatedUserId);
1851             if (archivedPackage == null) {
1852                 pw.write("Package not found " + packageName);
1853                 return -1;
1854             }
1855 
1856             Parcel parcel = Parcel.obtain();
1857             byte[] bytes;
1858             try {
1859                 parcel.writeParcelable(archivedPackage, 0);
1860                 bytes = parcel.marshall();
1861             } finally {
1862                 parcel.recycle();
1863             }
1864 
1865             String encoded = HexEncoding.encodeToString(bytes);
1866             pw.write(encoded);
1867         } catch (Exception e) {
1868             getErrPrintWriter().println("Failed to get archived package, reason: " + e);
1869             pw.println("Failure [failed to get archived package], reason: " + e);
1870             return -1;
1871         }
1872         return 0;
1873     }
1874 
1875     /**
1876      * Returns a string that shows the number of bytes in b, Kb, Mb or Gb.
1877      */
getFormattedBytes(long size)1878     protected static String getFormattedBytes(long size) {
1879         double k = size/1024.0;
1880         double m = size/1048576.0;
1881         double g = size/1073741824.0;
1882 
1883         DecimalFormat dec = new DecimalFormat("0.00");
1884         if (g > 1) {
1885             return dec.format(g).concat(" Gb");
1886         } else if (m > 1) {
1887             return dec.format(m).concat(" Mb");
1888         } else if (k > 1) {
1889             return dec.format(k).concat(" Kb");
1890         }
1891         return "";
1892     }
1893 
1894     /**
1895      * Return the string that displays the data size.
1896      */
getDataSizeDisplay(long size)1897     private String getDataSizeDisplay(long size) {
1898         String formattedOutput = getFormattedBytes(size);
1899         if (!formattedOutput.isEmpty()) {
1900            formattedOutput = " (" + formattedOutput + ")";
1901         }
1902         return Long.toString(size) + " bytes" + formattedOutput;
1903     }
1904 
1905     /**
1906      * Display storage stats of the specified package.
1907      *
1908      * Usage: get-package-storage-stats [--usr USER_ID] PACKAGE
1909      */
runGetPackageStorageStats()1910     private int runGetPackageStorageStats() throws RemoteException {
1911         final PrintWriter pw = getOutPrintWriter();
1912         if (!android.content.pm.Flags.getPackageStorageStats()) {
1913             pw.println("Error: get_package_storage_stats flag is not enabled");
1914             return 1;
1915         }
1916         if (!android.app.usage.Flags.getAppBytesByDataTypeApi()) {
1917             pw.println("Error: get_app_bytes_by_data_type_api flag is not enabled");
1918             return 1;
1919         }
1920         int userId = UserHandle.USER_CURRENT;
1921 
1922         String opt;
1923         while ((opt = getNextOption()) != null) {
1924             switch (opt) {
1925                 case "--user":
1926                     userId = UserHandle.parseUserArg(getNextArgRequired());
1927                     break;
1928                 default:
1929                     pw.println("Error: Unknown option: " + opt);
1930                     return 1;
1931             }
1932         }
1933 
1934         final String packageName = getNextArg();
1935         if (packageName == null) {
1936             pw.println("Error: package name not specified");
1937             return 1;
1938         }
1939         try {
1940             StorageStatsManager storageStatsManager =
1941                 mContext.getSystemService(StorageStatsManager.class);
1942             final int translatedUserId = translateUserId(userId, UserHandle.USER_NULL,
1943                 "runGetPackageStorageStats");
1944             StorageStats stats =
1945                 storageStatsManager.queryStatsForPackage(StorageManager.UUID_DEFAULT,
1946                     packageName, UserHandle.of(translatedUserId));
1947 
1948             pw.println("code: " + getDataSizeDisplay(stats.getAppBytes()));
1949             pw.println("data: " + getDataSizeDisplay(stats.getDataBytes()));
1950             pw.println("cache: " + getDataSizeDisplay(stats.getCacheBytes()));
1951             pw.println("apk: " + getDataSizeDisplay(stats.getAppBytesByDataType(
1952                 StorageStats.APP_DATA_TYPE_FILE_TYPE_APK)));
1953             pw.println("lib: " + getDataSizeDisplay(
1954                 stats.getAppBytesByDataType(StorageStats.APP_DATA_TYPE_LIB)));
1955             pw.println("dm: " + getDataSizeDisplay(stats.getAppBytesByDataType(
1956                 StorageStats.APP_DATA_TYPE_FILE_TYPE_DM)));
1957             pw.println("dexopt artifacts: " + getDataSizeDisplay(stats.getAppBytesByDataType(
1958                 StorageStats.APP_DATA_TYPE_FILE_TYPE_DEXOPT_ARTIFACT)));
1959             pw.println("current profile : " + getDataSizeDisplay(stats.getAppBytesByDataType(
1960                 StorageStats.APP_DATA_TYPE_FILE_TYPE_CURRENT_PROFILE)));
1961             pw.println("reference profile: " + getDataSizeDisplay(stats.getAppBytesByDataType(
1962                 StorageStats.APP_DATA_TYPE_FILE_TYPE_REFERENCE_PROFILE)));
1963             pw.println("external cache: " + getDataSizeDisplay(stats.getExternalCacheBytes()));
1964         } catch (Exception e) {
1965             getErrPrintWriter().println("Failed to get storage stats, reason: " + e);
1966             pw.println("Failure [failed to get storage stats], reason: " + e);
1967             return -1;
1968         }
1969         return 0;
1970     }
1971 
runInstallExisting()1972     private int runInstallExisting() throws RemoteException {
1973         final PrintWriter pw = getOutPrintWriter();
1974         int userId = UserHandle.USER_CURRENT;
1975         int installFlags = PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS;
1976         String opt;
1977         boolean waitTillComplete = false;
1978         while ((opt = getNextOption()) != null) {
1979             switch (opt) {
1980                 case "--user":
1981                     userId = UserHandle.parseUserArg(getNextArgRequired());
1982                     break;
1983                 case "--ephemeral":
1984                 case "--instant":
1985                     installFlags |= PackageManager.INSTALL_INSTANT_APP;
1986                     installFlags &= ~PackageManager.INSTALL_FULL_APP;
1987                     break;
1988                 case "--full":
1989                     installFlags &= ~PackageManager.INSTALL_INSTANT_APP;
1990                     installFlags |= PackageManager.INSTALL_FULL_APP;
1991                     break;
1992                 case "--wait":
1993                     waitTillComplete = true;
1994                     break;
1995                 case "--restrict-permissions":
1996                     installFlags &= ~PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS;
1997                     break;
1998                 default:
1999                     pw.println("Error: Unknown option: " + opt);
2000                     return 1;
2001             }
2002         }
2003 
2004         final String packageName = getNextArg();
2005         if (packageName == null) {
2006             pw.println("Error: package name not specified");
2007             return 1;
2008         }
2009         final int translatedUserId =
2010                 translateUserId(userId, UserHandle.USER_NULL, "runInstallExisting");
2011 
2012         int installReason = PackageManager.INSTALL_REASON_UNKNOWN;
2013         try {
2014             if (waitTillComplete) {
2015                 final LocalIntentReceiver receiver = new LocalIntentReceiver();
2016                 final IPackageInstaller installer = mInterface.getPackageInstaller();
2017                 pw.println("Installing package " + packageName + " for user: " + translatedUserId);
2018                 installer.installExistingPackage(packageName, installFlags, installReason,
2019                         receiver.getIntentSender(), translatedUserId, null);
2020                 final Intent result = receiver.getResult();
2021                 final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
2022                         PackageInstaller.STATUS_FAILURE);
2023                 pw.println("Received intent for package install");
2024                 return status == PackageInstaller.STATUS_SUCCESS ? 0 : 1;
2025             }
2026 
2027             final int res = mInterface.installExistingPackageAsUser(packageName, translatedUserId,
2028                     installFlags, installReason, null);
2029             if (res == PackageManager.INSTALL_FAILED_INVALID_URI) {
2030                 throw new NameNotFoundException("Package " + packageName + " doesn't exist");
2031             }
2032             pw.println("Package " + packageName + " installed for user: " + translatedUserId);
2033             return 0;
2034         } catch (RemoteException | NameNotFoundException e) {
2035             pw.println(e.toString());
2036             return 1;
2037         }
2038     }
2039 
runSetInstallLocation()2040     private int runSetInstallLocation() throws RemoteException {
2041         int loc;
2042 
2043         String arg = getNextArg();
2044         if (arg == null) {
2045             getErrPrintWriter().println("Error: no install location specified.");
2046             return 1;
2047         }
2048         try {
2049             loc = Integer.parseInt(arg);
2050         } catch (NumberFormatException e) {
2051             getErrPrintWriter().println("Error: install location has to be a number.");
2052             return 1;
2053         }
2054         if (!mInterface.setInstallLocation(loc)) {
2055             getErrPrintWriter().println("Error: install location has to be a number.");
2056             return 1;
2057         }
2058         return 0;
2059     }
2060 
runGetInstallLocation()2061     private int runGetInstallLocation() throws RemoteException {
2062         int loc = mInterface.getInstallLocation();
2063         String locStr = "invalid";
2064         if (loc == InstallLocationUtils.APP_INSTALL_AUTO) {
2065             locStr = "auto";
2066         } else if (loc == InstallLocationUtils.APP_INSTALL_INTERNAL) {
2067             locStr = "internal";
2068         } else if (loc == InstallLocationUtils.APP_INSTALL_EXTERNAL) {
2069             locStr = "external";
2070         }
2071         getOutPrintWriter().println(loc + "[" + locStr + "]");
2072         return 0;
2073     }
2074 
runMovePackage()2075     public int runMovePackage() throws RemoteException {
2076         final String packageName = getNextArg();
2077         if (packageName == null) {
2078             getErrPrintWriter().println("Error: package name not specified");
2079             return 1;
2080         }
2081         String volumeUuid = getNextArg();
2082         if ("internal".equals(volumeUuid)) {
2083             volumeUuid = null;
2084         }
2085 
2086         final int moveId = mInterface.movePackage(packageName, volumeUuid);
2087 
2088         int status = mInterface.getMoveStatus(moveId);
2089         while (!PackageManager.isMoveStatusFinished(status)) {
2090             SystemClock.sleep(DateUtils.SECOND_IN_MILLIS);
2091             status = mInterface.getMoveStatus(moveId);
2092         }
2093 
2094         if (status == PackageManager.MOVE_SUCCEEDED) {
2095             getOutPrintWriter().println("Success");
2096             return 0;
2097         } else {
2098             getErrPrintWriter().println("Failure [" + status + "]");
2099             return 1;
2100         }
2101     }
2102 
runMovePrimaryStorage()2103     public int runMovePrimaryStorage() throws RemoteException {
2104         String volumeUuid = getNextArg();
2105         if ("internal".equals(volumeUuid)) {
2106             volumeUuid = null;
2107         }
2108 
2109         final int moveId = mInterface.movePrimaryStorage(volumeUuid);
2110 
2111         int status = mInterface.getMoveStatus(moveId);
2112         while (!PackageManager.isMoveStatusFinished(status)) {
2113             SystemClock.sleep(DateUtils.SECOND_IN_MILLIS);
2114             status = mInterface.getMoveStatus(moveId);
2115         }
2116 
2117         if (status == PackageManager.MOVE_SUCCEEDED) {
2118             getOutPrintWriter().println("Success");
2119             return 0;
2120         } else {
2121             getErrPrintWriter().println("Failure [" + status + "]");
2122             return 1;
2123         }
2124     }
2125 
getRemainingArgs()2126     private ArrayList<String> getRemainingArgs() {
2127         ArrayList<String> args = new ArrayList<>();
2128         String arg;
2129         while ((arg = getNextArg()) != null) {
2130             args.add(arg);
2131         }
2132         return args;
2133     }
2134 
2135     private static class SnapshotRuntimeProfileCallback
2136             extends ISnapshotRuntimeProfileCallback.Stub {
2137         private boolean mSuccess = false;
2138         private int mErrCode = -1;
2139         private ParcelFileDescriptor mProfileReadFd = null;
2140         private final CountDownLatch mDoneSignal = new CountDownLatch(1);
2141 
2142         @Override
onSuccess(ParcelFileDescriptor profileReadFd)2143         public void onSuccess(ParcelFileDescriptor profileReadFd) {
2144             mSuccess = true;
2145             try {
2146                 // We need to dup the descriptor. We are in the same process as system server
2147                 // and we will be receiving the same object (which will be closed on the
2148                 // server side).
2149                 mProfileReadFd = profileReadFd.dup();
2150             } catch (IOException e) {
2151                 e.printStackTrace();
2152             }
2153             mDoneSignal.countDown();
2154         }
2155 
2156         @Override
onError(int errCode)2157         public void onError(int errCode) {
2158             mSuccess = false;
2159             mErrCode = errCode;
2160             mDoneSignal.countDown();
2161         }
2162 
waitTillDone()2163         boolean waitTillDone() {
2164             boolean done = false;
2165             try {
2166                 // The time-out is an arbitrary large value. Since this is a local call the result
2167                 // will come very fast.
2168                 done = mDoneSignal.await(10000000, TimeUnit.MILLISECONDS);
2169             } catch (InterruptedException ignored) {
2170             }
2171             return done && mSuccess;
2172         }
2173     }
2174 
runUninstall()2175     private int runUninstall() throws RemoteException {
2176         final PrintWriter pw = getOutPrintWriter();
2177         int flags = 0;
2178         int userId = UserHandle.USER_ALL;
2179         long versionCode = PackageManager.VERSION_CODE_HIGHEST;
2180 
2181         String opt;
2182         while ((opt = getNextOption()) != null) {
2183             switch (opt) {
2184                 case "-k":
2185                     flags |= PackageManager.DELETE_KEEP_DATA;
2186                     break;
2187                 case "--user":
2188                     userId = UserHandle.parseUserArg(getNextArgRequired());
2189                     if (userId != UserHandle.USER_ALL && userId != UserHandle.USER_CURRENT) {
2190                         UserManagerInternal umi =
2191                                 LocalServices.getService(UserManagerInternal.class);
2192                         UserInfo userInfo = umi.getUserInfo(userId);
2193                         if (userInfo == null) {
2194                             pw.println("Failure [user " + userId + " doesn't exist]");
2195                             return 1;
2196                         }
2197                     }
2198                     break;
2199                 case "--versionCode":
2200                     versionCode = Long.parseLong(getNextArgRequired());
2201                     break;
2202                 default:
2203                     pw.println("Error: Unknown option: " + opt);
2204                     return 1;
2205             }
2206         }
2207 
2208         final String packageName = getNextArg();
2209         if (packageName == null) {
2210             pw.println("Error: package name not specified");
2211             return 1;
2212         }
2213 
2214         // if a split is specified, just remove it and not the whole package
2215         ArrayList<String> splitNames = getRemainingArgs();
2216         if (!splitNames.isEmpty()) {
2217             return runRemoveSplits(packageName, splitNames);
2218         }
2219 
2220         if (userId == UserHandle.USER_ALL) {
2221             flags |= PackageManager.DELETE_ALL_USERS;
2222         }
2223         final int translatedUserId =
2224                 translateUserId(userId, UserHandle.USER_SYSTEM, "runUninstall");
2225         final LocalIntentReceiver receiver = new LocalIntentReceiver();
2226         final PackageManagerInternal internal =
2227                 LocalServices.getService(PackageManagerInternal.class);
2228 
2229         if (internal.isApexPackage(packageName)) {
2230             internal.uninstallApex(
2231                     packageName, versionCode, translatedUserId, receiver.getIntentSender(), flags);
2232         } else {
2233             if ((flags & PackageManager.DELETE_ALL_USERS) == 0) {
2234                 final PackageInfo info = mInterface.getPackageInfo(packageName,
2235                         PackageManager.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES, translatedUserId);
2236                 if (info == null) {
2237                     pw.println("Failure [not installed for " + translatedUserId + "]");
2238                     return 1;
2239                 }
2240                 final boolean isSystem =
2241                         (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
2242                 // If we are being asked to delete a system app for just one
2243                 // user set flag so it disables rather than reverting to system
2244                 // version of the app.
2245                 if (isSystem) {
2246                     flags |= PackageManager.DELETE_SYSTEM_APP;
2247                 }
2248             }
2249             mInterface.getPackageInstaller().uninstall(new VersionedPackage(packageName,
2250                             versionCode), null /*callerPackageName*/, flags,
2251                     receiver.getIntentSender(), translatedUserId);
2252         }
2253 
2254         final Intent result = receiver.getResult();
2255         final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
2256                 PackageInstaller.STATUS_FAILURE);
2257         if (status == PackageInstaller.STATUS_SUCCESS) {
2258             pw.println("Success");
2259             return 0;
2260         } else {
2261             pw.println("Failure ["
2262                     + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]");
2263             return 1;
2264         }
2265     }
2266 
runRemoveSplits(String packageName, Collection<String> splitNames)2267     private int runRemoveSplits(String packageName, Collection<String> splitNames)
2268             throws RemoteException {
2269         final PrintWriter pw = getOutPrintWriter();
2270         final SessionParams sessionParams = new SessionParams(SessionParams.MODE_INHERIT_EXISTING);
2271         sessionParams.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
2272         sessionParams.appPackageName = packageName;
2273         final int sessionId =
2274                 doCreateSession(sessionParams, null /*installerPackageName*/, UserHandle.USER_ALL);
2275         boolean abandonSession = true;
2276         try {
2277             if (doRemoveSplits(sessionId, splitNames, false /*logSuccess*/)
2278                     != PackageInstaller.STATUS_SUCCESS) {
2279                 return 1;
2280             }
2281             if (doCommitSession(sessionId, false /*logSuccess*/)
2282                     != PackageInstaller.STATUS_SUCCESS) {
2283                 return 1;
2284             }
2285             abandonSession = false;
2286             pw.println("Success");
2287             return 0;
2288         } finally {
2289             if (abandonSession) {
2290                 try {
2291                     doAbandonSession(sessionId, false /*logSuccess*/);
2292                 } catch (RuntimeException ignore) {
2293                 }
2294             }
2295         }
2296     }
2297 
2298     static class ClearDataObserver extends IPackageDataObserver.Stub {
2299         boolean finished;
2300         boolean result;
2301 
2302         @Override
onRemoveCompleted(String packageName, boolean succeeded)2303         public void onRemoveCompleted(String packageName, boolean succeeded) throws RemoteException {
2304             synchronized (this) {
2305                 finished = true;
2306                 result = succeeded;
2307                 notifyAll();
2308             }
2309         }
2310     }
2311 
runClear()2312     private int runClear() throws RemoteException {
2313         final PrintWriter pw = getOutPrintWriter();
2314         int userId = UserHandle.USER_SYSTEM;
2315         boolean cacheOnly = false;
2316 
2317         String opt;
2318         while ((opt = getNextOption()) != null) {
2319             switch (opt) {
2320                 case "--user":
2321                     userId = UserHandle.parseUserArg(getNextArgRequired());
2322                     break;
2323                 case "--cache-only":
2324                     cacheOnly = true;
2325                     break;
2326                 default:
2327                     pw.println("Error: Unknown option: " + opt);
2328                     return 1;
2329             }
2330         }
2331 
2332         String pkg = getNextArg();
2333         if (pkg == null) {
2334             getErrPrintWriter().println("Error: no package specified");
2335             return 1;
2336         }
2337 
2338         final int translatedUserId =
2339                 translateUserId(userId, UserHandle.USER_NULL, "runClear");
2340         final ClearDataObserver obs = new ClearDataObserver();
2341         if (!cacheOnly) {
2342             ActivityManager.getService()
2343                     .clearApplicationUserData(pkg, false, obs, translatedUserId);
2344         } else {
2345             mInterface.deleteApplicationCacheFilesAsUser(pkg, translatedUserId, obs);
2346         }
2347         synchronized (obs) {
2348             while (!obs.finished) {
2349                 try {
2350                     obs.wait();
2351                 } catch (InterruptedException e) {
2352                 }
2353             }
2354         }
2355 
2356         if (obs.result) {
2357             getOutPrintWriter().println("Success");
2358             return 0;
2359         } else {
2360             getErrPrintWriter().println("Failed");
2361             return 1;
2362         }
2363     }
2364 
enabledSettingToString(int state)2365     private static String enabledSettingToString(int state) {
2366         switch (state) {
2367             case PackageManager.COMPONENT_ENABLED_STATE_DEFAULT:
2368                 return "default";
2369             case PackageManager.COMPONENT_ENABLED_STATE_ENABLED:
2370                 return "enabled";
2371             case PackageManager.COMPONENT_ENABLED_STATE_DISABLED:
2372                 return "disabled";
2373             case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER:
2374                 return "disabled-user";
2375             case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED:
2376                 return "disabled-until-used";
2377         }
2378         return "unknown";
2379     }
2380 
runSetEnabledSetting(int state)2381     private int runSetEnabledSetting(int state) throws RemoteException {
2382         int userId = UserHandle.USER_SYSTEM;
2383         String option = getNextOption();
2384         if (option != null && option.equals("--user")) {
2385             userId = UserHandle.parseUserArg(getNextArgRequired());
2386         }
2387 
2388         final String pkg = getNextArg();
2389         if (pkg == null) {
2390             getErrPrintWriter().println("Error: no package or component specified");
2391             return 1;
2392         }
2393         final int translatedUserId =
2394                 translateUserId(userId, UserHandle.USER_NULL, "runSetEnabledSetting");
2395         final ComponentName cn = ComponentName.unflattenFromString(pkg);
2396         if (cn == null) {
2397             mInterface.setApplicationEnabledSetting(pkg, state, 0, translatedUserId,
2398                     "shell:" + android.os.Process.myUid());
2399             getOutPrintWriter().println("Package " + pkg + " new state: "
2400                     + enabledSettingToString(
2401                     mInterface.getApplicationEnabledSetting(pkg, translatedUserId)));
2402             return 0;
2403         } else {
2404             mInterface.setComponentEnabledSetting(cn, state, 0, translatedUserId, "shell");
2405             getOutPrintWriter().println("Component " + cn.toShortString() + " new state: "
2406                     + enabledSettingToString(
2407                     mInterface.getComponentEnabledSetting(cn, translatedUserId)));
2408             return 0;
2409         }
2410     }
2411 
runSetHiddenSetting(boolean state)2412     private int runSetHiddenSetting(boolean state) throws RemoteException {
2413         int userId = UserHandle.USER_SYSTEM;
2414         String option = getNextOption();
2415         if (option != null && option.equals("--user")) {
2416             userId = UserHandle.parseUserArg(getNextArgRequired());
2417         }
2418 
2419         String pkg = getNextArg();
2420         if (pkg == null) {
2421             getErrPrintWriter().println("Error: no package or component specified");
2422             return 1;
2423         }
2424         final int translatedUserId =
2425                 translateUserId(userId, UserHandle.USER_NULL, "runSetHiddenSetting");
2426         mInterface.setApplicationHiddenSettingAsUser(pkg, state, translatedUserId);
2427         getOutPrintWriter().println("Package " + pkg + " new hidden state: "
2428                 + mInterface.getApplicationHiddenSettingAsUser(pkg, translatedUserId));
2429         return 0;
2430     }
2431 
runSetStoppedState(boolean state)2432     private int runSetStoppedState(boolean state) throws RemoteException {
2433         int userId = UserHandle.USER_SYSTEM;
2434         String option = getNextOption();
2435         if (option != null && option.equals("--user")) {
2436             userId = UserHandle.parseUserArg(getNextArgRequired());
2437         }
2438 
2439         String pkg = getNextArg();
2440         if (pkg == null) {
2441             getErrPrintWriter().println("Error: no package specified");
2442             return 1;
2443         }
2444         final int translatedUserId =
2445                 translateUserId(userId, UserHandle.USER_NULL, "runSetStoppedState");
2446         mInterface.setPackageStoppedState(pkg, state, translatedUserId);
2447         getOutPrintWriter().println("Package " + pkg + " new stopped state: "
2448                 + mInterface.isPackageStoppedForUser(pkg, translatedUserId));
2449         return 0;
2450     }
2451 
runSetDistractingRestriction()2452     private int runSetDistractingRestriction() {
2453         final PrintWriter pw = getOutPrintWriter();
2454         int userId = UserHandle.USER_SYSTEM;
2455         String opt;
2456         int flags = 0;
2457         while ((opt = getNextOption()) != null) {
2458             switch (opt) {
2459                 case "--user":
2460                     userId = UserHandle.parseUserArg(getNextArgRequired());
2461                     break;
2462                 case "--flag":
2463                     final String flag = getNextArgRequired();
2464                     switch (flag) {
2465                         case "hide-notifications":
2466                             flags |= PackageManager.RESTRICTION_HIDE_NOTIFICATIONS;
2467                             break;
2468                         case "hide-from-suggestions":
2469                             flags |= PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS;
2470                             break;
2471                         default:
2472                             pw.println("Unrecognized flag: " + flag);
2473                             return 1;
2474                     }
2475                     break;
2476                 default:
2477                     pw.println("Error: Unknown option: " + opt);
2478                     return 1;
2479             }
2480         }
2481 
2482         final List<String> packageNames = getRemainingArgs();
2483         if (packageNames.isEmpty()) {
2484             pw.println("Error: package name not specified");
2485             return 1;
2486         }
2487         try {
2488             final int translatedUserId = translateUserId(userId, UserHandle.USER_NULL,
2489                     "set-distracting");
2490             final String[] errored = mInterface.setDistractingPackageRestrictionsAsUser(
2491                     packageNames.toArray(new String[]{}), flags, translatedUserId);
2492             if (errored.length > 0) {
2493                 pw.println("Could not set restriction for: " + Arrays.toString(errored));
2494                 return 1;
2495             }
2496             return 0;
2497         } catch (RemoteException | IllegalArgumentException e) {
2498             pw.println(e.toString());
2499             return 1;
2500         }
2501     }
2502 
runGetDistractingRestriction()2503     private int runGetDistractingRestriction() {
2504         final PrintWriter pw = getOutPrintWriter();
2505         int userId = UserHandle.USER_SYSTEM;
2506         String opt;
2507         while ((opt = getNextOption()) != null) {
2508             switch (opt) {
2509                 case "--user":
2510                     userId = UserHandle.parseUserArg(getNextArgRequired());
2511                     break;
2512                 default:
2513                     pw.println("Error: Unknown option: " + opt);
2514                     return 1;
2515             }
2516         }
2517 
2518         final List<String> packageNames = getRemainingArgs();
2519         if (packageNames.isEmpty()) {
2520             pw.println("Error: package name not specified");
2521             return 1;
2522         }
2523         pw.println("Distracting restrictions state for user " + userId);
2524 
2525         final int translatedUserId = translateUserId(userId, UserHandle.USER_NULL,
2526                 "get-distracting");
2527         final String[] packages = packageNames.toArray(new String[]{});
2528         int[] res = mPm.getDistractingPackageRestrictionsAsUser(packages, translatedUserId);
2529 
2530         for (int i = 0; i < res.length; i++) {
2531             final int state = res[i];
2532             if (state == -1) {
2533                 pw.println(packages[i] + " not found ...");
2534             } else {
2535                 pw.println(packages[i] + "  state: " + stateToString(state));
2536             }
2537         }
2538 
2539         return 0;
2540     }
2541 
stateToString(@ackageManager.DistractionRestriction int flag)2542     private static String stateToString(@PackageManager.DistractionRestriction int flag) {
2543         switch (flag) {
2544             case RESTRICTION_NONE:
2545                 return "NONE";
2546             case RESTRICTION_HIDE_FROM_SUGGESTIONS:
2547                 return "HIDE_FROM_SUGGESTIONS";
2548             case RESTRICTION_HIDE_NOTIFICATIONS:
2549                 return "HIDE_NOTIFICATIONS";
2550             default:
2551                 return "UNKNOWN";
2552         }
2553     }
2554 
runSuspend(boolean suspendedState, int flags)2555     private int runSuspend(boolean suspendedState, int flags) {
2556         final PrintWriter pw = getOutPrintWriter();
2557         int userId = UserHandle.USER_SYSTEM;
2558         String dialogMessage = null;
2559         final PersistableBundle appExtras = new PersistableBundle();
2560         final PersistableBundle launcherExtras = new PersistableBundle();
2561         String opt;
2562         while ((opt = getNextOption()) != null) {
2563             switch (opt) {
2564                 case "--user":
2565                     userId = UserHandle.parseUserArg(getNextArgRequired());
2566                     break;
2567                 case "--dialogMessage":
2568                     dialogMessage = getNextArgRequired();
2569                     break;
2570                 case "--ael":
2571                 case "--aes":
2572                 case "--aed":
2573                 case "--lel":
2574                 case "--les":
2575                 case "--led":
2576                     final String key = getNextArgRequired();
2577                     final String val = getNextArgRequired();
2578                     if (!suspendedState) {
2579                         break;
2580                     }
2581                     final PersistableBundle bundleToInsert =
2582                             opt.startsWith("--a") ? appExtras : launcherExtras;
2583                     switch (opt.charAt(4)) {
2584                         case 'l':
2585                             bundleToInsert.putLong(key, Long.valueOf(val));
2586                             break;
2587                         case 'd':
2588                             bundleToInsert.putDouble(key, Double.valueOf(val));
2589                             break;
2590                         case 's':
2591                             bundleToInsert.putString(key, val);
2592                             break;
2593                     }
2594                     break;
2595                 default:
2596                     pw.println("Error: Unknown option: " + opt);
2597                     return 1;
2598             }
2599         }
2600 
2601         final List<String> packageNames = getRemainingArgs();
2602         if (packageNames.isEmpty()) {
2603             pw.println("Error: package name not specified");
2604             return 1;
2605         }
2606         final String callingPackage =
2607                 (Binder.getCallingUid() == Process.ROOT_UID) ? "root" : "com.android.shell";
2608 
2609         final SuspendDialogInfo info;
2610         if (!TextUtils.isEmpty(dialogMessage)) {
2611             info = new SuspendDialogInfo.Builder()
2612                     .setMessage(dialogMessage)
2613                     .build();
2614         } else {
2615             info = null;
2616         }
2617         try {
2618             final int translatedUserId =
2619                     translateUserId(userId, UserHandle.USER_NULL, "runSuspend");
2620             mInterface.setPackagesSuspendedAsUser(packageNames.toArray(new String[] {}),
2621                     suspendedState, ((appExtras.size() > 0) ? appExtras : null),
2622                     ((launcherExtras.size() > 0) ? launcherExtras : null),
2623                     info, flags, callingPackage, UserHandle.USER_SYSTEM, translatedUserId);
2624             for (int i = 0; i < packageNames.size(); i++) {
2625                 final String packageName = packageNames.get(i);
2626                 pw.println("Package " + packageName + " new suspended state: "
2627                         + mInterface.isPackageSuspendedForUser(packageName, translatedUserId));
2628             }
2629             return 0;
2630         } catch (RemoteException | IllegalArgumentException e) {
2631             pw.println(e.toString());
2632             return 1;
2633         }
2634     }
2635 
runGrantRevokePermission(boolean grant)2636     private int runGrantRevokePermission(boolean grant) throws RemoteException {
2637         int userId = UserHandle.USER_SYSTEM;
2638 
2639         String opt;
2640         boolean allPermissions = false;
2641         while ((opt = getNextOption()) != null) {
2642             if (opt.equals("--user")) {
2643                 userId = UserHandle.parseUserArg(getNextArgRequired());
2644             }
2645             if (opt.equals("--all-permissions")) {
2646                 allPermissions = true;
2647             }
2648         }
2649 
2650         String pkg = getNextArg();
2651         if (!allPermissions && pkg == null) {
2652             getErrPrintWriter().println("Error: no package specified");
2653             return 1;
2654         }
2655         String perm = getNextArg();
2656         if (!allPermissions && perm == null) {
2657             getErrPrintWriter().println("Error: no permission specified");
2658             return 1;
2659         }
2660         if (allPermissions && perm != null) {
2661             getErrPrintWriter().println("Error: permission specified but not expected");
2662             return 1;
2663         }
2664         final UserHandle translatedUser = UserHandle.of(translateUserId(userId,
2665                 UserHandle.USER_NULL, "runGrantRevokePermission"));
2666 
2667         List<PackageInfo> packageInfos;
2668         PackageManager pm = mContext.createContextAsUser(translatedUser, 0).getPackageManager();
2669         if (pkg == null) {
2670             packageInfos = pm.getInstalledPackages(PackageManager.GET_PERMISSIONS);
2671         } else {
2672             try {
2673                 packageInfos = Collections.singletonList(pm.getPackageInfo(pkg,
2674                         PackageManager.GET_PERMISSIONS));
2675             } catch (NameNotFoundException e) {
2676                 getErrPrintWriter().println("Error: package not found");
2677                 getOutPrintWriter().println("Failure [package not found]");
2678                 return 1;
2679             }
2680         }
2681 
2682         for (PackageInfo packageInfo : packageInfos) {
2683             List<String> permissions = Collections.singletonList(perm);
2684             if (allPermissions) {
2685                 permissions = getRequestedRuntimePermissions(packageInfo);
2686             }
2687             for (String permission : permissions) {
2688                 if (grant) {
2689                     try {
2690                         mPermissionManager.grantRuntimePermission(packageInfo.packageName,
2691                                 permission,
2692                                 translatedUser);
2693                     } catch (Exception e) {
2694                         if (!allPermissions) {
2695                             throw e;
2696                         } else {
2697                             Slog.w(TAG, "Could not grant permission " + permission, e);
2698                         }
2699                     }
2700                 } else {
2701                     try {
2702                         mPermissionManager.revokeRuntimePermission(packageInfo.packageName,
2703                                 permission,
2704                                 translatedUser, null);
2705                     } catch (Exception e) {
2706                         if (!allPermissions) {
2707                             throw e;
2708                         } else {
2709                             Slog.w(TAG, "Could not grant permission " + permission, e);
2710                         }
2711                     }
2712                 }
2713             }
2714         }
2715         return 0;
2716     }
2717 
getRequestedRuntimePermissions(PackageInfo info)2718     private List<String> getRequestedRuntimePermissions(PackageInfo info) {
2719         // No requested permissions
2720         if (info.requestedPermissions == null) {
2721             return new ArrayList<>();
2722         }
2723         List<String> result = new ArrayList<>();
2724         PackageManager pm = mContext.getPackageManager();
2725         // Iterate through requested permissions for denied ones
2726         for (String permission : info.requestedPermissions) {
2727             PermissionInfo pi = null;
2728             try {
2729                 pi = pm.getPermissionInfo(permission, 0);
2730             } catch (NameNotFoundException nnfe) {
2731                 // ignore
2732             }
2733             if (pi == null) {
2734                 continue;
2735             }
2736             if (pi.getProtection() != PermissionInfo.PROTECTION_DANGEROUS) {
2737                 continue;
2738             }
2739             result.add(permission);
2740         }
2741         return result;
2742     }
2743 
runResetPermissions()2744     private int runResetPermissions() throws RemoteException {
2745         mLegacyPermissionManager.resetRuntimePermissions();
2746         return 0;
2747     }
2748 
setOrClearPermissionFlags(boolean setFlags)2749     private int setOrClearPermissionFlags(boolean setFlags) {
2750         int userId = UserHandle.USER_SYSTEM;
2751 
2752         String opt;
2753         while ((opt = getNextOption()) != null) {
2754             if (opt.equals("--user")) {
2755                 userId = UserHandle.parseUserArg(getNextArgRequired());
2756             }
2757         }
2758 
2759         String pkg = getNextArg();
2760         if (pkg == null) {
2761             getErrPrintWriter().println("Error: no package specified");
2762             return 1;
2763         }
2764         String perm = getNextArg();
2765         if (perm == null) {
2766             getErrPrintWriter().println("Error: no permission specified");
2767             return 1;
2768         }
2769 
2770         int flagMask = 0;
2771         String flagName = getNextArg();
2772         if (flagName == null) {
2773             getErrPrintWriter().println("Error: no permission flags specified");
2774             return 1;
2775         }
2776         while (flagName != null) {
2777             if (!SUPPORTED_PERMISSION_FLAGS.containsKey(flagName)) {
2778                 getErrPrintWriter().println("Error: specified flag " + flagName + " is not one of "
2779                         + SUPPORTED_PERMISSION_FLAGS_LIST);
2780                 return 1;
2781             }
2782             flagMask |= SUPPORTED_PERMISSION_FLAGS.get(flagName);
2783             flagName = getNextArg();
2784         }
2785 
2786         final UserHandle translatedUser = UserHandle.of(translateUserId(userId,
2787                 UserHandle.USER_NULL, "runGrantRevokePermission"));
2788         int flagSet = setFlags ? flagMask : 0;
2789         mPermissionManager.updatePermissionFlags(pkg, perm, flagMask, flagSet, translatedUser);
2790         return 0;
2791     }
2792 
runSetPermissionEnforced()2793     private int runSetPermissionEnforced() throws RemoteException {
2794         final String permission = getNextArg();
2795         if (permission == null) {
2796             getErrPrintWriter().println("Error: no permission specified");
2797             return 1;
2798         }
2799         final String enforcedRaw = getNextArg();
2800         if (enforcedRaw == null) {
2801             getErrPrintWriter().println("Error: no enforcement specified");
2802             return 1;
2803         }
2804         // Permissions are always enforced now.
2805         return 0;
2806     }
2807 
isVendorApp(String pkg)2808     private boolean isVendorApp(String pkg) {
2809         try {
2810             final PackageInfo info = mInterface.getPackageInfo(
2811                      pkg, PackageManager.MATCH_ANY_USER, UserHandle.USER_SYSTEM);
2812             return info != null && info.applicationInfo.isVendor();
2813         } catch (RemoteException e) {
2814             return false;
2815         }
2816     }
2817 
isProductApp(String pkg)2818     private boolean isProductApp(String pkg) {
2819         try {
2820             final PackageInfo info = mInterface.getPackageInfo(
2821                     pkg, PackageManager.MATCH_ANY_USER, UserHandle.USER_SYSTEM);
2822             return info != null && info.applicationInfo.isProduct();
2823         } catch (RemoteException e) {
2824             return false;
2825         }
2826     }
2827 
isSystemExtApp(String pkg)2828     private boolean isSystemExtApp(String pkg) {
2829         try {
2830             final PackageInfo info = mInterface.getPackageInfo(
2831                     pkg, PackageManager.MATCH_ANY_USER, UserHandle.USER_SYSTEM);
2832             return info != null && info.applicationInfo.isSystemExt();
2833         } catch (RemoteException e) {
2834             return false;
2835         }
2836     }
2837 
getApexPackageNameContainingPackage(String pkg)2838     private String getApexPackageNameContainingPackage(String pkg) {
2839         ApexManager apexManager = ApexManager.getInstance();
2840         return apexManager.getActiveApexPackageNameContainingPackage(pkg);
2841     }
2842 
isApexApp(String pkg)2843     private boolean isApexApp(String pkg) {
2844         return getApexPackageNameContainingPackage(pkg) != null;
2845     }
2846 
runGetPrivappPermissions()2847     private int runGetPrivappPermissions() {
2848         final String pkg = getNextArg();
2849         if (pkg == null) {
2850             getErrPrintWriter().println("Error: no package specified.");
2851             return 1;
2852         }
2853         getOutPrintWriter().println(getPrivAppPermissionsString(pkg, true));
2854         return 0;
2855     }
2856 
runGetPrivappDenyPermissions()2857     private int runGetPrivappDenyPermissions() {
2858         final String pkg = getNextArg();
2859         if (pkg == null) {
2860             getErrPrintWriter().println("Error: no package specified.");
2861             return 1;
2862         }
2863         getOutPrintWriter().println(getPrivAppPermissionsString(pkg, false));
2864         return 0;
2865     }
2866 
2867     @NonNull
getPrivAppPermissionsString(@onNull String packageName, boolean allowed)2868     private String getPrivAppPermissionsString(@NonNull String packageName, boolean allowed) {
2869         final PermissionAllowlist permissionAllowlist =
2870                 SystemConfig.getInstance().getPermissionAllowlist();
2871         final ArrayMap<String, ArrayMap<String, Boolean>> privAppPermissions;
2872         if (isVendorApp(packageName)) {
2873             privAppPermissions = permissionAllowlist.getVendorPrivilegedAppAllowlist();
2874         } else if (isProductApp(packageName)) {
2875             privAppPermissions = permissionAllowlist.getProductPrivilegedAppAllowlist();
2876         } else if (isSystemExtApp(packageName)) {
2877             privAppPermissions = permissionAllowlist.getSystemExtPrivilegedAppAllowlist();
2878         } else if (isApexApp(packageName)) {
2879             final String moduleName = ApexManager.getInstance().getApexModuleNameForPackageName(
2880                     getApexPackageNameContainingPackage(packageName));
2881             privAppPermissions = permissionAllowlist.getApexPrivilegedAppAllowlists()
2882                     .get(moduleName);
2883         } else {
2884             privAppPermissions = permissionAllowlist.getPrivilegedAppAllowlist();
2885         }
2886         final ArrayMap<String, Boolean> permissions = privAppPermissions != null
2887                 ? privAppPermissions.get(packageName) : null;
2888         if (permissions == null) {
2889             return "{}";
2890         }
2891         final StringBuilder result = new StringBuilder("{");
2892         boolean isFirstPermission = true;
2893         final int permissionsSize = permissions.size();
2894         for (int i = 0; i < permissionsSize; i++) {
2895             boolean permissionAllowed = permissions.valueAt(i);
2896             if (permissionAllowed != allowed) {
2897                 continue;
2898             }
2899             if (isFirstPermission) {
2900                 isFirstPermission = false;
2901             } else {
2902                 result.append(", ");
2903             }
2904             String permissionName = permissions.keyAt(i);
2905             result.append(permissionName);
2906         }
2907         result.append("}");
2908         return result.toString();
2909     }
2910 
runGetOemPermissions()2911     private int runGetOemPermissions() {
2912         final String pkg = getNextArg();
2913         if (pkg == null) {
2914             getErrPrintWriter().println("Error: no package specified.");
2915             return 1;
2916         }
2917         final Map<String, Boolean> oemPermissions = SystemConfig.getInstance()
2918                 .getPermissionAllowlist().getOemAppAllowlist().get(pkg);
2919         if (oemPermissions == null || oemPermissions.isEmpty()) {
2920             getOutPrintWriter().println("{}");
2921         } else {
2922             oemPermissions.forEach((permission, granted) ->
2923                     getOutPrintWriter().println(permission + " granted:" + granted)
2924             );
2925         }
2926         return 0;
2927     }
2928 
runGetSignaturePermissionAllowlist()2929     private int runGetSignaturePermissionAllowlist() {
2930         final var partition = getNextArg();
2931         if (partition == null) {
2932             getErrPrintWriter().println("Error: no partition specified.");
2933             return 1;
2934         }
2935         final var permissionAllowlist =
2936                 SystemConfig.getInstance().getPermissionAllowlist();
2937         final ArrayMap<String, ArrayMap<String, Boolean>> allowlist;
2938         switch (partition) {
2939             case "system":
2940                 allowlist = permissionAllowlist.getSignatureAppAllowlist();
2941                 break;
2942             case "vendor":
2943                 allowlist = permissionAllowlist.getVendorSignatureAppAllowlist();
2944                 break;
2945             case "product":
2946                 allowlist = permissionAllowlist.getProductSignatureAppAllowlist();
2947                 break;
2948             case "system-ext":
2949                 allowlist = permissionAllowlist.getSystemExtSignatureAppAllowlist();
2950                 break;
2951             case "apex":
2952                 allowlist = permissionAllowlist.getApexSignatureAppAllowlist();
2953                 break;
2954             default:
2955                 getErrPrintWriter().println("Error: unknown partition: " + partition);
2956                 return 1;
2957         }
2958         final var ipw = new IndentingPrintWriter(getOutPrintWriter(), "  ");
2959         final var allowlistSize = allowlist.size();
2960         for (var allowlistIndex = 0; allowlistIndex < allowlistSize; allowlistIndex++) {
2961             final var packageName = allowlist.keyAt(allowlistIndex);
2962             final var permissions = allowlist.valueAt(allowlistIndex);
2963             ipw.print("Package: ");
2964             ipw.println(packageName);
2965             ipw.increaseIndent();
2966             final var permissionsSize = permissions.size();
2967             for (var permissionsIndex = 0; permissionsIndex < permissionsSize; permissionsIndex++) {
2968                 final var permissionName = permissions.keyAt(permissionsIndex);
2969                 final var granted = permissions.valueAt(permissionsIndex);
2970                 if (granted) {
2971                     ipw.print("Permission: ");
2972                     ipw.println(permissionName);
2973                 }
2974             }
2975             ipw.decreaseIndent();
2976         }
2977         return 0;
2978     }
2979 
runGetSharedUidAllowlist()2980     private int runGetSharedUidAllowlist() {
2981         final var allowlist = SystemConfig.getInstance().getPackageToSharedUidAllowList();
2982         final var pw = getOutPrintWriter();
2983         final var allowlistSize = allowlist.size();
2984         for (var allowlistIndex = 0; allowlistIndex < allowlistSize; allowlistIndex++) {
2985             final var packageName = allowlist.keyAt(allowlistIndex);
2986             final var sharedUserName = allowlist.valueAt(allowlistIndex);
2987             pw.print(packageName);
2988             pw.print(" ");
2989             pw.println(sharedUserName);
2990         }
2991         return 0;
2992     }
2993 
runTrimCaches()2994     private int runTrimCaches() throws RemoteException {
2995         String size = getNextArg();
2996         if (size == null) {
2997             getErrPrintWriter().println("Error: no size specified");
2998             return 1;
2999         }
3000         long multiplier = 1;
3001         int len = size.length();
3002         char c = size.charAt(len - 1);
3003         if (c < '0' || c > '9') {
3004             if (c == 'K' || c == 'k') {
3005                 multiplier = 1024L;
3006             } else if (c == 'M' || c == 'm') {
3007                 multiplier = 1024L*1024L;
3008             } else if (c == 'G' || c == 'g') {
3009                 multiplier = 1024L*1024L*1024L;
3010             } else {
3011                 getErrPrintWriter().println("Invalid suffix: " + c);
3012                 return 1;
3013             }
3014             size = size.substring(0, len-1);
3015         }
3016         long sizeVal;
3017         try {
3018             sizeVal = Long.parseLong(size) * multiplier;
3019         } catch (NumberFormatException e) {
3020             getErrPrintWriter().println("Error: expected number at: " + size);
3021             return 1;
3022         }
3023         String volumeUuid = getNextArg();
3024         if ("internal".equals(volumeUuid)) {
3025             volumeUuid = null;
3026         }
3027         ClearDataObserver obs = new ClearDataObserver();
3028         mInterface.freeStorageAndNotify(volumeUuid, sizeVal,
3029                 StorageManager.FLAG_ALLOCATE_DEFY_ALL_RESERVED, obs);
3030         synchronized (obs) {
3031             while (!obs.finished) {
3032                 try {
3033                     obs.wait();
3034                 } catch (InterruptedException e) {
3035                 }
3036             }
3037         }
3038         return 0;
3039     }
3040 
isNumber(String s)3041     private static boolean isNumber(String s) {
3042         try {
3043             Integer.parseInt(s);
3044         } catch (NumberFormatException nfe) {
3045             return false;
3046         }
3047         return true;
3048     }
3049 
runCreateUser()3050     public int runCreateUser() throws RemoteException {
3051         String name;
3052         int userId = -1;
3053         int flags = 0;
3054         String userType = null;
3055         String opt;
3056         boolean preCreateOnly = false;
3057         while ((opt = getNextOption()) != null) {
3058             String newUserType = null;
3059             if ("--profileOf".equals(opt)) {
3060                 userId = translateUserId(UserHandle.parseUserArg(getNextArgRequired()),
3061                             UserHandle.USER_ALL, "runCreateUser");
3062             } else if ("--managed".equals(opt)) {
3063                 newUserType = UserManager.USER_TYPE_PROFILE_MANAGED;
3064             } else if ("--restricted".equals(opt)) {
3065                 newUserType = UserManager.USER_TYPE_FULL_RESTRICTED;
3066             } else if ("--guest".equals(opt)) {
3067                 newUserType = UserManager.USER_TYPE_FULL_GUEST;
3068             } else if ("--demo".equals(opt)) {
3069                 newUserType = UserManager.USER_TYPE_FULL_DEMO;
3070             } else if ("--ephemeral".equals(opt)) {
3071                 flags |= UserInfo.FLAG_EPHEMERAL;
3072             } else if ("--for-testing".equals(opt)) {
3073                 flags |= UserInfo.FLAG_FOR_TESTING;
3074             } else if ("--pre-create-only".equals(opt)) {
3075                 preCreateOnly = true;
3076             } else if ("--user-type".equals(opt)) {
3077                 newUserType = getNextArgRequired();
3078             } else {
3079                 getErrPrintWriter().println("Error: unknown option " + opt);
3080                 return 1;
3081             }
3082             // Ensure only one user-type was specified.
3083             if (newUserType != null) {
3084                 if (userType != null && !userType.equals(newUserType)) {
3085                     getErrPrintWriter().println("Error: more than one user type was specified ("
3086                             + userType + " and " + newUserType + ")");
3087                     return 1;
3088                 }
3089                 userType = newUserType;
3090             }
3091         }
3092         String arg = getNextArg();
3093         if (arg == null && !preCreateOnly) {
3094             getErrPrintWriter().println("Error: no user name specified.");
3095             return 1;
3096         }
3097         if (arg != null && preCreateOnly) {
3098             getErrPrintWriter().println("Warning: name is ignored for pre-created users");
3099         }
3100 
3101         name = arg;
3102         UserInfo info = null;
3103         IUserManager um = IUserManager.Stub.asInterface(
3104                 ServiceManager.getService(Context.USER_SERVICE));
3105         IAccountManager accm = IAccountManager.Stub.asInterface(
3106                 ServiceManager.getService(Context.ACCOUNT_SERVICE));
3107         if (userType == null) {
3108             userType = UserInfo.getDefaultUserType(flags);
3109         }
3110         Trace.traceBegin(Trace.TRACE_TAG_PACKAGE_MANAGER, "shell_runCreateUser");
3111         try {
3112             if (UserManager.isUserTypeRestricted(userType)) {
3113                 // In non-split user mode, userId can only be SYSTEM
3114                 int parentUserId = userId >= 0 ? userId : UserHandle.USER_SYSTEM;
3115                 info = um.createRestrictedProfileWithThrow(name, parentUserId);
3116                 accm.addSharedAccountsFromParentUser(parentUserId, userId,
3117                         (Process.myUid() == Process.ROOT_UID) ? "root" : "com.android.shell");
3118             } else if (userId < 0) {
3119                 info = preCreateOnly ?
3120                         um.preCreateUserWithThrow(userType) :
3121                         um.createUserWithThrow(name, userType, flags);
3122             } else {
3123                 info = um.createProfileForUserWithThrow(name, userType, flags, userId, null);
3124             }
3125         } catch (ServiceSpecificException e) {
3126             getErrPrintWriter().println("Error: " + e);
3127         } finally {
3128             Trace.traceEnd(Trace.TRACE_TAG_PACKAGE_MANAGER);
3129         }
3130 
3131         if (info != null) {
3132             getOutPrintWriter().println("Success: created user id " + info.id);
3133             return 0;
3134         } else {
3135             getErrPrintWriter().println("Error: couldn't create User.");
3136             return 1;
3137         }
3138     }
3139 
3140     // pm remove-user [--set-ephemeral-if-in-use][--wait] USER_ID
runRemoveUser()3141     public int runRemoveUser() throws RemoteException {
3142         int userId;
3143         String arg;
3144         boolean setEphemeralIfInUse = false;
3145         boolean wait = false;
3146 
3147         while ((arg = getNextOption()) != null) {
3148             switch (arg) {
3149                 case "--set-ephemeral-if-in-use":
3150                     setEphemeralIfInUse = true;
3151                     break;
3152                 case "--wait": // fallthrough
3153                 case "-w":
3154                     wait = true;
3155                     break;
3156                 default:
3157                     getErrPrintWriter().println("Error: unknown option: " + arg);
3158                     return -1;
3159             }
3160         }
3161 
3162         arg = getNextArg();
3163         if (arg == null) {
3164             getErrPrintWriter().println("Error: no user id specified.");
3165             return 1;
3166         }
3167         userId = UserHandle.parseUserArg(arg);
3168         IUserManager um = IUserManager.Stub.asInterface(
3169                 ServiceManager.getService(Context.USER_SERVICE));
3170         if (setEphemeralIfInUse) {
3171             return removeUserWhenPossible(um, userId);
3172         } else {
3173             final boolean success = wait ? removeUserAndWait(um, userId) : removeUser(um, userId);
3174             if (success) {
3175                 getOutPrintWriter().println("Success: removed user");
3176                 return 0;
3177             } else {
3178                 // Error message should already have been printed.
3179                 return 1;
3180             }
3181         }
3182     }
3183 
removeUser(IUserManager um, @UserIdInt int userId)3184     private boolean removeUser(IUserManager um, @UserIdInt int userId) throws RemoteException {
3185         Slog.i(TAG, "Removing user " + userId);
3186         if (um.removeUser(userId)) {
3187             return true;
3188         } else {
3189             getErrPrintWriter().println("Error: couldn't remove user id " + userId);
3190             return false;
3191         }
3192     }
3193 
removeUserAndWait(IUserManager um, @UserIdInt int userId)3194     private boolean removeUserAndWait(IUserManager um, @UserIdInt int userId)
3195             throws RemoteException {
3196         Slog.i(TAG, "Removing (and waiting for completion) user " + userId);
3197 
3198         final CountDownLatch waitLatch = new CountDownLatch(1);
3199         final UserManagerInternal.UserLifecycleListener listener =
3200                 new UserManagerInternal.UserLifecycleListener() {
3201                     @Override
3202                     public void onUserRemoved(UserInfo user) {
3203                         if (userId == user.id) {
3204                             waitLatch.countDown();
3205                         }
3206                     }
3207                 };
3208 
3209         final UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class);
3210         umi.addUserLifecycleListener(listener);
3211 
3212         try {
3213             if (um.removeUser(userId)) {
3214                 final boolean awaitSuccess = waitLatch.await(10, TimeUnit.MINUTES);
3215                 if (!awaitSuccess) {
3216                     getErrPrintWriter().printf("Error: Remove user %d timed out\n", userId);
3217                     return false;
3218                 }
3219                 // Success!
3220                 return true;
3221             } else {
3222                 getErrPrintWriter().println("Error: couldn't remove user id " + userId);
3223                 return false;
3224             }
3225         } catch (InterruptedException e) {
3226             getErrPrintWriter().printf("Error: Remove user %d wait interrupted: %s\n", userId, e);
3227             Thread.currentThread().interrupt();
3228             return false;
3229         } finally {
3230             umi.removeUserLifecycleListener(listener);
3231         }
3232     }
3233 
removeUserWhenPossible(IUserManager um, @UserIdInt int userId)3234     private int removeUserWhenPossible(IUserManager um, @UserIdInt int userId)
3235             throws RemoteException {
3236         Slog.i(TAG, "Removing " + userId + " or set as ephemeral if in use.");
3237         int result = um.removeUserWhenPossible(userId, /* overrideDevicePolicy= */ false);
3238         switch (result) {
3239             case UserManager.REMOVE_RESULT_REMOVED:
3240                 getOutPrintWriter().printf("Success: user %d removed\n", userId);
3241                 return 0;
3242             case UserManager.REMOVE_RESULT_DEFERRED:
3243                 getOutPrintWriter().printf("Success: user %d set as ephemeral\n", userId);
3244                 return 0;
3245             case UserManager.REMOVE_RESULT_ALREADY_BEING_REMOVED:
3246                 getOutPrintWriter().printf("Success: user %d is already being removed\n", userId);
3247                 return 0;
3248             case UserManager.REMOVE_RESULT_ERROR_MAIN_USER_PERMANENT_ADMIN:
3249                 getErrPrintWriter().printf("Error: user %d is a permanent admin main user\n",
3250                         userId);
3251                 return 1;
3252             default:
3253                 getErrPrintWriter().printf("Error: couldn't remove or mark ephemeral user id %d\n",
3254                         userId);
3255                 return 1;
3256         }
3257     }
3258 
runMarkGuestForDeletion()3259     private int runMarkGuestForDeletion() throws RemoteException {
3260         String arg = getNextArg();
3261         if (arg == null) {
3262             getErrPrintWriter().println("Error: no user id specified.");
3263             return 1;
3264         }
3265         int userId = resolveUserId(UserHandle.parseUserArg(arg));
3266 
3267         IUserManager um = IUserManager.Stub.asInterface(
3268                 ServiceManager.getService(Context.USER_SERVICE));
3269         if (!um.markGuestForDeletion(userId)) {
3270             getErrPrintWriter().println("Error: could not mark guest for deletion");
3271             return 1;
3272         }
3273 
3274         return 0;
3275     }
3276 
runRenameUser()3277     private int runRenameUser() throws RemoteException {
3278         String arg = getNextArg();
3279         if (arg == null) {
3280             getErrPrintWriter().println("Error: no user id specified.");
3281             return 1;
3282         }
3283         int userId = resolveUserId(UserHandle.parseUserArg(arg));
3284 
3285         String name = getNextArg();
3286         if (name == null) {
3287             Slog.i(TAG, "Resetting name of user " + userId);
3288         } else {
3289             Slog.i(TAG, "Renaming user " + userId + " to '" + name + "'");
3290         }
3291 
3292         IUserManager um = IUserManager.Stub.asInterface(
3293                 ServiceManager.getService(Context.USER_SERVICE));
3294         um.setUserName(userId, name);
3295 
3296         return 0;
3297     }
3298 
runSetUserRestriction()3299     public int runSetUserRestriction() throws RemoteException {
3300         int userId = UserHandle.USER_SYSTEM;
3301         String opt = getNextOption();
3302         if (opt != null && "--user".equals(opt)) {
3303             userId = UserHandle.parseUserArg(getNextArgRequired());
3304         }
3305 
3306         String restriction = getNextArg();
3307         String arg = getNextArg();
3308         boolean value;
3309         if ("1".equals(arg)) {
3310             value = true;
3311         } else if ("0".equals(arg)) {
3312             value = false;
3313         } else {
3314             getErrPrintWriter().println("Error: valid value not specified");
3315             return 1;
3316         }
3317         final int translatedUserId =
3318                 translateUserId(userId, UserHandle.USER_NULL, "runSetUserRestriction");
3319         final IUserManager um = IUserManager.Stub.asInterface(
3320                 ServiceManager.getService(Context.USER_SERVICE));
3321         um.setUserRestriction(restriction, value, translatedUserId);
3322         return 0;
3323     }
3324 
runGetUserRestriction()3325     private int runGetUserRestriction() throws RemoteException {
3326         final PrintWriter pw = getOutPrintWriter();
3327         int userId = UserHandle.USER_SYSTEM;
3328         boolean getAllRestrictions = false;
3329 
3330         String opt;
3331         while ((opt = getNextOption()) != null) {
3332             switch (opt) {
3333                 case "--user":
3334                     userId = UserHandle.parseUserArg(getNextArgRequired());
3335                     break;
3336                 case "--all":
3337                     getAllRestrictions = true;
3338                     if (getNextArg() != null) {
3339                         throw new IllegalArgumentException("Argument unexpected after \"--all\"");
3340                     }
3341                     break;
3342                 default:
3343                     throw new IllegalArgumentException("Unknown option " + opt);
3344             }
3345         }
3346 
3347         final int translatedUserId =
3348                 translateUserId(userId, UserHandle.USER_NULL, "runGetUserRestriction");
3349         final IUserManager um = IUserManager.Stub.asInterface(
3350                 ServiceManager.getService(Context.USER_SERVICE));
3351 
3352         if (getAllRestrictions) {
3353             final Bundle restrictions = um.getUserRestrictions(translatedUserId);
3354             pw.println("All restrictions:");
3355             pw.println(restrictions.toString());
3356         } else {
3357             String restriction = getNextArg();
3358             if (restriction == null) {
3359                 throw new IllegalArgumentException("No restriction key specified");
3360             }
3361             String unexpectedArgument = getNextArg();
3362             if (unexpectedArgument != null) {
3363                 throw new IllegalArgumentException("Argument unexpected after restriction key");
3364             }
3365             pw.println(um.hasUserRestriction(restriction, translatedUserId));
3366         }
3367         return 0;
3368     }
3369 
runSupportsMultipleUsers()3370     public int runSupportsMultipleUsers() {
3371         getOutPrintWriter().println("Is multiuser supported: "
3372                 + UserManager.supportsMultipleUsers());
3373         return 0;
3374     }
3375 
runGetMaxUsers()3376     public int runGetMaxUsers() {
3377         getOutPrintWriter().println("Maximum supported users: "
3378                 + UserManager.getMaxSupportedUsers());
3379         return 0;
3380     }
3381 
runGetMaxRunningUsers()3382     public int runGetMaxRunningUsers() {
3383         ActivityManagerInternal activityManagerInternal =
3384                 LocalServices.getService(ActivityManagerInternal.class);
3385         getOutPrintWriter().println("Maximum supported running users: "
3386                 + activityManagerInternal.getMaxRunningUsers());
3387         return 0;
3388     }
3389 
3390     private static class InstallParams {
3391         SessionParams sessionParams;
3392         String installerPackageName;
3393         int userId = UserHandle.USER_ALL;
3394         long stagedReadyTimeoutMs = DEFAULT_STAGED_READY_TIMEOUT_MS;
3395     }
3396 
makeInstallParams(Set<String> unsupportedOptions)3397     private InstallParams makeInstallParams(Set<String> unsupportedOptions) {
3398         final SessionParams sessionParams = new SessionParams(SessionParams.MODE_FULL_INSTALL);
3399         final InstallParams params = new InstallParams();
3400 
3401         params.sessionParams = sessionParams;
3402         // Allowlist all permissions by default
3403         sessionParams.installFlags |= PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS;
3404         // Set package source to other by default. Can be overridden by "--package-source"
3405         sessionParams.setPackageSource(PackageInstaller.PACKAGE_SOURCE_OTHER);
3406 
3407         // Encodes one of the states:
3408         //  1. Install request explicitly specified --staged, then value will be true.
3409         //  2. Install request explicitly specified --non-staged, then value will be false.
3410         //  3. Install request did not specify either --staged or --non-staged, then for APEX
3411         //      installs the value will be true, and for apk installs it will be false.
3412         Boolean staged = null;
3413 
3414         String opt;
3415         boolean replaceExisting = true;
3416         boolean forceNonStaged = false;
3417         while ((opt = getNextOption()) != null) {
3418             if (unsupportedOptions.contains(opt)) {
3419                 throw new IllegalArgumentException("Unsupported option " + opt);
3420             }
3421             switch (opt) {
3422                 case "-r": // ignore
3423                     break;
3424                 case "-R":
3425                     replaceExisting = false;
3426                     break;
3427                 case "-i":
3428                     params.installerPackageName = getNextArg();
3429                     if (params.installerPackageName == null) {
3430                         throw new IllegalArgumentException("Missing installer package");
3431                     }
3432                     break;
3433                 case "-t":
3434                     sessionParams.installFlags |= PackageManager.INSTALL_ALLOW_TEST;
3435                     break;
3436                 case "-f":
3437                     sessionParams.installFlags |= PackageManager.INSTALL_INTERNAL;
3438                     break;
3439                 case "-d":
3440                     sessionParams.installFlags |= PackageManager.INSTALL_REQUEST_DOWNGRADE;
3441                     break;
3442                 case "-g":
3443                     sessionParams.installFlags |=
3444                             PackageManager.INSTALL_GRANT_ALL_REQUESTED_PERMISSIONS;
3445                     break;
3446                 case "--restrict-permissions":
3447                     sessionParams.installFlags &=
3448                             ~PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS;
3449                     break;
3450                 case "--dont-kill":
3451                     sessionParams.installFlags |= PackageManager.INSTALL_DONT_KILL_APP;
3452                     break;
3453                 case "--originating-uri":
3454                     sessionParams.originatingUri = Uri.parse(getNextArg());
3455                     break;
3456                 case "--referrer":
3457                     sessionParams.referrerUri = Uri.parse(getNextArg());
3458                     break;
3459                 case "-p":
3460                     sessionParams.mode = SessionParams.MODE_INHERIT_EXISTING;
3461                     sessionParams.appPackageName = getNextArg();
3462                     if (sessionParams.appPackageName == null) {
3463                         throw new IllegalArgumentException("Missing inherit package name");
3464                     }
3465                     break;
3466                 case "--pkg":
3467                     sessionParams.appPackageName = getNextArg();
3468                     if (sessionParams.appPackageName == null) {
3469                         throw new IllegalArgumentException("Missing package name");
3470                     }
3471                     break;
3472                 case "-S":
3473                     final long sizeBytes = Long.parseLong(getNextArg());
3474                     if (sizeBytes <= 0) {
3475                         throw new IllegalArgumentException("Size must be positive");
3476                     }
3477                     sessionParams.setSize(sizeBytes);
3478                     break;
3479                 case "--abi":
3480                     sessionParams.abiOverride = checkAbiArgument(getNextArg());
3481                     break;
3482                 case "--ephemeral":
3483                 case "--instant":
3484                 case "--instantapp":
3485                     sessionParams.setInstallAsInstantApp(true /*isInstantApp*/);
3486                     break;
3487                 case "--full":
3488                     sessionParams.setInstallAsInstantApp(false /*isInstantApp*/);
3489                     break;
3490                 case "--preload":
3491                     sessionParams.setInstallAsVirtualPreload();
3492                     break;
3493                 case "--user":
3494                     params.userId = UserHandle.parseUserArg(getNextArgRequired());
3495                     break;
3496                 case "--install-location":
3497                     sessionParams.installLocation = Integer.parseInt(getNextArg());
3498                     break;
3499                 case "--install-reason":
3500                     sessionParams.installReason = Integer.parseInt(getNextArg());
3501                     break;
3502                 case "--update-ownership":
3503                     if (params.installerPackageName == null) {
3504                         // Enabling update ownership enforcement needs an installer. Since the
3505                         // default installer is null when using adb install, that effectively
3506                         // disable this enforcement.
3507                         params.installerPackageName = "com.android.shell";
3508                     }
3509                     sessionParams.installFlags |= PackageManager.INSTALL_REQUEST_UPDATE_OWNERSHIP;
3510                     break;
3511                 case "--force-uuid":
3512                     sessionParams.installFlags |= PackageManager.INSTALL_FORCE_VOLUME_UUID;
3513                     sessionParams.volumeUuid = getNextArg();
3514                     if ("internal".equals(sessionParams.volumeUuid)) {
3515                         sessionParams.volumeUuid = null;
3516                     }
3517                     break;
3518                 case "--force-sdk": // ignore
3519                     break;
3520                 case "--apex":
3521                     sessionParams.setInstallAsApex();
3522                     break;
3523                 case "--force-non-staged":
3524                     forceNonStaged = true;
3525                     break;
3526                 case "--multi-package":
3527                     sessionParams.setMultiPackage();
3528                     break;
3529                 case "--staged":
3530                     staged = true;
3531                     break;
3532                 case "--non-staged":
3533                     staged = false;
3534                     break;
3535                 case "--force-queryable":
3536                     sessionParams.setForceQueryable();
3537                     break;
3538                 case "--enable-rollback":
3539                     if (params.installerPackageName == null) {
3540                         // com.android.shell has the TEST_MANAGE_ROLLBACKS
3541                         // permission needed to enable rollback for non-module
3542                         // packages, which is likely what the user wants when
3543                         // enabling rollback through the shell command. Set
3544                         // the installer to com.android.shell if no installer
3545                         // has been provided so that the user doesn't have to
3546                         // remember to set it themselves.
3547                         params.installerPackageName = "com.android.shell";
3548                     }
3549                     int rollbackStrategy = PackageManager.ROLLBACK_DATA_POLICY_RESTORE;
3550                     try {
3551                         rollbackStrategy = Integer.parseInt(peekNextArg());
3552                         if (rollbackStrategy < PackageManager.ROLLBACK_DATA_POLICY_RESTORE
3553                                 || rollbackStrategy > PackageManager.ROLLBACK_DATA_POLICY_RETAIN) {
3554                             throw new IllegalArgumentException(
3555                                     rollbackStrategy + " is not a valid rollback data policy.");
3556                         }
3557                         getNextArg(); // pop the argument
3558                     } catch (NumberFormatException e) {
3559                         // not followed by a number assume ROLLBACK_DATA_POLICY_RESTORE.
3560                     }
3561                     sessionParams.setEnableRollback(true, rollbackStrategy);
3562                     break;
3563                 case "--rollback-impact-level":
3564                     if (!Flags.recoverabilityDetection()) {
3565                         throw new IllegalArgumentException("Unknown option " + opt);
3566                     }
3567                     int rollbackImpactLevel = Integer.parseInt(peekNextArg());
3568                     if (rollbackImpactLevel < PackageManager.ROLLBACK_USER_IMPACT_LOW
3569                             || rollbackImpactLevel
3570                                     > PackageManager.ROLLBACK_USER_IMPACT_ONLY_MANUAL) {
3571                         throw new IllegalArgumentException(
3572                             rollbackImpactLevel + " is not a valid rollback impact level.");
3573                     }
3574                     sessionParams.setRollbackImpactLevel(rollbackImpactLevel);
3575                 case "--staged-ready-timeout":
3576                     params.stagedReadyTimeoutMs = Long.parseLong(getNextArgRequired());
3577                     break;
3578                 case "--skip-verification":
3579                     sessionParams.installFlags |= PackageManager.INSTALL_DISABLE_VERIFICATION;
3580                     break;
3581                 case "--skip-enable":
3582                     sessionParams.setApplicationEnabledSettingPersistent();
3583                     break;
3584                 case "--bypass-low-target-sdk-block":
3585                     sessionParams.installFlags |=
3586                             PackageManager.INSTALL_BYPASS_LOW_TARGET_SDK_BLOCK;
3587                     break;
3588                 case "--ignore-dexopt-profile":
3589                     sessionParams.installFlags |= PackageManager.INSTALL_IGNORE_DEXOPT_PROFILE;
3590                     break;
3591                 case "--package-source":
3592                     sessionParams.setPackageSource(Integer.parseInt(getNextArg()));
3593                     break;
3594                 case "--dexopt-compiler-filter":
3595                     sessionParams.dexoptCompilerFilter = getNextArgRequired();
3596                     // An early check that throws IllegalArgumentException if the compiler filter is
3597                     // invalid.
3598                     new DexoptParams.Builder(ReasonMapping.REASON_INSTALL)
3599                             .setCompilerFilter(sessionParams.dexoptCompilerFilter)
3600                             .build();
3601                     break;
3602                 default:
3603                     throw new IllegalArgumentException("Unknown option " + opt);
3604             }
3605         }
3606         if (staged == null) {
3607             staged = (sessionParams.installFlags & PackageManager.INSTALL_APEX) != 0;
3608         }
3609         if (replaceExisting) {
3610             sessionParams.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
3611         }
3612         if (forceNonStaged) {
3613             sessionParams.isStaged = false;
3614             sessionParams.developmentInstallFlags |=
3615                     PackageManager.INSTALL_DEVELOPMENT_FORCE_NON_STAGED_APEX_UPDATE;
3616         } else if (staged) {
3617             sessionParams.setStaged();
3618         }
3619         if ((sessionParams.installFlags & PackageManager.INSTALL_APEX) != 0
3620                 && (sessionParams.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0
3621                 && sessionParams.rollbackDataPolicy == PackageManager.ROLLBACK_DATA_POLICY_WIPE) {
3622             throw new IllegalArgumentException("Data policy 'wipe' is not supported for apex.");
3623         }
3624         return params;
3625     }
3626 
runSetHomeActivity()3627     private int runSetHomeActivity() {
3628         final PrintWriter pw = getOutPrintWriter();
3629         int userId = UserHandle.USER_SYSTEM;
3630         String opt;
3631         while ((opt = getNextOption()) != null) {
3632             switch (opt) {
3633                 case "--user":
3634                     userId = UserHandle.parseUserArg(getNextArgRequired());
3635                     break;
3636                 default:
3637                     pw.println("Error: Unknown option: " + opt);
3638                     return 1;
3639             }
3640         }
3641 
3642         String pkgName;
3643         String component = getNextArg();
3644         if (component.indexOf('/') < 0) {
3645             // No component specified, so assume it's just a package name.
3646             pkgName = component;
3647         } else {
3648             ComponentName componentName =
3649                     component != null ? ComponentName.unflattenFromString(component) : null;
3650             if (componentName == null) {
3651                 pw.println("Error: invalid component name");
3652                 return 1;
3653             }
3654             pkgName = componentName.getPackageName();
3655         }
3656         final int translatedUserId =
3657                 translateUserId(userId, UserHandle.USER_NULL, "runSetHomeActivity");
3658         final CompletableFuture<Boolean> future = new CompletableFuture<>();
3659         try {
3660             RoleManager roleManager = mContext.getSystemService(RoleManager.class);
3661             roleManager.addRoleHolderAsUser(RoleManager.ROLE_HOME, pkgName, 0,
3662                     UserHandle.of(translatedUserId), FgThread.getExecutor(), future::complete);
3663             boolean success = future.get();
3664             if (success) {
3665                 pw.println("Success");
3666                 return 0;
3667             } else {
3668                 pw.println("Error: Failed to set default home.");
3669                 return 1;
3670             }
3671         } catch (Exception e) {
3672             pw.println(e.toString());
3673             return 1;
3674         }
3675     }
3676 
runSetInstaller()3677     private int runSetInstaller() throws RemoteException {
3678         final String targetPackage = getNextArg();
3679         final String installerPackageName = getNextArg();
3680 
3681         if (targetPackage == null || installerPackageName == null) {
3682             getErrPrintWriter().println("Must provide both target and installer package names");
3683             return 1;
3684         }
3685 
3686         mInterface.setInstallerPackageName(targetPackage, installerPackageName);
3687         getOutPrintWriter().println("Success");
3688         return 0;
3689     }
3690 
runGetInstantAppResolver()3691     private int runGetInstantAppResolver() {
3692         final PrintWriter pw = getOutPrintWriter();
3693         try {
3694             final ComponentName instantAppsResolver = mInterface.getInstantAppResolverComponent();
3695             if (instantAppsResolver == null) {
3696                 return 1;
3697             }
3698             pw.println(instantAppsResolver.flattenToString());
3699             return 0;
3700         } catch (Exception e) {
3701             pw.println(e.toString());
3702             return 1;
3703         }
3704     }
3705 
runHasFeature()3706     private int runHasFeature() {
3707         final PrintWriter err = getErrPrintWriter();
3708         final String featureName = getNextArg();
3709         if (featureName == null) {
3710             err.println("Error: expected FEATURE name");
3711             return 1;
3712         }
3713         final String versionString = getNextArg();
3714         try {
3715             final int version = (versionString == null) ? 0 : Integer.parseInt(versionString);
3716             final boolean hasFeature = mInterface.hasSystemFeature(featureName, version);
3717             getOutPrintWriter().println(hasFeature);
3718             return hasFeature ? 0 : 1;
3719         } catch (NumberFormatException e) {
3720             err.println("Error: illegal version number " + versionString);
3721             return 1;
3722         } catch (RemoteException e) {
3723             err.println(e.toString());
3724             return 1;
3725         }
3726     }
3727 
runDump()3728     private int runDump() {
3729         String pkg = getNextArg();
3730         if (pkg == null) {
3731             getErrPrintWriter().println("Error: no package specified");
3732             return 1;
3733         }
3734         ActivityManager.dumpPackageStateStatic(getOutFileDescriptor(), pkg);
3735         return 0;
3736     }
3737 
runDumpPackage()3738     private int runDumpPackage() {
3739         String pkg = getNextArg();
3740         if (pkg == null) {
3741             getErrPrintWriter().println("Error: no package specified");
3742             return 1;
3743         }
3744         try {
3745             ((IBinder) mInterface).dump(getOutFileDescriptor(), new String[]{pkg});
3746         } catch (Throwable e) {
3747             PrintWriter pw = getErrPrintWriter();
3748             pw.println("Failure dumping service:");
3749             e.printStackTrace(pw);
3750             pw.flush();
3751         }
3752         return 0;
3753     }
3754 
runSetHarmfulAppWarning()3755     private int runSetHarmfulAppWarning() throws RemoteException {
3756         int userId = UserHandle.USER_CURRENT;
3757 
3758         String opt;
3759         while ((opt = getNextOption()) != null) {
3760             if (opt.equals("--user")) {
3761                 userId = UserHandle.parseUserArg(getNextArgRequired());
3762             } else {
3763                 getErrPrintWriter().println("Error: Unknown option: " + opt);
3764                 return -1;
3765             }
3766         }
3767 
3768         final int translatedUserId =
3769                 translateUserId(userId, UserHandle.USER_NULL, "runSetHarmfulAppWarning");
3770         final String packageName = getNextArgRequired();
3771         final String warning = getNextArg();
3772 
3773         mInterface.setHarmfulAppWarning(packageName, warning, translatedUserId);
3774 
3775         return 0;
3776     }
3777 
runGetHarmfulAppWarning()3778     private int runGetHarmfulAppWarning() throws RemoteException {
3779         int userId = UserHandle.USER_CURRENT;
3780 
3781         String opt;
3782         while ((opt = getNextOption()) != null) {
3783             if (opt.equals("--user")) {
3784                 userId = UserHandle.parseUserArg(getNextArgRequired());
3785             } else {
3786                 getErrPrintWriter().println("Error: Unknown option: " + opt);
3787                 return -1;
3788             }
3789         }
3790 
3791         final int translatedUserId =
3792                 translateUserId(userId, UserHandle.USER_NULL, "runGetHarmfulAppWarning");
3793         final String packageName = getNextArgRequired();
3794         final CharSequence warning = mInterface.getHarmfulAppWarning(packageName, translatedUserId);
3795         if (!TextUtils.isEmpty(warning)) {
3796             getOutPrintWriter().println(warning);
3797             return 0;
3798         } else {
3799             return 1;
3800         }
3801     }
3802 
runSetSilentUpdatesPolicy()3803     private int runSetSilentUpdatesPolicy() {
3804         final PrintWriter pw = getOutPrintWriter();
3805         String opt;
3806         String installerPackageName = null;
3807         Long throttleTimeInSeconds = null;
3808         boolean reset = false;
3809         while ((opt = getNextOption()) != null) {
3810             switch (opt) {
3811                 case "--allow-unlimited-silent-updates":
3812                     installerPackageName = getNextArgRequired();
3813                     break;
3814                 case "--throttle-time":
3815                     throttleTimeInSeconds = Long.parseLong(getNextArgRequired());
3816                     break;
3817                 case "--reset":
3818                     reset = true;
3819                     break;
3820                 default:
3821                     pw.println("Error: Unknown option: " + opt);
3822                     return -1;
3823             }
3824         }
3825         if (throttleTimeInSeconds != null && throttleTimeInSeconds < 0) {
3826             pw.println("Error: Invalid value for \"--throttle-time\":" + throttleTimeInSeconds);
3827             return -1;
3828         }
3829 
3830         try {
3831             final IPackageInstaller installer = mInterface.getPackageInstaller();
3832             if (reset) {
3833                 installer.setAllowUnlimitedSilentUpdates(null /* installerPackageName */);
3834                 installer.setSilentUpdatesThrottleTime(-1 /* restore to the default */);
3835             } else {
3836                 if (installerPackageName != null) {
3837                     installer.setAllowUnlimitedSilentUpdates(installerPackageName);
3838                 }
3839                 if (throttleTimeInSeconds != null) {
3840                     installer.setSilentUpdatesThrottleTime(throttleTimeInSeconds);
3841                 }
3842             }
3843         } catch (RemoteException e) {
3844             pw.println("Failure ["
3845                     + e.getClass().getName() + " - "
3846                     + e.getMessage() + "]");
3847             return -1;
3848         }
3849         return 1;
3850     }
3851 
runGetAppMetadata()3852     private int runGetAppMetadata() {
3853         mContext.enforceCallingOrSelfPermission(GET_APP_METADATA, "getAppMetadataFd");
3854         final PrintWriter pw = getOutPrintWriter();
3855         String pkgName = getNextArgRequired();
3856         ParcelFileDescriptor pfd = null;
3857         try {
3858             pfd = mInterface.getAppMetadataFd(pkgName, mContext.getUserId());
3859         } catch (RemoteException e) {
3860             pw.println("Failure [" + e.getClass().getName() + " - " + e.getMessage() + "]");
3861             return -1;
3862         }
3863         if (pfd != null) {
3864             try (BufferedReader br = new BufferedReader(
3865                     new InputStreamReader(new ParcelFileDescriptor.AutoCloseInputStream(pfd)))) {
3866                 while (br.ready()) {
3867                     pw.println(br.readLine());
3868                 }
3869             } catch (IOException e) {
3870                 pw.println("Failure [" + e.getClass().getName() + " - " + e.getMessage() + "]");
3871                 return -1;
3872             }
3873         }
3874         return 1;
3875     }
3876 
runWaitForHandler(boolean forBackgroundHandler)3877     private int runWaitForHandler(boolean forBackgroundHandler) {
3878         final PrintWriter pw = getOutPrintWriter();
3879         long timeoutMillis = 60000; // default timeout is 60 seconds
3880         String opt;
3881         while ((opt = getNextOption()) != null) {
3882             switch (opt) {
3883                 case "--timeout":
3884                     timeoutMillis = Long.parseLong(getNextArgRequired());
3885                     break;
3886                 default:
3887                     pw.println("Error: Unknown option: " + opt);
3888                     return -1;
3889             }
3890         }
3891         if (timeoutMillis <= 0) {
3892             pw.println("Error: --timeout value must be positive: " + timeoutMillis);
3893             return -1;
3894         }
3895         final boolean success;
3896         try {
3897             success = mInterface.waitForHandler(timeoutMillis, forBackgroundHandler);
3898         } catch (RemoteException e) {
3899             pw.println("Failure [" + e.getClass().getName() + " - " + e.getMessage() + "]");
3900             return -1;
3901         }
3902         if (success) {
3903             pw.println("Success");
3904             return 0;
3905         } else {
3906             pw.println("Timeout. PackageManager handlers are still busy.");
3907             return -1;
3908         }
3909     }
3910 
runArtServiceCommand()3911     private int runArtServiceCommand() {
3912         try (var in = ParcelFileDescriptor.dup(getInFileDescriptor());
3913                 var out = ParcelFileDescriptor.dup(getOutFileDescriptor());
3914                 var err = ParcelFileDescriptor.dup(getErrFileDescriptor())) {
3915             return LocalManagerRegistry.getManagerOrThrow(ArtManagerLocal.class)
3916                     .handleShellCommand(getTarget(), in, out, err, getAllArgs());
3917         } catch (IOException e) {
3918             throw new IllegalStateException(e);
3919         } catch (ManagerNotFoundException e) {
3920             PrintWriter epw = getErrPrintWriter();
3921             epw.println("ART Service is not ready. Please try again later");
3922             return -1;
3923         }
3924     }
3925 
checkAbiArgument(String abi)3926     private static String checkAbiArgument(String abi) {
3927         if (TextUtils.isEmpty(abi)) {
3928             throw new IllegalArgumentException("Missing ABI argument");
3929         }
3930 
3931         if ("-".equals(abi)) {
3932             return abi;
3933         }
3934 
3935         final String[] supportedAbis = Build.SUPPORTED_ABIS;
3936         for (String supportedAbi : supportedAbis) {
3937             if (supportedAbi.equals(abi)) {
3938                 return abi;
3939             }
3940         }
3941 
3942         throw new IllegalArgumentException("ABI " + abi + " not supported on this device");
3943     }
3944 
translateUserId(int userId, int allUserId, String logContext)3945     private int translateUserId(int userId, int allUserId, String logContext) {
3946         final boolean allowAll = (allUserId != UserHandle.USER_NULL);
3947         final int translatedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
3948                 Binder.getCallingUid(), userId, allowAll, true, logContext, "pm command");
3949         return translatedUserId == UserHandle.USER_ALL ? allUserId : translatedUserId;
3950     }
3951 
doCreateSession(SessionParams params, String installerPackageName, int userId)3952     private int doCreateSession(SessionParams params, String installerPackageName, int userId)
3953             throws RemoteException {
3954         if (userId == UserHandle.USER_ALL) {
3955             params.installFlags |= PackageManager.INSTALL_ALL_USERS;
3956         }
3957         final int translatedUserId =
3958                 translateUserId(userId, UserHandle.USER_SYSTEM, "doCreateSession");
3959         final int sessionId = mInterface.getPackageInstaller()
3960                 .createSession(params, installerPackageName, null /*installerAttributionTag*/,
3961                         translatedUserId);
3962         return sessionId;
3963     }
3964 
doAddFiles(int sessionId, ArrayList<String> args, long sessionSizeBytes, boolean isApex, boolean installArchived)3965     private int doAddFiles(int sessionId, ArrayList<String> args, long sessionSizeBytes,
3966             boolean isApex, boolean installArchived) throws RemoteException {
3967         PackageInstaller.Session session = null;
3968         try {
3969             session = new PackageInstaller.Session(
3970                     mInterface.getPackageInstaller().openSession(sessionId));
3971 
3972             // 1. Single file from stdin.
3973             if (args.isEmpty() || STDIN_PATH.equals(args.get(0))) {
3974                 final String name = "base" + RANDOM.nextInt() + "." + (isApex ? "apex" : "apk");
3975                 final long size;
3976                 final Metadata metadata;
3977                 if (!installArchived) {
3978                     metadata = Metadata.forStdIn(name);
3979                     size = sessionSizeBytes;
3980                 } else {
3981                     metadata = Metadata.forArchived(
3982                             getArchivedPackage(STDIN_PATH, sessionSizeBytes));
3983                     size = -1;
3984                 }
3985                 session.addFile(LOCATION_DATA_APP, name, size, metadata.toByteArray(), null);
3986                 return 0;
3987             }
3988 
3989             for (String arg : args) {
3990                 final int delimLocation = arg.indexOf(':');
3991 
3992                 if (delimLocation != -1) {
3993                     // 2. File with specified size read from stdin.
3994                     if (installArchived) {
3995                         getOutPrintWriter().println(
3996                                 "Error: can't install with size from STDIN for Archival install");
3997                         return 1;
3998                     }
3999                     if (processArgForStdin(arg, session) != 0) {
4000                         return 1;
4001                     }
4002                 } else {
4003                     // 3. Local file.
4004                     processArgForLocalFile(arg, session, installArchived);
4005                 }
4006             }
4007             return 0;
4008         } catch (IOException | IllegalArgumentException e) {
4009             getErrPrintWriter().println("Failed to add file(s), reason: " + e);
4010             getOutPrintWriter().println("Failure [failed to add file(s)]");
4011             return 1;
4012         } finally {
4013             IoUtils.closeQuietly(session);
4014         }
4015     }
4016 
processArgForStdin(String arg, PackageInstaller.Session session)4017     private int processArgForStdin(String arg, PackageInstaller.Session session) {
4018         final String[] fileDesc = arg.split(":");
4019         String name, fileId;
4020         long sizeBytes;
4021         byte[] signature = null;
4022         int streamingVersion = 0;
4023 
4024         try {
4025             if (fileDesc.length < 2) {
4026                 getErrPrintWriter().println("Must specify file name and size");
4027                 return 1;
4028             }
4029             name = fileDesc[0];
4030             sizeBytes = Long.parseUnsignedLong(fileDesc[1]);
4031             fileId = name;
4032 
4033             if (fileDesc.length > 2 && !TextUtils.isEmpty(fileDesc[2])) {
4034                 fileId = fileDesc[2];
4035             }
4036             if (fileDesc.length > 3) {
4037                 signature = Base64.getDecoder().decode(fileDesc[3]);
4038             }
4039             if (fileDesc.length > 4) {
4040                 streamingVersion = Integer.parseUnsignedInt(fileDesc[4]);
4041                 if (streamingVersion < 0 || streamingVersion > 1) {
4042                     getErrPrintWriter().println(
4043                             "Unsupported streaming version: " + streamingVersion);
4044                     return 1;
4045                 }
4046             }
4047         } catch (IllegalArgumentException e) {
4048             getErrPrintWriter().println(
4049                     "Unable to parse file parameters: " + arg + ", reason: " + e);
4050             return 1;
4051         }
4052 
4053         if (TextUtils.isEmpty(name)) {
4054             getErrPrintWriter().println("Empty file name in: " + arg);
4055             return 1;
4056         }
4057 
4058         final Metadata metadata;
4059 
4060         if (signature != null) {
4061             // Streaming/adb mode. Versions:
4062             // 0: data only streaming, tree has to be fully available,
4063             // 1: tree and data streaming.
4064             metadata = (streamingVersion == 0) ? Metadata.forDataOnlyStreaming(fileId)
4065                     : Metadata.forStreaming(fileId);
4066             try {
4067                 if ((signature.length > 0) && (V4Signature.readFrom(signature) == null)) {
4068                     getErrPrintWriter().println("V4 signature is invalid in: " + arg);
4069                     return 1;
4070                 }
4071             } catch (Exception e) {
4072                 getErrPrintWriter().println(
4073                         "V4 signature is invalid: " + e + " in " + arg);
4074                 return 1;
4075             }
4076         } else {
4077             // Single-shot read from stdin.
4078             metadata = Metadata.forStdIn(fileId);
4079         }
4080 
4081         session.addFile(LOCATION_DATA_APP, name, sizeBytes, metadata.toByteArray(), signature);
4082         return 0;
4083     }
4084 
getFileStatSize(File file)4085     private long getFileStatSize(File file) {
4086         final ParcelFileDescriptor pfd = openFileForSystem(file.getPath(), "r");
4087         if (pfd == null) {
4088             throw new IllegalArgumentException("Error: Can't open file: " + file.getPath());
4089         }
4090         try {
4091             return pfd.getStatSize();
4092         } finally {
4093             IoUtils.closeQuietly(pfd);
4094         }
4095     }
4096 
getArchivedPackage(String inPath, long sizeBytes)4097     private ArchivedPackageParcel getArchivedPackage(String inPath, long sizeBytes)
4098             throws RemoteException, IOException {
4099         final var fdWithSize = openInFile(inPath, sizeBytes);
4100         if (fdWithSize.first == null) {
4101             throw new IllegalArgumentException("Error: Can't open file: " + inPath);
4102         }
4103 
4104         final String encoded;
4105         final ParcelFileDescriptor fd = fdWithSize.first;
4106         final int size = (int) (long) fdWithSize.second;
4107         try (InputStream inStream = new AutoCloseInputStream(fd)) {
4108             byte[] bytes = new byte[size];
4109             Streams.readFully(inStream, bytes);
4110             encoded = new String(bytes);
4111         } catch (IOException e) {
4112             throw new IllegalArgumentException("Error: Can't load archived package from: " + inPath,
4113                     e);
4114         }
4115 
4116         var result = Metadata.readArchivedPackageParcel(HexEncoding.decode(encoded));
4117         if (result == null) {
4118             throw new IllegalArgumentException(
4119                     "Error: Can't parse archived package from: " + inPath);
4120         }
4121         return result;
4122     }
4123 
processArgForLocalFile(String arg, PackageInstaller.Session session, boolean installArchived)4124     private void processArgForLocalFile(String arg, PackageInstaller.Session session,
4125             boolean installArchived) throws IOException, RemoteException {
4126         final String inPath = arg;
4127 
4128         final File file = new File(inPath);
4129         final String name = file.getName();
4130         final long size;
4131         final Metadata metadata;
4132         if (installArchived) {
4133             metadata = Metadata.forArchived(getArchivedPackage(inPath, -1));
4134             size = 0;
4135         } else {
4136             metadata = Metadata.forLocalFile(inPath);
4137             size = getFileStatSize(file);
4138         }
4139 
4140         byte[] v4signatureBytes = null;
4141         if (!installArchived) {
4142             // Try to load the v4 signature file for the APK; it might not exist.
4143             final String v4SignaturePath = inPath + V4Signature.EXT;
4144             final ParcelFileDescriptor pfd = openFileForSystem(v4SignaturePath, "r");
4145             if (pfd != null) {
4146                 try {
4147                     final V4Signature v4signature = V4Signature.readFrom(pfd);
4148                     v4signatureBytes = v4signature.toByteArray();
4149                 } catch (IOException ex) {
4150                     Slog.e(TAG, "V4 signature file exists but failed to be parsed.", ex);
4151                 } finally {
4152                     IoUtils.closeQuietly(pfd);
4153                 }
4154             }
4155         }
4156 
4157         session.addFile(LOCATION_DATA_APP, name, size, metadata.toByteArray(), v4signatureBytes);
4158     }
4159 
doWriteSplits(int sessionId, ArrayList<String> splitPaths, long sessionSizeBytes, boolean isApex)4160     private int doWriteSplits(int sessionId, ArrayList<String> splitPaths, long sessionSizeBytes,
4161             boolean isApex) throws RemoteException {
4162         final boolean multipleSplits = splitPaths.size() > 1;
4163         for (String splitPath : splitPaths) {
4164             String splitName = multipleSplits ? new File(splitPath).getName()
4165                     : "base." + (isApex ? "apex" : "apk");
4166 
4167             if (doWriteSplit(sessionId, splitPath, sessionSizeBytes, splitName,
4168                     false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {
4169                 return 1;
4170             }
4171         }
4172         return 0;
4173     }
4174 
openInFile(String inPath, long sizeBytes)4175     private Pair<ParcelFileDescriptor, Long> openInFile(String inPath, long sizeBytes)
4176             throws IOException {
4177         final ParcelFileDescriptor fd;
4178         if (STDIN_PATH.equals(inPath)) {
4179             fd = ParcelFileDescriptor.dup(getInFileDescriptor());
4180         } else if (inPath != null) {
4181             fd = openFileForSystem(inPath, "r");
4182             if (fd == null) {
4183                 return Pair.create(null, -1L);
4184             }
4185             sizeBytes = fd.getStatSize();
4186             if (sizeBytes < 0) {
4187                 fd.close();
4188                 getErrPrintWriter().println("Unable to get size of: " + inPath);
4189                 return Pair.create(null, -1L);
4190             }
4191         } else {
4192             fd = ParcelFileDescriptor.dup(getInFileDescriptor());
4193         }
4194         if (sizeBytes <= 0) {
4195             getErrPrintWriter().println("Error: must specify an APK size");
4196             return Pair.create(null, 1L);
4197         }
4198         return Pair.create(fd, sizeBytes);
4199     }
4200 
doWriteSplit(int sessionId, String inPath, long sizeBytes, String splitName, boolean logSuccess)4201     private int doWriteSplit(int sessionId, String inPath, long sizeBytes, String splitName,
4202             boolean logSuccess) throws RemoteException {
4203         PackageInstaller.Session session = null;
4204         try {
4205             session = new PackageInstaller.Session(
4206                     mInterface.getPackageInstaller().openSession(sessionId));
4207 
4208             final PrintWriter pw = getOutPrintWriter();
4209 
4210             final var fdWithSize = openInFile(inPath, sizeBytes);
4211             if (fdWithSize.first == null) {
4212                 long resultCode = fdWithSize.second;
4213                 return (int) resultCode;
4214             }
4215             final ParcelFileDescriptor fd = fdWithSize.first;
4216             sizeBytes = fdWithSize.second;
4217 
4218             session.write(splitName, 0, sizeBytes, fd);
4219 
4220             if (logSuccess) {
4221                 pw.println("Success: streamed " + sizeBytes + " bytes");
4222             }
4223             return 0;
4224         } catch (IOException e) {
4225             getErrPrintWriter().println("Error: failed to write; " + e.getMessage());
4226             return 1;
4227         } finally {
4228             IoUtils.closeQuietly(session);
4229         }
4230     }
4231 
doInstallAddSession(int parentId, int[] sessionIds, boolean logSuccess)4232     private int doInstallAddSession(int parentId, int[] sessionIds, boolean logSuccess)
4233             throws RemoteException {
4234         final PrintWriter pw = getOutPrintWriter();
4235         PackageInstaller.Session session = null;
4236         try {
4237             session = new PackageInstaller.Session(
4238                     mInterface.getPackageInstaller().openSession(parentId));
4239             if (!session.isMultiPackage()) {
4240                 getErrPrintWriter().println(
4241                         "Error: parent session ID is not a multi-package session");
4242                 return 1;
4243             }
4244             for (int i = 0; i < sessionIds.length; i++) {
4245                 session.addChildSessionId(sessionIds[i]);
4246             }
4247             if (logSuccess) {
4248                 pw.println("Success");
4249             }
4250             return 0;
4251         } finally {
4252             IoUtils.closeQuietly(session);
4253         }
4254     }
4255 
doRemoveSplits(int sessionId, Collection<String> splitNames, boolean logSuccess)4256     private int doRemoveSplits(int sessionId, Collection<String> splitNames, boolean logSuccess)
4257             throws RemoteException {
4258         final PrintWriter pw = getOutPrintWriter();
4259         PackageInstaller.Session session = null;
4260         try {
4261             session = new PackageInstaller.Session(
4262                     mInterface.getPackageInstaller().openSession(sessionId));
4263             for (String splitName : splitNames) {
4264                 session.removeSplit(splitName);
4265             }
4266 
4267             if (logSuccess) {
4268                 pw.println("Success");
4269             }
4270             return 0;
4271         } catch (IOException e) {
4272             pw.println("Error: failed to remove split; " + e.getMessage());
4273             return 1;
4274         } finally {
4275             IoUtils.closeQuietly(session);
4276         }
4277     }
4278 
doCommitSession(int sessionId, boolean logSuccess)4279     private int doCommitSession(int sessionId, boolean logSuccess)
4280             throws RemoteException {
4281 
4282         final PrintWriter pw = getOutPrintWriter();
4283         PackageInstaller.Session session = null;
4284         try {
4285             session = new PackageInstaller.Session(
4286                     mInterface.getPackageInstaller().openSession(sessionId));
4287             if (!session.isMultiPackage() && !session.isStaged()) {
4288                 // Validity check that all .dm files match an apk.
4289                 // (The installer does not support standalone .dm files and will not process them.)
4290                 try {
4291                     DexMetadataHelper.validateDexPaths(session.getNames());
4292                 } catch (IllegalStateException | IOException e) {
4293                     pw.println(
4294                             "Warning [Could not validate the dex paths: " + e.getMessage() + "]");
4295                 }
4296             }
4297             final LocalIntentReceiver receiver = new LocalIntentReceiver();
4298             session.commit(receiver.getIntentSender());
4299             if (!session.isStaged()) {
4300                 final Intent result = receiver.getResult();
4301                 int status = result.getIntExtra(
4302                         PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_FAILURE);
4303                 List<String> warnings =
4304                         result.getStringArrayListExtra(PackageInstaller.EXTRA_WARNINGS);
4305                 if (status == PackageInstaller.STATUS_SUCCESS) {
4306                     if (!ArrayUtils.isEmpty(warnings)) {
4307                         // Don't start the output string with "Success" because that will make adb
4308                         // treat this as a success.
4309                         for (String warning : warnings) {
4310                             pw.println("Warning: " + warning);
4311                         }
4312                         // Treat warnings as failure to draw app developers' attention.
4313                         status = PackageInstaller.STATUS_FAILURE;
4314                         pw.println("Completed with warning(s)");
4315                     } else if (logSuccess) {
4316                         pw.println("Success");
4317                     }
4318                 } else {
4319                     pw.println("Failure ["
4320                             + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]");
4321                 }
4322                 return status;
4323             } else {
4324                 // Return immediately without retrieving the result. The caller will decide
4325                 // whether to wait for the session to become ready.
4326                 if (logSuccess) {
4327                     pw.println("Success");
4328                 }
4329                 return PackageInstaller.STATUS_SUCCESS;
4330             }
4331         } finally {
4332             IoUtils.closeQuietly(session);
4333         }
4334     }
4335 
doAbandonSession(int sessionId, boolean logSuccess)4336     private int doAbandonSession(int sessionId, boolean logSuccess) throws RemoteException {
4337         final PrintWriter pw = getOutPrintWriter();
4338         PackageInstaller.Session session = null;
4339         try {
4340             session = new PackageInstaller.Session(
4341                     mInterface.getPackageInstaller().openSession(sessionId));
4342             session.abandon();
4343             if (logSuccess) {
4344                 pw.println("Success");
4345             }
4346             return 0;
4347         } finally {
4348             IoUtils.closeQuietly(session);
4349         }
4350     }
4351 
doListPermissions(ArrayList<String> groupList, boolean groups, boolean labels, boolean summary, int startProtectionLevel, int endProtectionLevel)4352     private void doListPermissions(ArrayList<String> groupList, boolean groups, boolean labels,
4353             boolean summary, int startProtectionLevel, int endProtectionLevel)
4354                     throws RemoteException {
4355         final PrintWriter pw = getOutPrintWriter();
4356         final int groupCount = groupList.size();
4357         for (int i = 0; i < groupCount; i++) {
4358             String groupName = groupList.get(i);
4359             String prefix = "";
4360             if (groups) {
4361                 if (i > 0) {
4362                     pw.println("");
4363                 }
4364                 if (groupName != null) {
4365                     PermissionGroupInfo pgi =
4366                             mInterface.getPermissionGroupInfo(groupName, 0 /*flags*/);
4367                     if (summary) {
4368                         Resources res = getResources(pgi);
4369                         if (res != null) {
4370                             pw.print(loadText(pgi, pgi.labelRes, pgi.nonLocalizedLabel) + ": ");
4371                         } else {
4372                             pw.print(pgi.name + ": ");
4373 
4374                         }
4375                     } else {
4376                         pw.println((labels ? "+ " : "") + "group:" + pgi.name);
4377                         if (labels) {
4378                             pw.println("  package:" + pgi.packageName);
4379                             Resources res = getResources(pgi);
4380                             if (res != null) {
4381                                 pw.println("  label:"
4382                                         + loadText(pgi, pgi.labelRes, pgi.nonLocalizedLabel));
4383                                 pw.println("  description:"
4384                                         + loadText(pgi, pgi.descriptionRes,
4385                                                 pgi.nonLocalizedDescription));
4386                             }
4387                         }
4388                     }
4389                 } else {
4390                     pw.println(((labels && !summary) ? "+ " : "") + "ungrouped:");
4391                 }
4392                 prefix = "  ";
4393             }
4394             List<PermissionInfo> ps = mPermissionManager
4395                     .queryPermissionsByGroup(groupList.get(i), 0 /*flags*/);
4396             final int count = (ps == null ? 0 : ps.size());
4397             boolean first = true;
4398             for (int p = 0 ; p < count ; p++) {
4399                 PermissionInfo pi = ps.get(p);
4400                 if (groups && groupName == null && pi.group != null) {
4401                     continue;
4402                 }
4403                 final int base = pi.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
4404                 if (base < startProtectionLevel
4405                         || base > endProtectionLevel) {
4406                     continue;
4407                 }
4408                 if (summary) {
4409                     if (first) {
4410                         first = false;
4411                     } else {
4412                         pw.print(", ");
4413                     }
4414                     Resources res = getResources(pi);
4415                     if (res != null) {
4416                         pw.print(loadText(pi, pi.labelRes,
4417                                 pi.nonLocalizedLabel));
4418                     } else {
4419                         pw.print(pi.name);
4420                     }
4421                 } else {
4422                     pw.println(prefix + (labels ? "+ " : "")
4423                             + "permission:" + pi.name);
4424                     if (labels) {
4425                         pw.println(prefix + "  package:" + pi.packageName);
4426                         Resources res = getResources(pi);
4427                         if (res != null) {
4428                             pw.println(prefix + "  label:"
4429                                     + loadText(pi, pi.labelRes,
4430                                             pi.nonLocalizedLabel));
4431                             pw.println(prefix + "  description:"
4432                                     + loadText(pi, pi.descriptionRes,
4433                                             pi.nonLocalizedDescription));
4434                         }
4435                         pw.println(prefix + "  protectionLevel:"
4436                                 + PermissionInfo.protectionToString(pi.protectionLevel));
4437                     }
4438                 }
4439             }
4440 
4441             if (summary) {
4442                 pw.println("");
4443             }
4444         }
4445     }
4446 
loadText(PackageItemInfo pii, int res, CharSequence nonLocalized)4447     private String loadText(PackageItemInfo pii, int res, CharSequence nonLocalized)
4448             throws RemoteException {
4449         if (nonLocalized != null) {
4450             return nonLocalized.toString();
4451         }
4452         if (res != 0) {
4453             Resources r = getResources(pii);
4454             if (r != null) {
4455                 try {
4456                     return r.getString(res);
4457                 } catch (Resources.NotFoundException e) {
4458                 }
4459             }
4460         }
4461         return null;
4462     }
4463 
getResources(PackageItemInfo pii)4464     private Resources getResources(PackageItemInfo pii) throws RemoteException {
4465         Resources res = mResourceCache.get(pii.packageName);
4466         if (res != null) return res;
4467 
4468         ApplicationInfo ai = mInterface.getApplicationInfo(pii.packageName,
4469                 PackageManager.MATCH_DISABLED_COMPONENTS
4470                         | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
4471                         | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, 0);
4472         if (ai == null) {
4473             Slog.e(TAG, "Failed to get ApplicationInfo for package name(" + pii.packageName + ").");
4474             return null;
4475         }
4476         AssetManager am = new AssetManager();
4477         am.addAssetPath(ai.publicSourceDir);
4478         res = new Resources(am, null, null);
4479         mResourceCache.put(pii.packageName, res);
4480         return res;
4481     }
4482 
4483     // Resolves the userId; supports UserHandle.USER_CURRENT, but not other special values
resolveUserId(@serIdInt int userId)4484     private @UserIdInt int resolveUserId(@UserIdInt int userId) {
4485         return userId == UserHandle.USER_CURRENT ? ActivityManager.getCurrentUser() : userId;
4486     }
4487 
runClearPackagePreferredActivities()4488     private int runClearPackagePreferredActivities() {
4489         final PrintWriter pw = getErrPrintWriter();
4490         final String packageName = getNextArg();
4491         if (packageName == null) {
4492             pw.println("Error: package name not specified");
4493             return 1;
4494         }
4495         try {
4496             mContext.getPackageManager().clearPackagePreferredActivities(packageName);
4497             return 0;
4498         } catch (Exception e) {
4499             pw.println(e.toString());
4500             return 1;
4501         }
4502     }
4503 
runArchive()4504     private int runArchive() throws RemoteException {
4505         final PrintWriter pw = getOutPrintWriter();
4506         int flags = 0;
4507         int userId = UserHandle.USER_ALL;
4508 
4509         String opt;
4510         while ((opt = getNextOption()) != null) {
4511             if (opt.equals("--user")) {
4512                 userId = UserHandle.parseUserArg(getNextArgRequired());
4513                 if (userId != UserHandle.USER_ALL && userId != UserHandle.USER_CURRENT) {
4514                     UserManagerInternal umi =
4515                             LocalServices.getService(UserManagerInternal.class);
4516                     UserInfo userInfo = umi.getUserInfo(userId);
4517                     if (userInfo == null) {
4518                         pw.println("Failure [user " + userId + " doesn't exist]");
4519                         return 1;
4520                     }
4521                 }
4522             } else {
4523                 pw.println("Error: Unknown option: " + opt);
4524                 return 1;
4525             }
4526         }
4527 
4528         final String packageName = getNextArg();
4529         if (packageName == null) {
4530             pw.println("Error: package name not specified");
4531             return 1;
4532         }
4533 
4534         if (userId == UserHandle.USER_ALL) {
4535             flags |= PackageManager.DELETE_ALL_USERS;
4536         }
4537         final int translatedUserId =
4538                 translateUserId(userId, UserHandle.USER_SYSTEM, "runArchive");
4539         final LocalIntentReceiver receiver = new LocalIntentReceiver();
4540 
4541         try {
4542             mInterface.getPackageInstaller().requestArchive(packageName,
4543                     /* callerPackageName= */ "", flags, receiver.getIntentSender(),
4544                     new UserHandle(translatedUserId));
4545         } catch (Exception e) {
4546             pw.println("Failure [" + e.getMessage() + "]");
4547             return 1;
4548         }
4549 
4550         final Intent result = receiver.getResult();
4551         final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
4552                 PackageInstaller.STATUS_FAILURE);
4553         if (status == PackageInstaller.STATUS_SUCCESS) {
4554             pw.println("Success");
4555             return 0;
4556         } else {
4557             pw.println("Failure ["
4558                     + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]");
4559             return 1;
4560         }
4561     }
4562 
runUnarchive()4563     private int runUnarchive() throws RemoteException {
4564         final PrintWriter pw = getOutPrintWriter();
4565         int userId = UserHandle.USER_ALL;
4566 
4567         String opt;
4568         while ((opt = getNextOption()) != null) {
4569             if (opt.equals("--user")) {
4570                 userId = UserHandle.parseUserArg(getNextArgRequired());
4571                 if (userId != UserHandle.USER_ALL && userId != UserHandle.USER_CURRENT) {
4572                     UserManagerInternal umi =
4573                             LocalServices.getService(UserManagerInternal.class);
4574                     UserInfo userInfo = umi.getUserInfo(userId);
4575                     if (userInfo == null) {
4576                         pw.println("Failure [user " + userId + " doesn't exist]");
4577                         return 1;
4578                     }
4579                 }
4580             } else {
4581                 pw.println("Error: Unknown option: " + opt);
4582                 return 1;
4583             }
4584         }
4585 
4586         final String packageName = getNextArg();
4587         if (packageName == null) {
4588             pw.println("Error: package name not specified");
4589             return 1;
4590         }
4591 
4592         final int translatedUserId =
4593                 translateUserId(userId, UserHandle.USER_SYSTEM, "runArchive");
4594         final LocalIntentReceiver receiver = new LocalIntentReceiver();
4595 
4596         try {
4597             mInterface.getPackageInstaller().requestUnarchive(packageName,
4598                     mContext.getPackageName(), receiver.getIntentSender(),
4599                     new UserHandle(translatedUserId));
4600         } catch (Exception e) {
4601             pw.println("Failure [" + e.getMessage() + "]");
4602             return 1;
4603         }
4604 
4605         pw.println("Success");
4606         return 0;
4607     }
4608 
runGetDomainVerificationAgent()4609     private int runGetDomainVerificationAgent() throws RemoteException {
4610         final PrintWriter pw = getOutPrintWriter();
4611         int userId = UserHandle.USER_ALL;
4612 
4613         String opt;
4614         while ((opt = getNextOption()) != null) {
4615             if (opt.equals("--user")) {
4616                 userId = UserHandle.parseUserArg(getNextArgRequired());
4617                 if (userId != UserHandle.USER_ALL && userId != UserHandle.USER_CURRENT) {
4618                     UserManagerInternal umi =
4619                             LocalServices.getService(UserManagerInternal.class);
4620                     UserInfo userInfo = umi.getUserInfo(userId);
4621                     if (userInfo == null) {
4622                         pw.println("Failure [user " + userId + " doesn't exist]");
4623                         return 1;
4624                     }
4625                 }
4626             } else {
4627                 pw.println("Error: Unknown option: " + opt);
4628                 return 1;
4629             }
4630         }
4631         final int translatedUserId =
4632                 translateUserId(userId, UserHandle.USER_SYSTEM, "runGetDomainVerificationAgent");
4633         try {
4634             final ComponentName domainVerificationAgent =
4635                     mInterface.getDomainVerificationAgent(translatedUserId);
4636             pw.println(domainVerificationAgent == null
4637                     ? "No Domain Verifier available!" : domainVerificationAgent.flattenToString());
4638         } catch (Exception e) {
4639             pw.println("Failure [" + e.getMessage() + "]");
4640             return 1;
4641         }
4642         return 0;
4643     }
4644 
4645     @Override
onHelp()4646     public void onHelp() {
4647         final PrintWriter pw = getOutPrintWriter();
4648         pw.println("Package manager (package) commands:");
4649         pw.println("  help");
4650         pw.println("    Print this help text.");
4651         pw.println("");
4652         pw.println("  path [--user USER_ID] PACKAGE");
4653         pw.println("    Print the path to the .apk of the given PACKAGE.");
4654         pw.println("");
4655         pw.println("  dump PACKAGE");
4656         pw.println("    Print various system state associated with the given PACKAGE.");
4657         pw.println("");
4658         pw.println("  dump-package PACKAGE");
4659         pw.println("    Print package manager state associated with the given PACKAGE.");
4660         pw.println("");
4661         pw.println("  has-feature FEATURE_NAME [version]");
4662         pw.println("    Prints true and returns exit status 0 when system has a FEATURE_NAME,");
4663         pw.println("    otherwise prints false and returns exit status 1");
4664         pw.println("");
4665         pw.println("  list features");
4666         pw.println("    Prints all features of the system.");
4667         pw.println("");
4668         pw.println("  list instrumentation [-f] [TARGET-PACKAGE]");
4669         pw.println("    Prints all test packages; optionally only those targeting TARGET-PACKAGE");
4670         pw.println("    Options:");
4671         pw.println("      -f: dump the name of the .apk file containing the test package");
4672         pw.println("");
4673         pw.println("  list libraries [-v]");
4674         pw.println("    Prints all system libraries.");
4675         pw.println("    Options:");
4676         pw.println("      -v: shows the location of the library in the device's filesystem");
4677         pw.println("");
4678         pw.println("  list packages [-f] [-d] [-e] [-s] [-q] [-3] [-i] [-l] [-u] [-U] ");
4679         pw.println("      [--show-versioncode] [--apex-only] [--factory-only]");
4680         pw.println("      [--uid UID] [--user USER_ID] [FILTER]");
4681         pw.println("    Prints all packages; optionally only those whose name contains");
4682         pw.println("    the text in FILTER.  Options are:");
4683         pw.println("      -f: see their associated file");
4684         pw.println("      -a: all known packages (but excluding APEXes)");
4685         pw.println("      -d: filter to only show disabled packages");
4686         pw.println("      -e: filter to only show enabled packages");
4687         pw.println("      -s: filter to only show system packages");
4688         if (Flags.quarantinedEnabled()) {
4689             pw.println("      -q: filter to only show quarantined packages");
4690         }
4691         pw.println("      -3: filter to only show third party packages");
4692         pw.println("      -i: see the installer for the packages");
4693         pw.println("      -l: ignored (used for compatibility with older releases)");
4694         pw.println("      -U: also show the package UID");
4695         pw.println("      -u: also include uninstalled packages");
4696         pw.println("      --show-versioncode: also show the version code");
4697         pw.println("      --apex-only: only show APEX packages");
4698         pw.println("      --factory-only: only show system packages excluding updates");
4699         pw.println("      --uid UID: filter to only show packages with the given UID");
4700         pw.println("      --user USER_ID: only list packages belonging to the given user");
4701         pw.println("      --match-libraries: include packages that declare static shared and SDK libraries");
4702         pw.println("");
4703         pw.println("  list permission-groups");
4704         pw.println("    Prints all known permission groups.");
4705         pw.println("");
4706         pw.println("  list permissions [-g] [-f] [-d] [-u] [GROUP]");
4707         pw.println("    Prints all known permissions; optionally only those in GROUP.  Options are:");
4708         pw.println("      -g: organize by group");
4709         pw.println("      -f: print all information");
4710         pw.println("      -s: short summary");
4711         pw.println("      -d: only list dangerous permissions");
4712         pw.println("      -u: list only the permissions users will see");
4713         pw.println("");
4714         pw.println("  list staged-sessions [--only-ready] [--only-sessionid] [--only-parent]");
4715         pw.println("    Prints all staged sessions.");
4716         pw.println("      --only-ready: show only staged sessions that are ready");
4717         pw.println("      --only-sessionid: show only sessionId of each session");
4718         pw.println("      --only-parent: hide all children sessions");
4719         pw.println("");
4720         pw.println("  list users");
4721         pw.println("    Prints all users.");
4722         pw.println("");
4723         pw.println("  resolve-activity [--brief] [--components] [--query-flags FLAGS]");
4724         pw.println("       [--user USER_ID] INTENT");
4725         pw.println("    Prints the activity that resolves to the given INTENT.");
4726         pw.println("");
4727         pw.println("  query-activities [--brief] [--components] [--query-flags FLAGS]");
4728         pw.println("       [--user USER_ID] INTENT");
4729         pw.println("    Prints all activities that can handle the given INTENT.");
4730         pw.println("");
4731         pw.println("  query-services [--brief] [--components] [--query-flags FLAGS]");
4732         pw.println("       [--user USER_ID] INTENT");
4733         pw.println("    Prints all services that can handle the given INTENT.");
4734         pw.println("");
4735         pw.println("  query-receivers [--brief] [--components] [--query-flags FLAGS]");
4736         pw.println("       [--user USER_ID] INTENT");
4737         pw.println("    Prints all broadcast receivers that can handle the given INTENT.");
4738         pw.println("");
4739         pw.println("  install [-rtfdg] [-i PACKAGE] [--user USER_ID|all|current]");
4740         pw.println("       [-p INHERIT_PACKAGE] [--install-location 0/1/2]");
4741         pw.println("       [--install-reason 0/1/2/3/4] [--originating-uri URI]");
4742         pw.println("       [--referrer URI] [--abi ABI_NAME] [--force-sdk]");
4743         pw.println("       [--preload] [--instant] [--full] [--dont-kill]");
4744         pw.println("       [--enable-rollback [0/1/2]]");
4745         pw.println("       [--force-uuid internal|UUID] [--pkg PACKAGE] [-S BYTES]");
4746         pw.println("       [--apex] [--non-staged] [--force-non-staged]");
4747         pw.println("       [--staged-ready-timeout TIMEOUT] [--ignore-dexopt-profile]");
4748         pw.println("       [--dexopt-compiler-filter FILTER]");
4749         pw.println("       [PATH [SPLIT...]|-]");
4750         pw.println("    Install an application.  Must provide the apk data to install, either as");
4751         pw.println("    file path(s) or '-' to read from stdin.  Options are:");
4752         pw.println("      -R: disallow replacement of existing application");
4753         pw.println("      -t: allow test packages");
4754         pw.println("      -i: specify package name of installer owning the app");
4755         pw.println("      -f: install application on internal flash");
4756         pw.println("      -d: allow version code downgrade (debuggable packages only)");
4757         pw.println("      -p: partial application install (new split on top of existing pkg)");
4758         pw.println("      -g: grant all runtime permissions");
4759         pw.println("      -S: size in bytes of package, required for stdin");
4760         pw.println("      --user: install under the given user.");
4761         pw.println("      --dont-kill: installing a new feature split, don't kill running app");
4762         pw.println("      --restrict-permissions: don't whitelist restricted permissions at install");
4763         pw.println("      --originating-uri: set URI where app was downloaded from");
4764         pw.println("      --referrer: set URI that instigated the install of the app");
4765         pw.println("      --pkg: specify expected package name of app being installed");
4766         pw.println("      --abi: override the default ABI of the platform");
4767         pw.println("      --instant: cause the app to be installed as an ephemeral install app");
4768         pw.println("      --full: cause the app to be installed as a non-ephemeral full app");
4769         pw.println("      --enable-rollback: enable rollbacks for the upgrade.");
4770         pw.println("          0=restore (default), 1=wipe, 2=retain");
4771         if (Flags.recoverabilityDetection()) {
4772             pw.println(
4773                     "      --rollback-impact-level: set device impact required for rollback.");
4774             pw.println("          0=low (default), 1=high, 2=manual only");
4775         }
4776         pw.println("      --install-location: force the install location:");
4777         pw.println("          0=auto, 1=internal only, 2=prefer external");
4778         pw.println("      --install-reason: indicates why the app is being installed:");
4779         pw.println("          0=unknown, 1=admin policy, 2=device restore,");
4780         pw.println("          3=device setup, 4=user request");
4781         pw.println("      --update-ownership: request the update ownership enforcement");
4782         pw.println("      --force-uuid: force install on to disk volume with given UUID");
4783         pw.println("      --apex: install an .apex file, not an .apk");
4784         pw.println("      --non-staged: explicitly set this installation to be non-staged.");
4785         pw.println("          This flag is only useful for APEX installs that are implicitly");
4786         pw.println("          assumed to be staged.");
4787         pw.println("      --force-non-staged: force the installation to run under a non-staged");
4788         pw.println("          session, which may complete without requiring a reboot. This will");
4789         pw.println("          force a rebootless update even for APEXes that don't support it");
4790         pw.println("      --staged-ready-timeout: By default, staged sessions wait "
4791                 + DEFAULT_STAGED_READY_TIMEOUT_MS);
4792         pw.println("          milliseconds for pre-reboot verification to complete when");
4793         pw.println("          performing staged install. This flag is used to alter the waiting");
4794         pw.println("          time. You can skip the waiting time by specifying a TIMEOUT of '0'");
4795         pw.println("      --ignore-dexopt-profile: if set, all profiles are ignored by dexopt");
4796         pw.println("          during the installation, including the profile in the DM file and");
4797         pw.println("          the profile embedded in the APK file. If an invalid profile is");
4798         pw.println("          provided during installation, no warning will be reported by `adb");
4799         pw.println("          install`.");
4800         pw.println("          This option does not affect later dexopt operations (e.g.,");
4801         pw.println("          background dexopt and manual `pm compile` invocations).");
4802         pw.println("      --dexopt-compiler-filter: the target compiler filter for dexopt during");
4803         pw.println("          the installation. The filter actually used may be different.");
4804         pw.println("          Valid values: one of the values documented in");
4805         pw.println("          https://source.android.com/docs/core/runtime/configure"
4806                 + "#compiler_filters");
4807         pw.println("          or 'skip'");
4808         pw.println("");
4809         pw.println("  install-existing [--user USER_ID|all|current]");
4810         pw.println("       [--instant] [--full] [--wait] [--restrict-permissions] PACKAGE");
4811         pw.println("    Installs an existing application for a new user.  Options are:");
4812         pw.println("      --user: install for the given user.");
4813         pw.println("      --instant: install as an instant app");
4814         pw.println("      --full: install as a full app");
4815         pw.println("      --wait: wait until the package is installed");
4816         pw.println("      --restrict-permissions: don't whitelist restricted permissions");
4817         pw.println("");
4818         pw.println("  install-create [-lrtsfdg] [-i PACKAGE] [--user USER_ID|all|current]");
4819         pw.println("       [-p INHERIT_PACKAGE] [--install-location 0/1/2]");
4820         pw.println("       [--install-reason 0/1/2/3/4] [--originating-uri URI]");
4821         pw.println("       [--referrer URI] [--abi ABI_NAME] [--force-sdk]");
4822         pw.println("       [--preload] [--instant] [--full] [--dont-kill]");
4823         pw.println("       [--force-uuid internal|UUID] [--pkg PACKAGE] [--apex] [-S BYTES]");
4824         pw.println("       [--multi-package] [--staged] [--update-ownership]");
4825         pw.println("    Like \"install\", but starts an install session.  Use \"install-write\"");
4826         pw.println("    to push data into the session, and \"install-commit\" to finish.");
4827         pw.println("");
4828         pw.println("  install-write [-S BYTES] SESSION_ID SPLIT_NAME [PATH|-]");
4829         pw.println("    Write an apk into the given install session.  If the path is '-', data");
4830         pw.println("    will be read from stdin.  Options are:");
4831         pw.println("      -S: size in bytes of package, required for stdin");
4832         pw.println("");
4833         pw.println("  install-remove SESSION_ID SPLIT...");
4834         pw.println("    Mark SPLIT(s) as removed in the given install session.");
4835         pw.println("");
4836         pw.println("  install-add-session MULTI_PACKAGE_SESSION_ID CHILD_SESSION_IDs");
4837         pw.println("    Add one or more session IDs to a multi-package session.");
4838         pw.println("");
4839         pw.println("  install-set-pre-verified-domains SESSION_ID PRE_VERIFIED_DOMAIN... ");
4840         pw.println("    Specify a comma separated list of pre-verified domains for a session.");
4841         pw.println("");
4842         pw.println("  install-get-pre-verified-domains SESSION_ID");
4843         pw.println("    List all the pre-verified domains that are specified in a session.");
4844         pw.println("    The result list is comma separated.");
4845         pw.println("");
4846         pw.println("  install-commit SESSION_ID");
4847         pw.println("    Commit the given active install session, installing the app.");
4848         pw.println("");
4849         pw.println("  install-abandon SESSION_ID");
4850         pw.println("    Delete the given active install session.");
4851         pw.println("");
4852         pw.println("  set-install-location LOCATION");
4853         pw.println("    Changes the default install location.  NOTE this is only intended for debugging;");
4854         pw.println("    using this can cause applications to break and other undersireable behavior.");
4855         pw.println("    LOCATION is one of:");
4856         pw.println("    0 [auto]: Let system decide the best location");
4857         pw.println("    1 [internal]: Install on internal device storage");
4858         pw.println("    2 [external]: Install on external media");
4859         pw.println("");
4860         pw.println("  get-install-location");
4861         pw.println("    Returns the current install location: 0, 1 or 2 as per set-install-location.");
4862         pw.println("");
4863         pw.println("  move-package PACKAGE [internal|UUID]");
4864         pw.println("");
4865         pw.println("  move-primary-storage [internal|UUID]");
4866         pw.println("");
4867         pw.println("  uninstall [-k] [--user USER_ID] [--versionCode VERSION_CODE]");
4868         pw.println("       PACKAGE [SPLIT...]");
4869         pw.println("    Remove the given package name from the system.  May remove an entire app");
4870         pw.println("    if no SPLIT names specified, otherwise will remove only the splits of the");
4871         pw.println("    given app.  Options are:");
4872         pw.println("      -k: keep the data and cache directories around after package removal.");
4873         pw.println("      --user: remove the app from the given user.");
4874         pw.println("      --versionCode: only uninstall if the app has the given version code.");
4875         pw.println("");
4876         pw.println("  clear [--user USER_ID] [--cache-only] PACKAGE");
4877         pw.println("    Deletes data associated with a package. Options are:");
4878         pw.println("    --user: specifies the user for which we need to clear data");
4879         pw.println("    --cache-only: a flag which tells if we only need to clear cache data");
4880         pw.println("");
4881         pw.println("  enable [--user USER_ID] PACKAGE_OR_COMPONENT");
4882         pw.println("  disable [--user USER_ID] PACKAGE_OR_COMPONENT");
4883         pw.println("  disable-user [--user USER_ID] PACKAGE_OR_COMPONENT");
4884         pw.println("  disable-until-used [--user USER_ID] PACKAGE_OR_COMPONENT");
4885         pw.println("  default-state [--user USER_ID] PACKAGE_OR_COMPONENT");
4886         pw.println("    These commands change the enabled state of a given package or");
4887         pw.println("    component (written as \"package/class\").");
4888         pw.println("");
4889         pw.println("  hide [--user USER_ID] PACKAGE_OR_COMPONENT");
4890         pw.println("  unhide [--user USER_ID] PACKAGE_OR_COMPONENT");
4891         pw.println("");
4892         pw.println("  unstop [--user USER_ID] PACKAGE");
4893         pw.println("");
4894         pw.println("  suspend [--user USER_ID] PACKAGE [PACKAGE...]");
4895         pw.println("    Suspends the specified package(s) (as user).");
4896         pw.println("");
4897         pw.println("  unsuspend [--user USER_ID] PACKAGE [PACKAGE...]");
4898         pw.println("    Unsuspends the specified package(s) (as user).");
4899         pw.println("");
4900         pw.println("  set-distracting-restriction [--user USER_ID] [--flag FLAG ...]");
4901         pw.println("      PACKAGE [PACKAGE...]");
4902         pw.println("    Sets the specified restriction flags to given package(s) (for user).");
4903         pw.println("    Flags are:");
4904         pw.println("      hide-notifications: Hides notifications from this package");
4905         pw.println("      hide-from-suggestions: Hides this package from suggestions");
4906         pw.println("        (by the launcher, etc.)");
4907         pw.println("    Any existing flags are overwritten, which also means that if no flags are");
4908         pw.println("    specified then all existing flags will be cleared.");
4909         pw.println("");
4910         pw.println("  get-distracting-restriction [--user USER_ID] PACKAGE [PACKAGE...]");
4911         pw.println("    Gets the specified restriction flags of given package(s) (of the user).");
4912         pw.println("");
4913         pw.println("  grant [--user USER_ID] [--all-permissions] PACKAGE PERMISSION");
4914         pw.println("  revoke [--user USER_ID] [--all-permissions] PACKAGE PERMISSION");
4915         pw.println("    These commands either grant or revoke permissions to apps.  The permissions");
4916         pw.println("    must be declared as used in the app's manifest, be runtime permissions");
4917         pw.println("    (protection level dangerous), and the app targeting SDK greater than Lollipop MR1.");
4918         pw.println("    Flags are:");
4919         pw.println("    --user: Specifies the user for which the operation needs to be performed");
4920         pw.println("    --all-permissions: If specified all the missing runtime permissions will");
4921         pw.println("       be granted to the PACKAGE or to all the packages if none is specified.");
4922         pw.println("");
4923         pw.println("  set-permission-flags [--user USER_ID] PACKAGE PERMISSION [FLAGS..]");
4924         pw.println("  clear-permission-flags [--user USER_ID] PACKAGE PERMISSION [FLAGS..]");
4925         pw.println("    These commands either set or clear permission flags on apps.  The permissions");
4926         pw.println("    must be declared as used in the app's manifest, be runtime permissions");
4927         pw.println("    (protection level dangerous), and the app targeting SDK greater than Lollipop MR1.");
4928         pw.println("    The flags must be one or more of " + SUPPORTED_PERMISSION_FLAGS_LIST);
4929         pw.println("");
4930         pw.println("  reset-permissions");
4931         pw.println("    Revert all runtime permissions to their default state.");
4932         pw.println("");
4933         pw.println("  set-permission-enforced PERMISSION [true|false]");
4934         pw.println("");
4935         pw.println("  get-privapp-permissions TARGET-PACKAGE");
4936         pw.println("    Prints all privileged permissions for a package.");
4937         pw.println("");
4938         pw.println("  get-privapp-deny-permissions TARGET-PACKAGE");
4939         pw.println("    Prints all privileged permissions that are denied for a package.");
4940         pw.println("");
4941         pw.println("  get-oem-permissions TARGET-PACKAGE");
4942         pw.println("    Prints all OEM permissions for a package.");
4943         pw.println("");
4944         pw.println("  get-signature-permission-allowlist PARTITION");
4945         pw.println("    Prints the signature permission allowlist for a partition.");
4946         pw.println("    PARTITION is one of system, vendor, product, system-ext and apex");
4947         pw.println("");
4948         pw.println("  get-shared-uid-allowlist");
4949         pw.println("    Prints the shared UID allowlist.");
4950         pw.println("");
4951         pw.println("  trim-caches DESIRED_FREE_SPACE [internal|UUID]");
4952         pw.println("    Trim cache files to reach the given free space.");
4953         pw.println("");
4954         pw.println("  list users");
4955         pw.println("    Lists the current users.");
4956         pw.println("");
4957         pw.println("  create-user [--profileOf USER_ID] [--managed] [--restricted] [--guest]");
4958         pw.println("       [--user-type USER_TYPE] [--ephemeral] [--for-testing] [--pre-create-only]   USER_NAME");
4959         pw.println("    Create a new user with the given USER_NAME, printing the new user identifier");
4960         pw.println("    of the user.");
4961         // TODO(b/142482943): Consider fetching the list of user types from UMS.
4962         pw.println("    USER_TYPE is the name of a user type, e.g. android.os.usertype.profile.MANAGED.");
4963         pw.println("      If not specified, the default user type is android.os.usertype.full.SECONDARY.");
4964         pw.println("      --managed is shorthand for '--user-type android.os.usertype.profile.MANAGED'.");
4965         pw.println("      --restricted is shorthand for '--user-type android.os.usertype.full.RESTRICTED'.");
4966         pw.println("      --guest is shorthand for '--user-type android.os.usertype.full.GUEST'.");
4967         pw.println("");
4968         pw.println("  remove-user [--set-ephemeral-if-in-use | --wait] USER_ID");
4969         pw.println("    Remove the user with the given USER_IDENTIFIER, deleting all data");
4970         pw.println("    associated with that user.");
4971         pw.println("      --set-ephemeral-if-in-use: If the user is currently running and");
4972         pw.println("        therefore cannot be removed immediately, mark the user as ephemeral");
4973         pw.println("        so that it will be automatically removed when possible (after user");
4974         pw.println("        switch or reboot)");
4975         pw.println("      --wait: Wait until user is removed. Ignored if set-ephemeral-if-in-use");
4976         pw.println("");
4977         pw.println("  mark-guest-for-deletion USER_ID");
4978         pw.println("    Mark the guest user for deletion. After this, it is possible to create a");
4979         pw.println("    new guest user and switch to it. This allows resetting the guest user");
4980         pw.println("    without switching to another user.");
4981         pw.println("");
4982         pw.println("  rename-user USER_ID [USER_NAME]");
4983         pw.println("    Rename USER_ID with USER_NAME (or null when [USER_NAME] is not set)");
4984         pw.println("");
4985         pw.println("  set-user-restriction [--user USER_ID] RESTRICTION VALUE");
4986         pw.println("");
4987         pw.println("  get-user-restriction [--user USER_ID] [--all] RESTRICTION_KEY");
4988         pw.println("    Display the value of restriction for the given restriction key if the");
4989         pw.println("    given user is valid.");
4990         pw.println("      --all: display all restrictions for the given user");
4991         pw.println("          This option is used without restriction key");
4992         pw.println("");
4993         pw.println("  get-max-users");
4994         pw.println("");
4995         pw.println("  get-max-running-users");
4996         pw.println("");
4997         pw.println("  set-home-activity [--user USER_ID] TARGET-COMPONENT");
4998         pw.println("    Set the default home activity (aka launcher).");
4999         pw.println("    TARGET-COMPONENT can be a package name (com.package.my) or a full");
5000         pw.println("    component (com.package.my/component.name). However, only the package name");
5001         pw.println("    matters: the actual component used will be determined automatically from");
5002         pw.println("    the package.");
5003         pw.println("");
5004         pw.println("  set-installer PACKAGE INSTALLER");
5005         pw.println("    Set installer package name");
5006         pw.println("");
5007         pw.println("  get-instantapp-resolver");
5008         pw.println(
5009                 "    Return the name of the component that is the current instant app installer.");
5010         pw.println("");
5011         pw.println("  set-harmful-app-warning [--user <USER_ID>] <PACKAGE> [<WARNING>]");
5012         pw.println("    Mark the app as harmful with the given warning message.");
5013         pw.println("");
5014         pw.println("  get-harmful-app-warning [--user <USER_ID>] <PACKAGE>");
5015         pw.println("    Return the harmful app warning message for the given app, if present");
5016         pw.println();
5017         pw.println("  uninstall-system-updates [<PACKAGE>]");
5018         pw.println("    Removes updates to the given system application and falls back to its");
5019         pw.println("    /system version. Does nothing if the given package is not a system app.");
5020         pw.println("    If no package is specified, removes updates to all system applications.");
5021         pw.println("");
5022         pw.println("  get-moduleinfo [--all | --installed] [module-name]");
5023         pw.println("    Displays module info. If module-name is specified only that info is shown");
5024         pw.println("    By default, without any argument only installed modules are shown.");
5025         pw.println("      --all: show all module info");
5026         pw.println("      --installed: show only installed modules");
5027         pw.println("");
5028         pw.println("  log-visibility [--enable|--disable] <PACKAGE>");
5029         pw.println("    Turns on debug logging when visibility is blocked for the given package.");
5030         pw.println("      --enable: turn on debug logging (default)");
5031         pw.println("      --disable: turn off debug logging");
5032         pw.println("");
5033         pw.println("  set-silent-updates-policy [--allow-unlimited-silent-updates <INSTALLER>]");
5034         pw.println("                            [--throttle-time <SECONDS>] [--reset]");
5035         pw.println("    Sets the policies of the silent updates.");
5036         pw.println("      --allow-unlimited-silent-updates: allows unlimited silent updated");
5037         pw.println("        installation requests from the installer without the throttle time.");
5038         pw.println("      --throttle-time: update the silent updates throttle time in seconds.");
5039         pw.println("      --reset: restore the installer and throttle time to the default, and");
5040         pw.println("        clear tracks of silent updates in the system.");
5041         pw.println("");
5042         pw.println("  clear-package-preferred-activities <PACKAGE>");
5043         pw.println("    Remove the preferred activity mappings for the given package.");
5044         pw.println("  wait-for-handler --timeout <MILLIS>");
5045         pw.println("    Wait for a given amount of time till the package manager handler finishes");
5046         pw.println("    handling all pending messages.");
5047         pw.println("      --timeout: wait for a given number of milliseconds. If the handler(s)");
5048         pw.println("        fail to finish before the timeout, the command returns error.");
5049         pw.println("");
5050         pw.println("  wait-for-background-handler --timeout <MILLIS>");
5051         pw.println("    Wait for a given amount of time till the package manager's background");
5052         pw.println("    handler finishes handling all pending messages.");
5053         pw.println("      --timeout: wait for a given number of milliseconds. If the handler(s)");
5054         pw.println("        fail to finish before the timeout, the command returns error.");
5055         pw.println("");
5056         pw.println("  archive [--user USER_ID] PACKAGE ");
5057         pw.println("    During the archival process, the apps APKs and cache are removed from the");
5058         pw.println("    device while the user data is kept. Options are:");
5059         pw.println("      --user: archive the app from the given user.");
5060         pw.println("");
5061         pw.println("  request-unarchive [--user USER_ID] PACKAGE ");
5062         pw.println("    Requests to unarchive a currently archived package by sending a request");
5063         pw.println("    to unarchive an app to the responsible installer. Options are:");
5064         pw.println("      --user: request unarchival of the app from the given user.");
5065         pw.println("");
5066         pw.println("  get-domain-verification-agent [--user USER_ID]");
5067         pw.println("    Displays the component name of the domain verification agent on device.");
5068         pw.println("    If the component isn't enabled, an error message will be displayed.");
5069         pw.println("      --user: return the agent of the given user (SYSTEM_USER if unspecified)");
5070         pw.println("  get-package-storage-stats [--user <USER_ID>] <PACKAGE>");
5071         pw.println("    Return the storage stats for the given app, if present");
5072         pw.println("");
5073         printArtServiceHelp();
5074         pw.println("");
5075         mDomainVerificationShell.printHelp(pw);
5076         pw.println("");
5077         Intent.printIntentArgsHelp(pw, "");
5078     }
5079 
printArtServiceHelp()5080     private void printArtServiceHelp() {
5081         final var ipw = new IndentingPrintWriter(getOutPrintWriter(), "  " /* singleIndent */);
5082         ipw.increaseIndent();
5083         try {
5084             LocalManagerRegistry.getManagerOrThrow(ArtManagerLocal.class)
5085                     .printShellCommandHelp(ipw);
5086         } catch (ManagerNotFoundException e) {
5087             ipw.println("ART Service is not ready. Please try again later");
5088         }
5089         ipw.decreaseIndent();
5090     }
5091 
5092     private static class LocalIntentReceiver {
5093         private final LinkedBlockingQueue<Intent> mResult = new LinkedBlockingQueue<>();
5094 
5095         private final IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
5096             @Override
5097             public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
5098                     IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
5099                 try {
5100                     mResult.offer(intent, 5, TimeUnit.SECONDS);
5101                 } catch (InterruptedException e) {
5102                     throw new RuntimeException(e);
5103                 }
5104             }
5105         };
5106 
getIntentSender()5107         public IntentSender getIntentSender() {
5108             return new IntentSender((IIntentSender) mLocalSender);
5109         }
5110 
getResult()5111         public Intent getResult() {
5112             try {
5113                 return mResult.take();
5114             } catch (InterruptedException e) {
5115                 throw new RuntimeException(e);
5116             }
5117         }
5118     }
5119 }
5120