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