1 /*
2  * Copyright (C) 2014 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 android.content.pm;
18 
19 import static android.app.AppOpsManager.MODE_ALLOWED;
20 import static android.app.AppOpsManager.MODE_DEFAULT;
21 import static android.app.AppOpsManager.MODE_IGNORED;
22 import static android.content.pm.Checksum.TYPE_PARTIAL_MERKLE_ROOT_1M_SHA256;
23 import static android.content.pm.Checksum.TYPE_PARTIAL_MERKLE_ROOT_1M_SHA512;
24 import static android.content.pm.Checksum.TYPE_WHOLE_MD5;
25 import static android.content.pm.Checksum.TYPE_WHOLE_MERKLE_ROOT_4K_SHA256;
26 import static android.content.pm.Checksum.TYPE_WHOLE_SHA1;
27 import static android.content.pm.Checksum.TYPE_WHOLE_SHA256;
28 import static android.content.pm.Checksum.TYPE_WHOLE_SHA512;
29 import static android.content.pm.PackageInfo.INSTALL_LOCATION_AUTO;
30 import static android.content.pm.PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY;
31 import static android.content.pm.PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL;
32 
33 import android.Manifest;
34 import android.annotation.CallbackExecutor;
35 import android.annotation.CurrentTimeMillisLong;
36 import android.annotation.DurationMillisLong;
37 import android.annotation.IntDef;
38 import android.annotation.NonNull;
39 import android.annotation.Nullable;
40 import android.annotation.RequiresPermission;
41 import android.annotation.SdkConstant;
42 import android.annotation.SdkConstant.SdkConstantType;
43 import android.annotation.SuppressLint;
44 import android.annotation.SystemApi;
45 import android.annotation.TestApi;
46 import android.app.ActivityManager;
47 import android.app.ActivityThread;
48 import android.app.AppGlobals;
49 import android.compat.annotation.UnsupportedAppUsage;
50 import android.content.IIntentReceiver;
51 import android.content.IIntentSender;
52 import android.content.Intent;
53 import android.content.IntentSender;
54 import android.content.pm.PackageManager.DeleteFlags;
55 import android.content.pm.PackageManager.InstallReason;
56 import android.content.pm.PackageManager.InstallScenario;
57 import android.content.pm.parsing.ApkLiteParseUtils;
58 import android.content.pm.parsing.PackageLite;
59 import android.content.pm.parsing.result.ParseResult;
60 import android.content.pm.parsing.result.ParseTypeImpl;
61 import android.graphics.Bitmap;
62 import android.icu.util.ULocale;
63 import android.net.Uri;
64 import android.os.Build;
65 import android.os.Bundle;
66 import android.os.FileBridge;
67 import android.os.Handler;
68 import android.os.HandlerExecutor;
69 import android.os.IBinder;
70 import android.os.Parcel;
71 import android.os.ParcelFileDescriptor;
72 import android.os.Parcelable;
73 import android.os.ParcelableException;
74 import android.os.PersistableBundle;
75 import android.os.RemoteCallback;
76 import android.os.RemoteException;
77 import android.os.SystemProperties;
78 import android.os.UserHandle;
79 import android.system.ErrnoException;
80 import android.system.Os;
81 import android.text.TextUtils;
82 import android.util.ArrayMap;
83 import android.util.ArraySet;
84 import android.util.ExceptionUtils;
85 
86 import com.android.internal.content.InstallLocationUtils;
87 import com.android.internal.util.ArrayUtils;
88 import com.android.internal.util.DataClass;
89 import com.android.internal.util.IndentingPrintWriter;
90 import com.android.internal.util.Preconditions;
91 import com.android.internal.util.function.pooled.PooledLambda;
92 
93 import java.io.Closeable;
94 import java.io.File;
95 import java.io.FileNotFoundException;
96 import java.io.IOException;
97 import java.io.InputStream;
98 import java.io.OutputStream;
99 import java.lang.annotation.Retention;
100 import java.lang.annotation.RetentionPolicy;
101 import java.security.MessageDigest;
102 import java.security.cert.Certificate;
103 import java.security.cert.CertificateEncodingException;
104 import java.security.cert.X509Certificate;
105 import java.util.ArrayList;
106 import java.util.Collection;
107 import java.util.Collections;
108 import java.util.Iterator;
109 import java.util.List;
110 import java.util.Objects;
111 import java.util.Set;
112 import java.util.concurrent.Executor;
113 import java.util.function.Consumer;
114 
115 /**
116  * Offers the ability to install, upgrade, and remove applications on the
117  * device. This includes support for apps packaged either as a single
118  * "monolithic" APK, or apps packaged as multiple "split" APKs.
119  * <p>
120  * An app is delivered for installation through a
121  * {@link PackageInstaller.Session}, which any app can create. Once the session
122  * is created, the installer can stream one or more APKs into place until it
123  * decides to either commit or destroy the session. Committing may require user
124  * intervention to complete the installation, unless the caller falls into one of the
125  * following categories, in which case the installation will complete automatically.
126  * <ul>
127  * <li>the device owner
128  * <li>the affiliated profile owner
129  * </ul>
130  * <p>
131  * Sessions can install brand new apps, upgrade existing apps, or add new splits
132  * into an existing app.
133  * <p>
134  * Apps packaged as multiple split APKs always consist of a single "base" APK
135  * (with a {@code null} split name) and zero or more "split" APKs (with unique
136  * split names). Any subset of these APKs can be installed together, as long as
137  * the following constraints are met:
138  * <ul>
139  * <li>All APKs must have the exact same package name, version code, and signing
140  * certificates.
141  * <li>All APKs must have unique split names.
142  * <li>All installations must contain a single base APK.
143  * </ul>
144  * <p>
145  * The ApiDemos project contains examples of using this API:
146  * <code>ApiDemos/src/com/example/android/apis/content/InstallApk*.java</code>.
147  */
148 public class PackageInstaller {
149     private static final String TAG = "PackageInstaller";
150 
151     /** {@hide} */
152     public static final boolean ENABLE_REVOCABLE_FD =
153             SystemProperties.getBoolean("fw.revocable_fd", false);
154 
155     /**
156      * Activity Action: Show details about a particular install session. This
157      * may surface actions such as pause, resume, or cancel.
158      * <p>
159      * This should always be scoped to the installer package that owns the
160      * session. Clients should use {@link SessionInfo#createDetailsIntent()} to
161      * build this intent correctly.
162      * <p>
163      * In some cases, a matching Activity may not exist, so ensure you safeguard
164      * against this.
165      * <p>
166      * The session to show details for is defined in {@link #EXTRA_SESSION_ID}.
167      */
168     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
169     public static final String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS";
170 
171     /**
172      * Broadcast Action: Explicit broadcast sent to the last known default launcher when a session
173      * for a new install is committed. For managed profile, this is sent to the default launcher
174      * of the primary profile.
175      * <p>
176      * The associated session is defined in {@link #EXTRA_SESSION} and the user for which this
177      * session was created in {@link Intent#EXTRA_USER}.
178      */
179     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
180     public static final String ACTION_SESSION_COMMITTED =
181             "android.content.pm.action.SESSION_COMMITTED";
182 
183     /**
184      * Broadcast Action: Send information about a staged install session when its state is updated.
185      * <p>
186      * The associated session information is defined in {@link #EXTRA_SESSION}.
187      */
188     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
189     public static final String ACTION_SESSION_UPDATED =
190             "android.content.pm.action.SESSION_UPDATED";
191 
192     /**
193      * Intent action to indicate that user action is required for current install. This action can
194      * be used only by system apps.
195      *
196      * @hide
197      */
198     @SystemApi
199     public static final String ACTION_CONFIRM_INSTALL = "android.content.pm.action.CONFIRM_INSTALL";
200 
201     /**
202      * Activity Action: Intent sent to the installer when a session for requesting
203      * user pre-approval, and user needs to confirm the installation.
204      *
205      * @hide
206      */
207     @SystemApi
208     public static final String ACTION_CONFIRM_PRE_APPROVAL =
209             "android.content.pm.action.CONFIRM_PRE_APPROVAL";
210 
211     /**
212      * An integer session ID that an operation is working with.
213      *
214      * @see Intent#getIntExtra(String, int)
215      */
216     public static final String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID";
217 
218     /**
219      * {@link SessionInfo} that an operation is working with.
220      *
221      * @see Intent#getParcelableExtra(String)
222      */
223     public static final String EXTRA_SESSION = "android.content.pm.extra.SESSION";
224 
225     /**
226      * Package name that an operation is working with.
227      *
228      * @see Intent#getStringExtra(String)
229      */
230     public static final String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME";
231 
232     /**
233      * Current status of an operation. Will be one of
234      * {@link #STATUS_PENDING_USER_ACTION}, {@link #STATUS_SUCCESS},
235      * {@link #STATUS_FAILURE}, {@link #STATUS_FAILURE_ABORTED},
236      * {@link #STATUS_FAILURE_BLOCKED}, {@link #STATUS_FAILURE_CONFLICT},
237      * {@link #STATUS_FAILURE_INCOMPATIBLE}, {@link #STATUS_FAILURE_INVALID},
238      * {@link #STATUS_FAILURE_STORAGE}, or {@link #STATUS_FAILURE_TIMEOUT}.
239      * <p>
240      * More information about a status may be available through additional
241      * extras; see the individual status documentation for details.
242      *
243      * @see Intent#getIntExtra(String, int)
244      */
245     public static final String EXTRA_STATUS = "android.content.pm.extra.STATUS";
246 
247     /**
248      * Indicate if the status is for a pre-approval request.
249      *
250      * If callers use the same {@link IntentSender} for both
251      * {@link Session#requestUserPreapproval(PreapprovalDetails, IntentSender)} and
252      * {@link Session#commit(IntentSender)}, they can use this to differentiate between them.
253      *
254      * @see Intent#getBooleanExtra(String, boolean)
255      */
256     public static final String EXTRA_PRE_APPROVAL = "android.content.pm.extra.PRE_APPROVAL";
257 
258     /**
259      * Detailed string representation of the status, including raw details that
260      * are useful for debugging.
261      *
262      * @see Intent#getStringExtra(String)
263      */
264     public static final String EXTRA_STATUS_MESSAGE = "android.content.pm.extra.STATUS_MESSAGE";
265 
266     /**
267      * Another package name relevant to a status. This is typically the package
268      * responsible for causing an operation failure.
269      *
270      * @see Intent#getStringExtra(String)
271      */
272     public static final String
273             EXTRA_OTHER_PACKAGE_NAME = "android.content.pm.extra.OTHER_PACKAGE_NAME";
274 
275     /**
276      * Storage path relevant to a status.
277      *
278      * @see Intent#getStringExtra(String)
279      */
280     public static final String EXTRA_STORAGE_PATH = "android.content.pm.extra.STORAGE_PATH";
281 
282     /**
283      * The {@link InstallConstraints} object.
284      *
285      * @see Intent#getParcelableExtra(String, Class)
286      * @see #waitForInstallConstraints(List, InstallConstraints, IntentSender, long)
287      */
288     public static final String EXTRA_INSTALL_CONSTRAINTS =
289             "android.content.pm.extra.INSTALL_CONSTRAINTS";
290 
291     /**
292      * The {@link InstallConstraintsResult} object.
293      *
294      * @see Intent#getParcelableExtra(String, Class)
295      * @see #waitForInstallConstraints(List, InstallConstraints, IntentSender, long)
296      */
297     public static final String EXTRA_INSTALL_CONSTRAINTS_RESULT =
298             "android.content.pm.extra.INSTALL_CONSTRAINTS_RESULT";
299 
300     /** {@hide} */
301     @Deprecated
302     public static final String EXTRA_PACKAGE_NAMES = "android.content.pm.extra.PACKAGE_NAMES";
303 
304     /**
305      * The status as used internally in the package manager. Refer to {@link PackageManager} for
306      * a list of all valid legacy statuses.
307      *
308      * @hide
309      */
310     @SystemApi
311     public static final String EXTRA_LEGACY_STATUS = "android.content.pm.extra.LEGACY_STATUS";
312     /** {@hide} */
313     public static final String EXTRA_LEGACY_BUNDLE = "android.content.pm.extra.LEGACY_BUNDLE";
314     /**
315      * The callback to execute once an uninstall is completed (used for both successful and
316      * unsuccessful uninstalls).
317      *
318      * @hide
319      */
320     @SystemApi
321     public static final String EXTRA_CALLBACK = "android.content.pm.extra.CALLBACK";
322 
323     /**
324      * Type of DataLoader for this session. Will be one of
325      * {@link #DATA_LOADER_TYPE_NONE}, {@link #DATA_LOADER_TYPE_STREAMING},
326      * {@link #DATA_LOADER_TYPE_INCREMENTAL}.
327      * <p>
328      * See the individual types documentation for details.
329      *
330      * @see Intent#getIntExtra(String, int)
331      * {@hide}
332      */
333     @SystemApi
334     public static final String EXTRA_DATA_LOADER_TYPE = "android.content.pm.extra.DATA_LOADER_TYPE";
335 
336     /**
337      * Path to the validated base APK for this session, which may point at an
338      * APK inside the session (when the session defines the base), or it may
339      * point at the existing base APK (when adding splits to an existing app).
340      *
341      * @hide
342      */
343     @SystemApi
344     public static final String EXTRA_RESOLVED_BASE_PATH =
345             "android.content.pm.extra.RESOLVED_BASE_PATH";
346 
347     /**
348      * Streaming installation pending.
349      * Caller should make sure DataLoader is able to prepare image and reinitiate the operation.
350      *
351      * @see #EXTRA_SESSION_ID
352      * {@hide}
353      */
354     public static final int STATUS_PENDING_STREAMING = -2;
355 
356     /**
357      * User action is currently required to proceed. You can launch the intent
358      * activity described by {@link Intent#EXTRA_INTENT} to involve the user and
359      * continue.
360      * <p>
361      * You may choose to immediately launch the intent if the user is actively
362      * using your app. Otherwise, you should use a notification to guide the
363      * user back into your app before launching.
364      *
365      * @see Intent#getParcelableExtra(String)
366      */
367     public static final int STATUS_PENDING_USER_ACTION = -1;
368 
369     /**
370      * The operation succeeded.
371      */
372     public static final int STATUS_SUCCESS = 0;
373 
374     /**
375      * The operation failed in a generic way. The system will always try to
376      * provide a more specific failure reason, but in some rare cases this may
377      * be delivered.
378      *
379      * @see #EXTRA_STATUS_MESSAGE
380      */
381     public static final int STATUS_FAILURE = 1;
382 
383     /**
384      * The operation failed because it was blocked. For example, a device policy
385      * may be blocking the operation, a package verifier may have blocked the
386      * operation, or the app may be required for core system operation.
387      * <p>
388      * The result may also contain {@link #EXTRA_OTHER_PACKAGE_NAME} with the
389      * specific package blocking the install.
390      *
391      * @see #EXTRA_STATUS_MESSAGE
392      * @see #EXTRA_OTHER_PACKAGE_NAME
393      */
394     public static final int STATUS_FAILURE_BLOCKED = 2;
395 
396     /**
397      * The operation failed because it was actively aborted. For example, the
398      * user actively declined requested permissions, or the session was
399      * abandoned.
400      *
401      * @see #EXTRA_STATUS_MESSAGE
402      */
403     public static final int STATUS_FAILURE_ABORTED = 3;
404 
405     /**
406      * The operation failed because one or more of the APKs was invalid. For
407      * example, they might be malformed, corrupt, incorrectly signed,
408      * mismatched, etc.
409      *
410      * @see #EXTRA_STATUS_MESSAGE
411      */
412     public static final int STATUS_FAILURE_INVALID = 4;
413 
414     /**
415      * The operation failed because it conflicts (or is inconsistent with) with
416      * another package already installed on the device. For example, an existing
417      * permission, incompatible certificates, etc. The user may be able to
418      * uninstall another app to fix the issue.
419      * <p>
420      * The result may also contain {@link #EXTRA_OTHER_PACKAGE_NAME} with the
421      * specific package identified as the cause of the conflict.
422      *
423      * @see #EXTRA_STATUS_MESSAGE
424      * @see #EXTRA_OTHER_PACKAGE_NAME
425      */
426     public static final int STATUS_FAILURE_CONFLICT = 5;
427 
428     /**
429      * The operation failed because of storage issues. For example, the device
430      * may be running low on space, or external media may be unavailable. The
431      * user may be able to help free space or insert different external media.
432      * <p>
433      * The result may also contain {@link #EXTRA_STORAGE_PATH} with the path to
434      * the storage device that caused the failure.
435      *
436      * @see #EXTRA_STATUS_MESSAGE
437      * @see #EXTRA_STORAGE_PATH
438      */
439     public static final int STATUS_FAILURE_STORAGE = 6;
440 
441     /**
442      * The operation failed because it is fundamentally incompatible with this
443      * device. For example, the app may require a hardware feature that doesn't
444      * exist, it may be missing native code for the ABIs supported by the
445      * device, or it requires a newer SDK version, etc.
446      *
447      * Starting in {@link Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, an app with only 32-bit native
448      * code can still be installed on a device that supports both 64-bit and 32-bit ABIs.
449      * However, a warning dialog will be displayed when the app is launched.
450      *
451      * @see #EXTRA_STATUS_MESSAGE
452      */
453     public static final int STATUS_FAILURE_INCOMPATIBLE = 7;
454 
455     /**
456      * The operation failed because it didn't complete within the specified timeout.
457      *
458      * @see #EXTRA_STATUS_MESSAGE
459      */
460     public static final int STATUS_FAILURE_TIMEOUT = 8;
461 
462     /**
463      * Default value, non-streaming installation session.
464      *
465      * @see #EXTRA_DATA_LOADER_TYPE
466      * {@hide}
467      */
468     @SystemApi
469     public static final int DATA_LOADER_TYPE_NONE = DataLoaderType.NONE;
470 
471     /**
472      * Streaming installation using data loader.
473      *
474      * @see #EXTRA_DATA_LOADER_TYPE
475      * {@hide}
476      */
477     @SystemApi
478     public static final int DATA_LOADER_TYPE_STREAMING = DataLoaderType.STREAMING;
479 
480     /**
481      * Streaming installation using Incremental FileSystem.
482      *
483      * @see #EXTRA_DATA_LOADER_TYPE
484      * {@hide}
485      */
486     @SystemApi
487     public static final int DATA_LOADER_TYPE_INCREMENTAL = DataLoaderType.INCREMENTAL;
488 
489     /**
490      * Target location for the file in installation session is /data/app/<packageName>-<id>.
491      * This is the intended location for APKs.
492      * Requires permission to install packages.
493      * {@hide}
494      */
495     @SystemApi
496     public static final int LOCATION_DATA_APP = InstallationFileLocation.DATA_APP;
497 
498     /**
499      * Target location for the file in installation session is
500      * /data/media/<userid>/Android/obb/<packageName>. This is the intended location for OBBs.
501      * {@hide}
502      */
503     @SystemApi
504     public static final int LOCATION_MEDIA_OBB = InstallationFileLocation.MEDIA_OBB;
505 
506     /**
507      * Target location for the file in installation session is
508      * /data/media/<userid>/Android/data/<packageName>.
509      * This is the intended location for application data.
510      * Can only be used by an app itself running under specific user.
511      * {@hide}
512      */
513     @SystemApi
514     public static final int LOCATION_MEDIA_DATA = InstallationFileLocation.MEDIA_DATA;
515 
516     /** @hide */
517     @IntDef(prefix = { "LOCATION_" }, value = {
518             LOCATION_DATA_APP,
519             LOCATION_MEDIA_OBB,
520             LOCATION_MEDIA_DATA})
521     @Retention(RetentionPolicy.SOURCE)
522     public @interface FileLocation{}
523 
524     /**
525      * The installer did not call {@link PackageInstaller.SessionParams#setPackageSource(int)} to
526      * specify the package source.
527      */
528     public static final int PACKAGE_SOURCE_UNSPECIFIED = 0;
529 
530     /**
531      * Code indicating that the package being installed is from a source not reflected by any
532      * other package source constant.
533      */
534     public static final int PACKAGE_SOURCE_OTHER = 1;
535 
536     /**
537      * Code indicating that the package being installed is from a store. An app store that
538      * installs an app for the user would use this.
539      */
540     public static final int PACKAGE_SOURCE_STORE = 2;
541 
542     /**
543      * Code indicating that the package being installed comes from a local file on the device. A
544      * file manager that is facilitating the installation of an APK file would use this.
545      */
546     public static final int PACKAGE_SOURCE_LOCAL_FILE = 3;
547 
548     /**
549      * Code indicating that the package being installed comes from a file that was downloaded to
550      * the device by the user. For use in place of {@link #PACKAGE_SOURCE_LOCAL_FILE} when the
551      * installer knows the package was downloaded.
552      */
553     public static final int PACKAGE_SOURCE_DOWNLOADED_FILE = 4;
554 
555     /** @hide */
556     @IntDef(prefix = { "PACKAGE_SOURCE_" }, value = {
557             PACKAGE_SOURCE_UNSPECIFIED,
558             PACKAGE_SOURCE_STORE,
559             PACKAGE_SOURCE_LOCAL_FILE,
560             PACKAGE_SOURCE_DOWNLOADED_FILE,
561             PACKAGE_SOURCE_OTHER
562     })
563     @Retention(RetentionPolicy.SOURCE)
564     @interface PackageSourceType{}
565 
566     /**
567      * Indicate the user intervention is required when the installer attempts to commit the session.
568      * This is the default case.
569      *
570      * @hide
571      */
572     @SystemApi
573     public static final int REASON_CONFIRM_PACKAGE_CHANGE = 0;
574 
575     /**
576      * Indicate the user intervention is required because the update ownership enforcement is
577      * enabled, and the update owner will change.
578      *
579      * @see PackageInstaller.SessionParams#setRequestUpdateOwnership
580      * @see InstallSourceInfo#getUpdateOwnerPackageName
581      * @hide
582      */
583     @SystemApi
584     public static final int REASON_OWNERSHIP_CHANGED = 1;
585 
586     /**
587      * Indicate the user intervention is required because the update ownership enforcement is
588      * enabled, and remind the update owner is a different package.
589      *
590      * @see PackageInstaller.SessionParams#setRequestUpdateOwnership
591      * @see InstallSourceInfo#getUpdateOwnerPackageName
592      * @hide
593      */
594     @SystemApi
595     public static final int REASON_REMIND_OWNERSHIP = 2;
596 
597     /** @hide */
598     @IntDef(prefix = { "REASON_" }, value = {
599             REASON_CONFIRM_PACKAGE_CHANGE,
600             REASON_OWNERSHIP_CHANGED,
601             REASON_REMIND_OWNERSHIP,
602     })
603     @Retention(RetentionPolicy.SOURCE)
604     public @interface UserActionReason {}
605 
606     /** Default set of checksums - includes all available checksums.
607      * @see Session#requestChecksums  */
608     private static final int DEFAULT_CHECKSUMS =
609             TYPE_WHOLE_MERKLE_ROOT_4K_SHA256 | TYPE_WHOLE_MD5 | TYPE_WHOLE_SHA1 | TYPE_WHOLE_SHA256
610                     | TYPE_WHOLE_SHA512 | TYPE_PARTIAL_MERKLE_ROOT_1M_SHA256
611                     | TYPE_PARTIAL_MERKLE_ROOT_1M_SHA512;
612 
613     private final IPackageInstaller mInstaller;
614     private final int mUserId;
615     private final String mInstallerPackageName;
616     private final String mAttributionTag;
617 
618     private final ArrayList<SessionCallbackDelegate> mDelegates = new ArrayList<>();
619 
620     /** {@hide} */
PackageInstaller(IPackageInstaller installer, String installerPackageName, String installerAttributionTag, int userId)621     public PackageInstaller(IPackageInstaller installer,
622             String installerPackageName, String installerAttributionTag, int userId) {
623         Objects.requireNonNull(installer, "installer cannot be null");
624         mInstaller = installer;
625         mInstallerPackageName = installerPackageName;
626         mAttributionTag = installerAttributionTag;
627         mUserId = userId;
628     }
629 
630     /**
631      * Create a new session using the given parameters, returning a unique ID
632      * that represents the session. Once created, the session can be opened
633      * multiple times across multiple device boots.
634      * <p>
635      * The system may automatically destroy sessions that have not been
636      * finalized (either committed or abandoned) within a reasonable period of
637      * time, typically on the order of a day.
638      *
639      * @throws IOException if parameters were unsatisfiable, such as lack of
640      *             disk space or unavailable media.
641      * @throws SecurityException when installation services are unavailable,
642      *             such as when called from a restricted user.
643      * @throws IllegalArgumentException when {@link SessionParams} is invalid.
644      * @return positive, non-zero unique ID that represents the created session.
645      *         This ID remains consistent across device reboots until the
646      *         session is finalized. IDs are not reused during a given boot.
647      */
createSession(@onNull SessionParams params)648     public int createSession(@NonNull SessionParams params) throws IOException {
649         try {
650             return mInstaller.createSession(params, mInstallerPackageName, mAttributionTag,
651                     mUserId);
652         } catch (RuntimeException e) {
653             ExceptionUtils.maybeUnwrapIOException(e);
654             throw e;
655         } catch (RemoteException e) {
656             throw e.rethrowFromSystemServer();
657         }
658     }
659 
660     /**
661      * Open an existing session to actively perform work. To succeed, the caller
662      * must be the owner of the install session.
663      *
664      * @throws IOException if parameters were unsatisfiable, such as lack of
665      *             disk space or unavailable media.
666      * @throws SecurityException when the caller does not own the session, or
667      *             the session is invalid.
668      */
openSession(int sessionId)669     public @NonNull Session openSession(int sessionId) throws IOException {
670         try {
671             try {
672                 return new Session(mInstaller.openSession(sessionId));
673             } catch (RemoteException e) {
674                 throw e.rethrowFromSystemServer();
675             }
676         } catch (RuntimeException e) {
677             ExceptionUtils.maybeUnwrapIOException(e);
678             throw e;
679         }
680     }
681 
682     /**
683      * Update the icon representing the app being installed in a specific
684      * session. This should be roughly
685      * {@link ActivityManager#getLauncherLargeIconSize()} in both dimensions.
686      *
687      * @throws SecurityException when the caller does not own the session, or
688      *             the session is invalid.
689      */
updateSessionAppIcon(int sessionId, @Nullable Bitmap appIcon)690     public void updateSessionAppIcon(int sessionId, @Nullable Bitmap appIcon) {
691         try {
692             mInstaller.updateSessionAppIcon(sessionId, appIcon);
693         } catch (RemoteException e) {
694             throw e.rethrowFromSystemServer();
695         }
696     }
697 
698     /**
699      * Update the label representing the app being installed in a specific
700      * session.
701      *
702      * @throws SecurityException when the caller does not own the session, or
703      *             the session is invalid.
704      */
updateSessionAppLabel(int sessionId, @Nullable CharSequence appLabel)705     public void updateSessionAppLabel(int sessionId, @Nullable CharSequence appLabel) {
706         try {
707             final String val = (appLabel != null) ? appLabel.toString() : null;
708             mInstaller.updateSessionAppLabel(sessionId, val);
709         } catch (RemoteException e) {
710             throw e.rethrowFromSystemServer();
711         }
712     }
713 
714     /**
715      * Completely abandon the given session, destroying all staged data and
716      * rendering it invalid. Abandoned sessions will be reported to
717      * {@link SessionCallback} listeners as failures. This is equivalent to
718      * opening the session and calling {@link Session#abandon()}.
719      *
720      * @throws SecurityException when the caller does not own the session, or
721      *             the session is invalid.
722      */
abandonSession(int sessionId)723     public void abandonSession(int sessionId) {
724         try {
725             mInstaller.abandonSession(sessionId);
726         } catch (RemoteException e) {
727             throw e.rethrowFromSystemServer();
728         }
729     }
730 
731     /**
732      * Return details for a specific session. Callers need to either declare &lt;queries&gt;
733      * element with the specific package name in the app's manifest, have the
734      * android.permission.QUERY_ALL_PACKAGES, or be the session owner to retrieve these details.
735      *
736      * @return details for the requested session, or {@code null} if the session
737      *         does not exist.
738      */
getSessionInfo(int sessionId)739     public @Nullable SessionInfo getSessionInfo(int sessionId) {
740         try {
741             return mInstaller.getSessionInfo(sessionId);
742         } catch (RemoteException e) {
743             throw e.rethrowFromSystemServer();
744         }
745     }
746 
747     /**
748      * Return list of all known install sessions, regardless of the installer. Callers need to
749      * either declare &lt;queries&gt; element with the specific  package name in the app's manifest,
750      * have the android.permission.QUERY_ALL_PACKAGES, or be the session owner to retrieve these
751      * details.
752      */
getAllSessions()753     public @NonNull List<SessionInfo> getAllSessions() {
754         try {
755             return mInstaller.getAllSessions(mUserId).getList();
756         } catch (RemoteException e) {
757             throw e.rethrowFromSystemServer();
758         }
759     }
760 
761     /**
762      * Return list of all known install sessions owned by the calling app.
763      */
getMySessions()764     public @NonNull List<SessionInfo> getMySessions() {
765         try {
766             return mInstaller.getMySessions(mInstallerPackageName, mUserId).getList();
767         } catch (RemoteException e) {
768             throw e.rethrowFromSystemServer();
769         }
770     }
771 
772     /**
773      * Return list of all staged install sessions. Callers need to either declare &lt;queries&gt;
774      * element with the specific package name in the app's manifest, have the
775      * android.permission.QUERY_ALL_PACKAGES, or be the session owner to retrieve these details.
776      */
getStagedSessions()777     public @NonNull List<SessionInfo> getStagedSessions() {
778         try {
779             // TODO: limit this to the mUserId?
780             return mInstaller.getStagedSessions().getList();
781         } catch (RemoteException e) {
782             throw e.rethrowFromSystemServer();
783         }
784     }
785 
786     /**
787      * Returns first active staged session, or {@code null} if there is none.
788      *
789      * <p>For more information on what sessions are considered active see
790      * {@link SessionInfo#isStagedSessionActive()}.
791      *
792      * @deprecated Use {@link #getActiveStagedSessions} as there can be more than one active staged
793      * session
794      */
795     @Deprecated
getActiveStagedSession()796     public @Nullable SessionInfo getActiveStagedSession() {
797         List<SessionInfo> activeSessions = getActiveStagedSessions();
798         return activeSessions.isEmpty() ? null : activeSessions.get(0);
799     }
800 
801     /**
802      * Returns list of active staged sessions. Returns empty list if there is none.
803      *
804      * <p>For more information on what sessions are considered active see
805      *      * {@link SessionInfo#isStagedSessionActive()}.
806      */
getActiveStagedSessions()807     public @NonNull List<SessionInfo> getActiveStagedSessions() {
808         final List<SessionInfo> activeStagedSessions = new ArrayList<>();
809         final List<SessionInfo> stagedSessions = getStagedSessions();
810         for (int i = 0; i < stagedSessions.size(); i++) {
811             final SessionInfo sessionInfo = stagedSessions.get(i);
812             if (sessionInfo.isStagedSessionActive()) {
813                 activeStagedSessions.add(sessionInfo);
814             }
815         }
816         return activeStagedSessions;
817     }
818 
819     /**
820      * Uninstall the given package, removing it completely from the device. This
821      * method is available to:
822      * <ul>
823      * <li>the current "installer of record" for the package
824      * <li>the device owner
825      * <li>the affiliated profile owner
826      * </ul>
827      *
828      * @param packageName The package to uninstall.
829      * @param statusReceiver Where to deliver the result of the operation indicated by the extra
830      *                       {@link #EXTRA_STATUS}. Refer to the individual status codes
831      *                       on how to handle them.
832      *
833      * @see android.app.admin.DevicePolicyManager
834      */
835     @RequiresPermission(anyOf = {
836             Manifest.permission.DELETE_PACKAGES,
837             Manifest.permission.REQUEST_DELETE_PACKAGES})
uninstall(@onNull String packageName, @NonNull IntentSender statusReceiver)838     public void uninstall(@NonNull String packageName, @NonNull IntentSender statusReceiver) {
839         uninstall(packageName, 0 /*flags*/, statusReceiver);
840     }
841 
842     /**
843      * Uninstall the given package, removing it completely from the device. This
844      * method is only available to the current "installer of record" for the
845      * package.
846      *
847      * @param packageName The package to uninstall.
848      * @param flags Flags for uninstall.
849      * @param statusReceiver Where to deliver the result of the operation indicated by the extra
850      *                       {@link #EXTRA_STATUS}. Refer to the individual status codes
851      *                       on how to handle them.
852      *
853      * @hide
854      */
uninstall(@onNull String packageName, @DeleteFlags int flags, @NonNull IntentSender statusReceiver)855     public void uninstall(@NonNull String packageName, @DeleteFlags int flags,
856             @NonNull IntentSender statusReceiver) {
857         uninstall(new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST),
858                 flags, statusReceiver);
859     }
860 
861     /**
862      * Uninstall the given package with a specific version code, removing it
863      * completely from the device. If the version code of the package
864      * does not match the one passed in the versioned package argument this
865      * method is a no-op. Use {@link PackageManager#VERSION_CODE_HIGHEST} to
866      * uninstall the latest version of the package.
867      * <p>
868      * This method is available to:
869      * <ul>
870      * <li>the current "installer of record" for the package
871      * <li>the device owner
872      * <li>the affiliated profile owner
873      * </ul>
874      *
875      * @param versionedPackage The versioned package to uninstall.
876      * @param statusReceiver Where to deliver the result of the operation indicated by the extra
877      *                       {@link #EXTRA_STATUS}. Refer to the individual status codes
878      *                       on how to handle them.
879      *
880      * @see android.app.admin.DevicePolicyManager
881      */
882     @RequiresPermission(anyOf = {
883             Manifest.permission.DELETE_PACKAGES,
884             Manifest.permission.REQUEST_DELETE_PACKAGES})
uninstall(@onNull VersionedPackage versionedPackage, @NonNull IntentSender statusReceiver)885     public void uninstall(@NonNull VersionedPackage versionedPackage,
886             @NonNull IntentSender statusReceiver) {
887         uninstall(versionedPackage, 0 /*flags*/, statusReceiver);
888     }
889 
890     /**
891      * Uninstall the given package with a specific version code, removing it
892      * completely from the device. This method is only available to the current
893      * "installer of record" for the package. If the version code of the package
894      * does not match the one passed in the versioned package argument this
895      * method is a no-op. Use {@link PackageManager#VERSION_CODE_HIGHEST} to
896      * uninstall the latest version of the package.
897      *
898      * @param versionedPackage The versioned package to uninstall.
899      * @param flags Flags for uninstall.
900      * @param statusReceiver Where to deliver the result of the operation indicated by the extra
901      *                       {@link #EXTRA_STATUS}. Refer to the individual status codes
902      *                       on how to handle them.
903      */
904     @RequiresPermission(anyOf = {
905             Manifest.permission.DELETE_PACKAGES,
906             Manifest.permission.REQUEST_DELETE_PACKAGES})
uninstall(@onNull VersionedPackage versionedPackage, @DeleteFlags int flags, @NonNull IntentSender statusReceiver)907     public void uninstall(@NonNull VersionedPackage versionedPackage, @DeleteFlags int flags,
908             @NonNull IntentSender statusReceiver) {
909         Objects.requireNonNull(versionedPackage, "versionedPackage cannot be null");
910         try {
911             mInstaller.uninstall(versionedPackage, mInstallerPackageName,
912                     flags, statusReceiver, mUserId);
913         } catch (RemoteException e) {
914             throw e.rethrowFromSystemServer();
915         }
916     }
917 
918     /**
919      * Install the given package, which already exists on the device, for the user for which this
920      * installer was created.
921      *
922      * <p>This will
923      * {@link PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set) allowlist
924      * all restricted permissions}.
925      *
926      * @param packageName The package to install.
927      * @param installReason Reason for install.
928      * @param statusReceiver Where to deliver the result of the operation indicated by the extra
929      *                       {@link #EXTRA_STATUS}. Refer to the individual status codes
930      *                       on how to handle them.
931      */
932     @RequiresPermission(allOf = {
933             Manifest.permission.INSTALL_PACKAGES,
934             Manifest.permission.INSTALL_EXISTING_PACKAGES})
installExistingPackage(@onNull String packageName, @InstallReason int installReason, @Nullable IntentSender statusReceiver)935     public void installExistingPackage(@NonNull String packageName,
936             @InstallReason int installReason,
937             @Nullable IntentSender statusReceiver) {
938         Objects.requireNonNull(packageName, "packageName cannot be null");
939         try {
940             mInstaller.installExistingPackage(packageName,
941                     PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS, installReason,
942                     statusReceiver, mUserId, null);
943         } catch (RemoteException e) {
944             throw e.rethrowFromSystemServer();
945         }
946     }
947 
948     /**
949      * Uninstall the given package for the user for which this installer was created if the package
950      * will still exist for other users on the device.
951      *
952      * @param packageName The package to uninstall.
953      * @param statusReceiver Where to deliver the result of the operation indicated by the extra
954      *                       {@link #EXTRA_STATUS}. Refer to the individual status codes
955      *                       on how to handle them.
956      */
957     @RequiresPermission(Manifest.permission.DELETE_PACKAGES)
uninstallExistingPackage(@onNull String packageName, @Nullable IntentSender statusReceiver)958     public void uninstallExistingPackage(@NonNull String packageName,
959             @Nullable IntentSender statusReceiver) {
960         Objects.requireNonNull(packageName, "packageName cannot be null");
961         try {
962             mInstaller.uninstallExistingPackage(
963                     new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST),
964                     mInstallerPackageName, statusReceiver, mUserId);
965         } catch (RemoteException e) {
966             throw e.rethrowFromSystemServer();
967         }
968     }
969 
970     /** {@hide} */
971     @SystemApi
972     @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES)
setPermissionsResult(int sessionId, boolean accepted)973     public void setPermissionsResult(int sessionId, boolean accepted) {
974         try {
975             mInstaller.setPermissionsResult(sessionId, accepted);
976         } catch (RemoteException e) {
977             throw e.rethrowFromSystemServer();
978         }
979     }
980 
981     /**
982      * Check if install constraints are satisfied for the given packages.
983      *
984      * Note this query result is just a hint and subject to race because system states could
985      * change anytime in-between this query and committing the session.
986      *
987      * The result is returned by a callback because some constraints might take a long time
988      * to evaluate.
989      *
990      * @param packageNames a list of package names to check the constraints for installation
991      * @param constraints the constraints for installation.
992      * @param executor the {@link Executor} on which to invoke the callback
993      * @param callback called when the {@link InstallConstraintsResult} is ready
994      *
995      * @throws SecurityException if the given packages' installer of record doesn't match the
996      *             caller's own package name or the installerPackageName set by the caller doesn't
997      *             match the caller's own package name.
998      */
checkInstallConstraints(@onNull List<String> packageNames, @NonNull InstallConstraints constraints, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<InstallConstraintsResult> callback)999     public void checkInstallConstraints(@NonNull List<String> packageNames,
1000             @NonNull InstallConstraints constraints,
1001             @NonNull @CallbackExecutor Executor executor,
1002             @NonNull Consumer<InstallConstraintsResult> callback) {
1003         Objects.requireNonNull(executor);
1004         Objects.requireNonNull(callback);
1005         try {
1006             var remoteCallback = new RemoteCallback(b -> {
1007                 executor.execute(() -> {
1008                     callback.accept(b.getParcelable("result", InstallConstraintsResult.class));
1009                 });
1010             });
1011             mInstaller.checkInstallConstraints(
1012                     mInstallerPackageName, packageNames, constraints, remoteCallback);
1013         } catch (RemoteException e) {
1014             throw e.rethrowFromSystemServer();
1015         }
1016     }
1017 
1018     /**
1019      * Similar to {@link #checkInstallConstraints(List, InstallConstraints, Executor, Consumer)},
1020      * but the callback is invoked only when the constraints are satisfied or after timeout.
1021      * <p>
1022      * Note: the device idle constraint might take a long time to evaluate. The system will
1023      * ensure the constraint is evaluated completely before handling timeout.
1024      *
1025      * @param packageNames a list of package names to check the constraints for installation
1026      * @param constraints the constraints for installation.
1027      * @param callback Called when the constraints are satisfied or after timeout.
1028      *                 Intents sent to this callback contain:
1029      *                 {@link Intent#EXTRA_PACKAGES} for the input package names,
1030      *                 {@link #EXTRA_INSTALL_CONSTRAINTS} for the input constraints,
1031      *                 {@link #EXTRA_INSTALL_CONSTRAINTS_RESULT} for the result.
1032      * @param timeoutMillis The maximum time to wait, in milliseconds until the constraints are
1033      *                      satisfied. Valid range is from 0 to one week. {@code 0} means the
1034      *                      callback will be invoked immediately no matter constraints are
1035      *                      satisfied or not.
1036      * @throws SecurityException if the given packages' installer of record doesn't match the
1037      *             caller's own package name or the installerPackageName set by the caller doesn't
1038      *             match the caller's own package name.
1039      */
waitForInstallConstraints(@onNull List<String> packageNames, @NonNull InstallConstraints constraints, @NonNull IntentSender callback, @DurationMillisLong long timeoutMillis)1040     public void waitForInstallConstraints(@NonNull List<String> packageNames,
1041             @NonNull InstallConstraints constraints,
1042             @NonNull IntentSender callback,
1043             @DurationMillisLong long timeoutMillis) {
1044         try {
1045             mInstaller.waitForInstallConstraints(
1046                     mInstallerPackageName, packageNames, constraints, callback, timeoutMillis);
1047         } catch (RemoteException e) {
1048             throw e.rethrowFromSystemServer();
1049         }
1050     }
1051 
1052     /**
1053      * Commit the session when all constraints are satisfied. This is a convenient method to
1054      * combine {@link #waitForInstallConstraints(List, InstallConstraints, IntentSender, long)}
1055      * and {@link Session#commit(IntentSender)}.
1056      * <p>
1057      * Once this method is called, the session is sealed and no additional mutations
1058      * may be performed on the session. In the case of timeout, you may commit the
1059      * session again using this method or {@link Session#commit(IntentSender)} for retries.
1060      *
1061      * @param sessionId the session ID to commit when all constraints are satisfied.
1062      * @param statusReceiver Called when the state of the session changes. Intents
1063      *                       sent to this receiver contain {@link #EXTRA_STATUS}.
1064      *                       Refer to the individual status codes on how to handle them.
1065      * @param constraints The requirements to satisfy before committing the session.
1066      * @param timeoutMillis The maximum time to wait, in milliseconds until the
1067      *                      constraints are satisfied. The caller will be notified via
1068      *                      {@code statusReceiver} if timeout happens before commit.
1069      */
commitSessionAfterInstallConstraintsAreMet(int sessionId, @NonNull IntentSender statusReceiver, @NonNull InstallConstraints constraints, @DurationMillisLong long timeoutMillis)1070     public void commitSessionAfterInstallConstraintsAreMet(int sessionId,
1071             @NonNull IntentSender statusReceiver, @NonNull InstallConstraints constraints,
1072             @DurationMillisLong long timeoutMillis) {
1073         try {
1074             var session = mInstaller.openSession(sessionId);
1075             session.seal();
1076             var packageNames = session.fetchPackageNames();
1077             var intentSender = new IntentSender((IIntentSender) new IIntentSender.Stub() {
1078                 @Override
1079                 public void send(int code, Intent intent, String resolvedType,
1080                         IBinder allowlistToken, IIntentReceiver finishedReceiver,
1081                         String requiredPermission, Bundle options)  {
1082                     var result = intent.getParcelableExtra(
1083                             PackageInstaller.EXTRA_INSTALL_CONSTRAINTS_RESULT,
1084                             InstallConstraintsResult.class);
1085                     try {
1086                         if (result.areAllConstraintsSatisfied()) {
1087                             session.commit(statusReceiver, false);
1088                         } else {
1089                             // timeout
1090                             final Intent fillIn = new Intent();
1091                             fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
1092                             fillIn.putExtra(PackageInstaller.EXTRA_STATUS, STATUS_FAILURE_TIMEOUT);
1093                             fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
1094                                     "Install constraints not satisfied within timeout");
1095                             statusReceiver.sendIntent(
1096                                     ActivityThread.currentApplication(), 0, fillIn, null, null);
1097                         }
1098                     } catch (Exception ignore) {
1099                     }
1100                 }
1101             });
1102             waitForInstallConstraints(packageNames, constraints, intentSender, timeoutMillis);
1103         } catch (RemoteException e) {
1104             throw e.rethrowFromSystemServer();
1105         }
1106     }
1107 
1108     /**
1109      * Events for observing session lifecycle.
1110      * <p>
1111      * A typical session lifecycle looks like this:
1112      * <ul>
1113      * <li>An installer creates a session to indicate pending app delivery. All
1114      * install details are available at this point.
1115      * <li>The installer opens the session to deliver APK data. Note that a
1116      * session may be opened and closed multiple times as network connectivity
1117      * changes. The installer may deliver periodic progress updates.
1118      * <li>The installer commits or abandons the session, resulting in the
1119      * session being finished.
1120      * </ul>
1121      */
1122     public static abstract class SessionCallback {
1123         /**
1124          * New session has been created. Details about the session can be
1125          * obtained from {@link PackageInstaller#getSessionInfo(int)}.
1126          */
onCreated(int sessionId)1127         public abstract void onCreated(int sessionId);
1128 
1129         /**
1130          * Badging details for an existing session has changed. For example, the
1131          * app icon or label has been updated.
1132          */
onBadgingChanged(int sessionId)1133         public abstract void onBadgingChanged(int sessionId);
1134 
1135         /**
1136          * Active state for session has been changed.
1137          * <p>
1138          * A session is considered active whenever there is ongoing forward
1139          * progress being made, such as the installer holding an open
1140          * {@link Session} instance while streaming data into place, or the
1141          * system optimizing code as the result of
1142          * {@link Session#commit(IntentSender)}.
1143          * <p>
1144          * If the installer closes the {@link Session} without committing, the
1145          * session is considered inactive until the installer opens the session
1146          * again.
1147          */
onActiveChanged(int sessionId, boolean active)1148         public abstract void onActiveChanged(int sessionId, boolean active);
1149 
1150         /**
1151          * Progress for given session has been updated.
1152          * <p>
1153          * Note that this progress may not directly correspond to the value
1154          * reported by
1155          * {@link PackageInstaller.Session#setStagingProgress(float)}, as the
1156          * system may carve out a portion of the overall progress to represent
1157          * its own internal installation work.
1158          */
onProgressChanged(int sessionId, float progress)1159         public abstract void onProgressChanged(int sessionId, float progress);
1160 
1161         /**
1162          * Session has completely finished, either with success or failure.
1163          */
onFinished(int sessionId, boolean success)1164         public abstract void onFinished(int sessionId, boolean success);
1165     }
1166 
1167     /** {@hide} */
1168     static class SessionCallbackDelegate extends IPackageInstallerCallback.Stub {
1169         private static final int MSG_SESSION_CREATED = 1;
1170         private static final int MSG_SESSION_BADGING_CHANGED = 2;
1171         private static final int MSG_SESSION_ACTIVE_CHANGED = 3;
1172         private static final int MSG_SESSION_PROGRESS_CHANGED = 4;
1173         private static final int MSG_SESSION_FINISHED = 5;
1174 
1175         final SessionCallback mCallback;
1176         final Executor mExecutor;
1177 
SessionCallbackDelegate(SessionCallback callback, Executor executor)1178         SessionCallbackDelegate(SessionCallback callback, Executor executor) {
1179             mCallback = callback;
1180             mExecutor = executor;
1181         }
1182 
1183         @Override
onSessionCreated(int sessionId)1184         public void onSessionCreated(int sessionId) {
1185             mExecutor.execute(PooledLambda.obtainRunnable(SessionCallback::onCreated, mCallback,
1186                     sessionId).recycleOnUse());
1187         }
1188 
1189         @Override
onSessionBadgingChanged(int sessionId)1190         public void onSessionBadgingChanged(int sessionId) {
1191             mExecutor.execute(PooledLambda.obtainRunnable(SessionCallback::onBadgingChanged,
1192                     mCallback, sessionId).recycleOnUse());
1193         }
1194 
1195         @Override
onSessionActiveChanged(int sessionId, boolean active)1196         public void onSessionActiveChanged(int sessionId, boolean active) {
1197             mExecutor.execute(PooledLambda.obtainRunnable(SessionCallback::onActiveChanged,
1198                     mCallback, sessionId, active).recycleOnUse());
1199         }
1200 
1201         @Override
onSessionProgressChanged(int sessionId, float progress)1202         public void onSessionProgressChanged(int sessionId, float progress) {
1203             mExecutor.execute(PooledLambda.obtainRunnable(SessionCallback::onProgressChanged,
1204                     mCallback, sessionId, progress).recycleOnUse());
1205         }
1206 
1207         @Override
onSessionFinished(int sessionId, boolean success)1208         public void onSessionFinished(int sessionId, boolean success) {
1209             mExecutor.execute(PooledLambda.obtainRunnable(SessionCallback::onFinished,
1210                     mCallback, sessionId, success).recycleOnUse());
1211         }
1212     }
1213 
1214     /** {@hide} */
1215     @Deprecated
addSessionCallback(@onNull SessionCallback callback)1216     public void addSessionCallback(@NonNull SessionCallback callback) {
1217         registerSessionCallback(callback);
1218     }
1219 
1220     /**
1221      * Register to watch for session lifecycle events. The callers need to be the session
1222      * owner or have the android.permission.QUERY_ALL_PACKAGES to watch for these events.
1223      */
registerSessionCallback(@onNull SessionCallback callback)1224     public void registerSessionCallback(@NonNull SessionCallback callback) {
1225         registerSessionCallback(callback, new Handler());
1226     }
1227 
1228     /** {@hide} */
1229     @Deprecated
addSessionCallback(@onNull SessionCallback callback, @NonNull Handler handler)1230     public void addSessionCallback(@NonNull SessionCallback callback, @NonNull Handler handler) {
1231         registerSessionCallback(callback, handler);
1232     }
1233 
1234     /**
1235      * Register to watch for session lifecycle events. No special permissions
1236      * are required to watch for these events.
1237      *
1238      * @param handler to dispatch callback events through, otherwise uses
1239      *            calling thread.
1240      */
registerSessionCallback(@onNull SessionCallback callback, @NonNull Handler handler)1241     public void registerSessionCallback(@NonNull SessionCallback callback, @NonNull Handler handler) {
1242         synchronized (mDelegates) {
1243             final SessionCallbackDelegate delegate = new SessionCallbackDelegate(callback,
1244                     new HandlerExecutor(handler));
1245             try {
1246                 mInstaller.registerCallback(delegate, mUserId);
1247             } catch (RemoteException e) {
1248                 throw e.rethrowFromSystemServer();
1249             }
1250             mDelegates.add(delegate);
1251         }
1252     }
1253 
1254     /** {@hide} */
1255     @Deprecated
removeSessionCallback(@onNull SessionCallback callback)1256     public void removeSessionCallback(@NonNull SessionCallback callback) {
1257         unregisterSessionCallback(callback);
1258     }
1259 
1260     /**
1261      * Unregister a previously registered callback.
1262      */
unregisterSessionCallback(@onNull SessionCallback callback)1263     public void unregisterSessionCallback(@NonNull SessionCallback callback) {
1264         synchronized (mDelegates) {
1265             for (Iterator<SessionCallbackDelegate> i = mDelegates.iterator(); i.hasNext();) {
1266                 final SessionCallbackDelegate delegate = i.next();
1267                 if (delegate.mCallback == callback) {
1268                     try {
1269                         mInstaller.unregisterCallback(delegate);
1270                     } catch (RemoteException e) {
1271                         throw e.rethrowFromSystemServer();
1272                     }
1273                     i.remove();
1274                 }
1275             }
1276         }
1277     }
1278 
1279     /**
1280      * An installation that is being actively staged. For an install to succeed,
1281      * all existing and new packages must have identical package names, version
1282      * codes, and signing certificates.
1283      * <p>
1284      * A session may contain any number of split packages. If the application
1285      * does not yet exist, this session must include a base package.
1286      * <p>
1287      * If an APK included in this session is already defined by the existing
1288      * installation (for example, the same split name), the APK in this session
1289      * will replace the existing APK.
1290      * <p>
1291      * In such a case that multiple packages need to be committed simultaneously,
1292      * multiple sessions can be referenced by a single multi-package session.
1293      * This session is created with no package name and calling
1294      * {@link SessionParams#setMultiPackage()}. The individual session IDs can be
1295      * added with {@link #addChildSessionId(int)} and commit of the multi-package
1296      * session will result in all child sessions being committed atomically.
1297      */
1298     public static class Session implements Closeable {
1299         /** {@hide} */
1300         protected final IPackageInstallerSession mSession;
1301 
1302         /** {@hide} */
Session(IPackageInstallerSession session)1303         public Session(IPackageInstallerSession session) {
1304             mSession = session;
1305         }
1306 
1307         /** {@hide} */
1308         @Deprecated
setProgress(float progress)1309         public void setProgress(float progress) {
1310             setStagingProgress(progress);
1311         }
1312 
1313         /**
1314          * Set current progress of staging this session. Valid values are
1315          * anywhere between 0 and 1.
1316          * <p>
1317          * Note that this progress may not directly correspond to the value
1318          * reported by {@link SessionCallback#onProgressChanged(int, float)}, as
1319          * the system may carve out a portion of the overall progress to
1320          * represent its own internal installation work.
1321          */
setStagingProgress(float progress)1322         public void setStagingProgress(float progress) {
1323             try {
1324                 mSession.setClientProgress(progress);
1325             } catch (RemoteException e) {
1326                 throw e.rethrowFromSystemServer();
1327             }
1328         }
1329 
1330         /** {@hide} */
1331         @UnsupportedAppUsage
addProgress(float progress)1332         public void addProgress(float progress) {
1333             try {
1334                 mSession.addClientProgress(progress);
1335             } catch (RemoteException e) {
1336                 throw e.rethrowFromSystemServer();
1337             }
1338         }
1339 
1340         /**
1341          * Open a stream to write an APK file into the session.
1342          * <p>
1343          * The returned stream will start writing data at the requested offset
1344          * in the underlying file, which can be used to resume a partially
1345          * written file. If a valid file length is specified, the system will
1346          * preallocate the underlying disk space to optimize placement on disk.
1347          * It's strongly recommended to provide a valid file length when known.
1348          * <p>
1349          * You can write data into the returned stream, optionally call
1350          * {@link #fsync(OutputStream)} as needed to ensure bytes have been
1351          * persisted to disk, and then close when finished. All streams must be
1352          * closed before calling {@link #commit(IntentSender)}.
1353          *
1354          * @param name arbitrary, unique name of your choosing to identify the
1355          *            APK being written. You can open a file again for
1356          *            additional writes (such as after a reboot) by using the
1357          *            same name. This name is only meaningful within the context
1358          *            of a single install session.
1359          * @param offsetBytes offset into the file to begin writing at, or 0 to
1360          *            start at the beginning of the file.
1361          * @param lengthBytes total size of the file being written, used to
1362          *            preallocate the underlying disk space, or -1 if unknown.
1363          *            The system may clear various caches as needed to allocate
1364          *            this space.
1365          * @throws IOException if trouble opening the file for writing, such as
1366          *             lack of disk space or unavailable media.
1367          * @throws SecurityException if called after the session has been
1368          *             sealed or abandoned
1369          */
openWrite(@onNull String name, long offsetBytes, long lengthBytes)1370         public @NonNull OutputStream openWrite(@NonNull String name, long offsetBytes,
1371                 long lengthBytes) throws IOException {
1372             try {
1373                 if (ENABLE_REVOCABLE_FD) {
1374                     return new ParcelFileDescriptor.AutoCloseOutputStream(
1375                             mSession.openWrite(name, offsetBytes, lengthBytes));
1376                 } else {
1377                     final ParcelFileDescriptor clientSocket = mSession.openWrite(name,
1378                             offsetBytes, lengthBytes);
1379                     return new FileBridge.FileBridgeOutputStream(clientSocket);
1380                 }
1381             } catch (RuntimeException e) {
1382                 ExceptionUtils.maybeUnwrapIOException(e);
1383                 throw e;
1384             } catch (RemoteException e) {
1385                 throw e.rethrowFromSystemServer();
1386             }
1387         }
1388 
1389         /** {@hide} */
write(@onNull String name, long offsetBytes, long lengthBytes, @NonNull ParcelFileDescriptor fd)1390         public void write(@NonNull String name, long offsetBytes, long lengthBytes,
1391                 @NonNull ParcelFileDescriptor fd) throws IOException {
1392             try {
1393                 mSession.write(name, offsetBytes, lengthBytes, fd);
1394             } catch (RuntimeException e) {
1395                 ExceptionUtils.maybeUnwrapIOException(e);
1396                 throw e;
1397             } catch (RemoteException e) {
1398                 throw e.rethrowFromSystemServer();
1399             }
1400         }
1401 
1402         /**
1403          * Populate an APK file by creating a hard link to avoid the need to copy.
1404          * <p>
1405          * Note this API is used by RollbackManager only and can only be called from system_server.
1406          * {@code target} will be relabeled if link is created successfully. RollbackManager has
1407          * to delete {@code target} when the session is committed successfully to avoid SELinux
1408          * label conflicts.
1409          * <p>
1410          * Note No more bytes should be written to the file once the link is created successfully.
1411          *
1412          * @param target the path of the link target
1413          *
1414          * @hide
1415          */
stageViaHardLink(String target)1416         public void stageViaHardLink(String target) throws IOException {
1417             try {
1418                 mSession.stageViaHardLink(target);
1419             } catch (RuntimeException e) {
1420                 ExceptionUtils.maybeUnwrapIOException(e);
1421                 throw e;
1422             } catch (RemoteException e) {
1423                 throw e.rethrowFromSystemServer();
1424             }
1425         }
1426 
1427         /**
1428          * Ensure that any outstanding data for given stream has been committed
1429          * to disk. This is only valid for streams returned from
1430          * {@link #openWrite(String, long, long)}.
1431          */
fsync(@onNull OutputStream out)1432         public void fsync(@NonNull OutputStream out) throws IOException {
1433             if (ENABLE_REVOCABLE_FD) {
1434                 if (out instanceof ParcelFileDescriptor.AutoCloseOutputStream) {
1435                     try {
1436                         Os.fsync(((ParcelFileDescriptor.AutoCloseOutputStream) out).getFD());
1437                     } catch (ErrnoException e) {
1438                         throw e.rethrowAsIOException();
1439                     }
1440                 } else {
1441                     throw new IllegalArgumentException("Unrecognized stream");
1442                 }
1443             } else {
1444                 if (out instanceof FileBridge.FileBridgeOutputStream) {
1445                     ((FileBridge.FileBridgeOutputStream) out).fsync();
1446                 } else {
1447                     throw new IllegalArgumentException("Unrecognized stream");
1448                 }
1449             }
1450         }
1451 
1452         /**
1453          * Return all APK names contained in this session.
1454          * <p>
1455          * This returns all names which have been previously written through
1456          * {@link #openWrite(String, long, long)} as part of this session.
1457          *
1458          * @throws SecurityException if called after the session has been
1459          *             committed or abandoned.
1460          */
getNames()1461         public @NonNull String[] getNames() throws IOException {
1462             try {
1463                 return mSession.getNames();
1464             } catch (RuntimeException e) {
1465                 ExceptionUtils.maybeUnwrapIOException(e);
1466                 throw e;
1467             } catch (RemoteException e) {
1468                 throw e.rethrowFromSystemServer();
1469             }
1470         }
1471 
1472         /**
1473          * Open a stream to read an APK file from the session.
1474          * <p>
1475          * This is only valid for names which have been previously written
1476          * through {@link #openWrite(String, long, long)} as part of this
1477          * session. For example, this stream may be used to calculate a
1478          * {@link MessageDigest} of a written APK before committing.
1479          *
1480          * @throws SecurityException if called after the session has been
1481          *             committed or abandoned.
1482          */
openRead(@onNull String name)1483         public @NonNull InputStream openRead(@NonNull String name) throws IOException {
1484             try {
1485                 final ParcelFileDescriptor pfd = mSession.openRead(name);
1486                 return new ParcelFileDescriptor.AutoCloseInputStream(pfd);
1487             } catch (RuntimeException e) {
1488                 ExceptionUtils.maybeUnwrapIOException(e);
1489                 throw e;
1490             } catch (RemoteException e) {
1491                 throw e.rethrowFromSystemServer();
1492             }
1493         }
1494 
1495         /**
1496          * Removes a split.
1497          * <p>
1498          * Split removals occur prior to adding new APKs. If upgrading a feature
1499          * split, it is not expected nor desirable to remove the split prior to
1500          * upgrading.
1501          * <p>
1502          * When split removal is bundled with new APKs, the packageName must be
1503          * identical.
1504          */
removeSplit(@onNull String splitName)1505         public void removeSplit(@NonNull String splitName) throws IOException {
1506             try {
1507                 mSession.removeSplit(splitName);
1508             } catch (RuntimeException e) {
1509                 ExceptionUtils.maybeUnwrapIOException(e);
1510                 throw e;
1511             } catch (RemoteException e) {
1512                 throw e.rethrowFromSystemServer();
1513             }
1514         }
1515 
1516         /**
1517          * @return data loader params or null if the session is not using one.
1518          * {@hide}
1519          */
1520         @SystemApi
1521         @RequiresPermission(android.Manifest.permission.USE_INSTALLER_V2)
getDataLoaderParams()1522         public @Nullable DataLoaderParams getDataLoaderParams() {
1523             try {
1524                 DataLoaderParamsParcel data = mSession.getDataLoaderParams();
1525                 if (data == null) {
1526                     return null;
1527                 }
1528                 return new DataLoaderParams(data);
1529             } catch (RemoteException e) {
1530                 throw e.rethrowFromSystemServer();
1531             }
1532         }
1533 
1534         /**
1535          * Adds a file to session. On commit this file will be pulled from DataLoader {@code
1536          * android.service.dataloader.DataLoaderService.DataLoader}.
1537          *
1538          * @param location target location for the file. Possible values:
1539          *            {@link #LOCATION_DATA_APP},
1540          *            {@link #LOCATION_MEDIA_OBB},
1541          *            {@link #LOCATION_MEDIA_DATA}.
1542          * @param name arbitrary, unique name of your choosing to identify the
1543          *            APK being written. You can open a file again for
1544          *            additional writes (such as after a reboot) by using the
1545          *            same name. This name is only meaningful within the context
1546          *            of a single install session.
1547          * @param lengthBytes total size of the file being written.
1548          *            The system may clear various caches as needed to allocate
1549          *            this space.
1550          * @param metadata additional info use by DataLoader to pull data for the file.
1551          * @param signature additional file signature, e.g.
1552          *                  <a href="https://source.android.com/security/apksigning/v4.html">APK Signature Scheme v4</a>
1553          * @throws SecurityException if called after the session has been
1554          *             sealed or abandoned
1555          * @throws IllegalStateException if called for non-streaming session
1556          *
1557          * @see android.content.pm.InstallationFile
1558          *
1559          * {@hide}
1560          */
1561         @SystemApi
1562         @RequiresPermission(android.Manifest.permission.USE_INSTALLER_V2)
addFile(@ileLocation int location, @NonNull String name, long lengthBytes, @NonNull byte[] metadata, @Nullable byte[] signature)1563         public void addFile(@FileLocation int location, @NonNull String name, long lengthBytes,
1564                 @NonNull byte[] metadata, @Nullable byte[] signature) {
1565             try {
1566                 mSession.addFile(location, name, lengthBytes, metadata, signature);
1567             } catch (RemoteException e) {
1568                 throw e.rethrowFromSystemServer();
1569             }
1570         }
1571 
1572         /**
1573          * Removes a file.
1574          *
1575          * @param location target location for the file. Possible values:
1576          *            {@link #LOCATION_DATA_APP},
1577          *            {@link #LOCATION_MEDIA_OBB},
1578          *            {@link #LOCATION_MEDIA_DATA}.
1579          * @param name name of a file, e.g. split.
1580          * @throws SecurityException if called after the session has been
1581          *             sealed or abandoned
1582          * @throws IllegalStateException if called for non-DataLoader session
1583          * {@hide}
1584          */
1585         @SystemApi
1586         @RequiresPermission(android.Manifest.permission.USE_INSTALLER_V2)
removeFile(@ileLocation int location, @NonNull String name)1587         public void removeFile(@FileLocation int location, @NonNull String name) {
1588             try {
1589                 mSession.removeFile(location, name);
1590             } catch (RemoteException e) {
1591                 throw e.rethrowFromSystemServer();
1592             }
1593         }
1594 
1595         /**
1596          * Sets installer-provided checksums for the APK file in session.
1597          *
1598          * @param name      previously written as part of this session.
1599          *                  {@link #openWrite}
1600          * @param checksums installer intends to make available via
1601          *                  {@link PackageManager#requestChecksums} or {@link #requestChecksums}.
1602          * @param signature DER PKCS#7 detached signature bytes over binary serialized checksums
1603          *                  to enable integrity checking for the checksums or null for no integrity
1604          *                  checking. {@link PackageManager#requestChecksums} will return
1605          *                  the certificate used to create signature.
1606          *                  Binary format for checksums:
1607          *                  <pre>{@code DataOutputStream dos;
1608          *                  dos.writeInt(checksum.getType());
1609          *                  dos.writeInt(checksum.getValue().length);
1610          *                  dos.write(checksum.getValue());}</pre>
1611          *                  If using <b>openssl cms</b>, make sure to specify -binary -nosmimecap.
1612          *                  @see <a href="https://www.openssl.org/docs/man1.0.2/man1/cms.html">openssl cms</a>
1613          * @throws SecurityException if called after the session has been
1614          *                           committed or abandoned.
1615          * @throws IllegalStateException if checksums for this file have already been added.
1616          * @deprecated  do not use installer-provided checksums,
1617          *              use platform-enforced checksums
1618          *              e.g. {@link Checksum#TYPE_WHOLE_MERKLE_ROOT_4K_SHA256}
1619          *              in {@link PackageManager#requestChecksums}.
1620          */
1621         @Deprecated
setChecksums(@onNull String name, @NonNull List<Checksum> checksums, @Nullable byte[] signature)1622         public void setChecksums(@NonNull String name, @NonNull List<Checksum> checksums,
1623                 @Nullable byte[] signature) throws IOException {
1624             Objects.requireNonNull(name);
1625             Objects.requireNonNull(checksums);
1626 
1627             try {
1628                 mSession.setChecksums(name, checksums.toArray(new Checksum[checksums.size()]),
1629                         signature);
1630             } catch (RuntimeException e) {
1631                 ExceptionUtils.maybeUnwrapIOException(e);
1632                 throw e;
1633             } catch (RemoteException e) {
1634                 throw e.rethrowFromSystemServer();
1635             }
1636         }
1637 
encodeCertificates(List<Certificate> certs)1638         private static List<byte[]> encodeCertificates(List<Certificate> certs) throws
1639                 CertificateEncodingException {
1640             if (certs == null) {
1641                 return null;
1642             }
1643             List<byte[]> result = new ArrayList<>(certs.size());
1644             for (Certificate cert : certs) {
1645                 if (!(cert instanceof X509Certificate)) {
1646                     throw new CertificateEncodingException("Only X509 certificates supported.");
1647                 }
1648                 result.add(cert.getEncoded());
1649             }
1650             return result;
1651         }
1652 
1653         /**
1654          * Requests checksums for the APK file in session.
1655          * <p>
1656          * A possible use case is replying to {@link Intent#ACTION_PACKAGE_NEEDS_VERIFICATION}
1657          * broadcast.
1658          * The checksums will be returned asynchronously via onChecksumsReadyListener.
1659          * <p>
1660          * By default returns all readily available checksums:
1661          * <ul>
1662          * <li>enforced by platform,
1663          * <li>enforced by the installer.
1664          * </ul>
1665          * If the caller needs a specific checksum type, they can specify it as required.
1666          * <p>
1667          * <b>Caution: Android can not verify installer-provided checksums. Make sure you specify
1668          * trusted installers.</b>
1669          * <p>
1670          * @param name      previously written as part of this session.
1671          *                  {@link #openWrite}
1672          * @param required to explicitly request the checksum types. Will incur significant
1673          *                 CPU/memory/disk usage.
1674          * @param trustedInstallers for checksums enforced by installer, which installers are to be
1675          *                          trusted.
1676          *                          {@link PackageManager#TRUST_ALL} will return checksums from any
1677          *                          installer,
1678          *                          {@link PackageManager#TRUST_NONE} disables optimized
1679          *                          installer-enforced checksums, otherwise the list has to be
1680          *                          a non-empty list of certificates.
1681          * @param executor the {@link Executor} on which to invoke the callback
1682          * @param onChecksumsReadyListener called once when the results are available.
1683          * @throws CertificateEncodingException if an encoding error occurs for trustedInstallers.
1684          * @throws FileNotFoundException if the file does not exist.
1685          * @throws IllegalArgumentException if the list of trusted installer certificates is empty.
1686          */
requestChecksums(@onNull String name, @Checksum.TypeMask int required, @NonNull List<Certificate> trustedInstallers, @NonNull @CallbackExecutor Executor executor, @NonNull PackageManager.OnChecksumsReadyListener onChecksumsReadyListener)1687         public void requestChecksums(@NonNull String name, @Checksum.TypeMask int required,
1688                 @NonNull List<Certificate> trustedInstallers,
1689                 @NonNull @CallbackExecutor Executor executor,
1690                 @NonNull PackageManager.OnChecksumsReadyListener onChecksumsReadyListener)
1691                 throws CertificateEncodingException, FileNotFoundException {
1692             Objects.requireNonNull(name);
1693             Objects.requireNonNull(trustedInstallers);
1694             Objects.requireNonNull(executor);
1695             Objects.requireNonNull(onChecksumsReadyListener);
1696             if (trustedInstallers == PackageManager.TRUST_ALL) {
1697                 trustedInstallers = null;
1698             } else if (trustedInstallers == PackageManager.TRUST_NONE) {
1699                 trustedInstallers = Collections.emptyList();
1700             } else if (trustedInstallers.isEmpty()) {
1701                 throw new IllegalArgumentException(
1702                         "trustedInstallers has to be one of TRUST_ALL/TRUST_NONE or a non-empty "
1703                                 + "list of certificates.");
1704             }
1705             try {
1706                 IOnChecksumsReadyListener onChecksumsReadyListenerDelegate =
1707                         new IOnChecksumsReadyListener.Stub() {
1708                             @Override
1709                             public void onChecksumsReady(List<ApkChecksum> checksums)
1710                                     throws RemoteException {
1711                                 executor.execute(
1712                                         () -> onChecksumsReadyListener.onChecksumsReady(checksums));
1713                             }
1714                         };
1715                 mSession.requestChecksums(name, DEFAULT_CHECKSUMS, required,
1716                         encodeCertificates(trustedInstallers), onChecksumsReadyListenerDelegate);
1717             } catch (ParcelableException e) {
1718                 e.maybeRethrow(FileNotFoundException.class);
1719                 throw new RuntimeException(e);
1720             } catch (RemoteException e) {
1721                 throw e.rethrowFromSystemServer();
1722             }
1723         }
1724 
1725         /**
1726          * Attempt to commit everything staged in this session. This may require
1727          * user intervention, and so it may not happen immediately. The final
1728          * result of the commit will be reported through the given callback.
1729          * <p>
1730          * Once this method is called, the session is sealed and no additional mutations may be
1731          * performed on the session. In case of device reboot or data loader transient failure
1732          * before the session has been finalized, you may commit the session again.
1733          * <p>
1734          * If the installer is the device owner, the affiliated profile owner, or has received
1735          * user pre-approval of this session, there will be no user intervention.
1736          *
1737          * @param statusReceiver Called when the state of the session changes. Intents
1738          *                       sent to this receiver contain {@link #EXTRA_STATUS}. Refer to the
1739          *                       individual status codes on how to handle them.
1740          *
1741          * @throws SecurityException if streams opened through
1742          *             {@link #openWrite(String, long, long)} are still open.
1743          *
1744          * @see android.app.admin.DevicePolicyManager
1745          * @see #requestUserPreapproval
1746          */
commit(@onNull IntentSender statusReceiver)1747         public void commit(@NonNull IntentSender statusReceiver) {
1748             try {
1749                 mSession.commit(statusReceiver, false);
1750             } catch (RemoteException e) {
1751                 throw e.rethrowFromSystemServer();
1752             }
1753         }
1754 
1755         /**
1756          * Attempt to commit a session that has been {@link #transfer(String) transferred}.
1757          *
1758          * <p>If the device reboots before the session has been finalized, you may commit the
1759          * session again.
1760          *
1761          * <p>The caller of this method is responsible to ensure the safety of the session. As the
1762          * session was created by another - usually less trusted - app, it is paramount that before
1763          * committing <u>all</u> public and system {@link SessionInfo properties of the session}
1764          * and <u>all</u> {@link #openRead(String) APKs} are verified by the caller. It might happen
1765          * that new properties are added to the session with a new API revision. In this case the
1766          * callers need to be updated.
1767          *
1768          * @param statusReceiver Called when the state of the session changes. Intents
1769          *                       sent to this receiver contain {@link #EXTRA_STATUS}. Refer to the
1770          *                       individual status codes on how to handle them.
1771          *
1772          * @hide
1773          */
1774         @SystemApi
1775         @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES)
commitTransferred(@onNull IntentSender statusReceiver)1776         public void commitTransferred(@NonNull IntentSender statusReceiver) {
1777             try {
1778                 mSession.commit(statusReceiver, true);
1779             } catch (RemoteException e) {
1780                 throw e.rethrowFromSystemServer();
1781             }
1782         }
1783 
1784         /**
1785          * Transfer the session to a new owner.
1786          * <p>
1787          * Only sessions that update the installing app can be transferred.
1788          * <p>
1789          * After the transfer to a package with a different uid all method calls on the session
1790          * will cause {@link SecurityException}s.
1791          * <p>
1792          * Once this method is called, the session is sealed and no additional mutations beside
1793          * committing it may be performed on the session.
1794          *
1795          * @param packageName The package of the new owner. Needs to hold the INSTALL_PACKAGES
1796          *                    permission.
1797          *
1798          * @throws PackageManager.NameNotFoundException if the new owner could not be found.
1799          * @throws SecurityException if called after the session has been committed or abandoned.
1800          * @throws IllegalStateException if streams opened through
1801          *                                  {@link #openWrite(String, long, long) are still open.
1802          * @throws IllegalArgumentException if {@code packageName} is invalid.
1803          */
transfer(@onNull String packageName)1804         public void transfer(@NonNull String packageName)
1805                 throws PackageManager.NameNotFoundException {
1806             Preconditions.checkArgument(!TextUtils.isEmpty(packageName));
1807 
1808             try {
1809                 mSession.transfer(packageName);
1810             } catch (ParcelableException e) {
1811                 e.maybeRethrow(PackageManager.NameNotFoundException.class);
1812                 throw new RuntimeException(e);
1813             } catch (RemoteException e) {
1814                 throw e.rethrowFromSystemServer();
1815             }
1816         }
1817 
1818         /**
1819          * Release this session object. You can open the session again if it
1820          * hasn't been finalized.
1821          */
1822         @Override
close()1823         public void close() {
1824             try {
1825                 mSession.close();
1826             } catch (RemoteException e) {
1827                 throw e.rethrowFromSystemServer();
1828             }
1829         }
1830 
1831         /**
1832          * Completely abandon this session, destroying all staged data and
1833          * rendering it invalid. Abandoned sessions will be reported to
1834          * {@link SessionCallback} listeners as failures. This is equivalent to
1835          * {@link #abandonSession(int)}.
1836          * <p>If the parent is abandoned, all children will also be abandoned. Any written data
1837          * would be destroyed and the created {@link Session} information will be discarded.</p>
1838          */
abandon()1839         public void abandon() {
1840             try {
1841                 mSession.abandon();
1842             } catch (RemoteException e) {
1843                 throw e.rethrowFromSystemServer();
1844             }
1845         }
1846 
1847         /**
1848          * @return {@code true} if this session will commit more than one package when it is
1849          * committed.
1850          */
isMultiPackage()1851         public boolean isMultiPackage() {
1852             try {
1853                 return mSession.isMultiPackage();
1854             } catch (RemoteException e) {
1855                 throw e.rethrowFromSystemServer();
1856             }
1857         }
1858 
1859         /**
1860          * @return {@code true} if this session will be staged and applied at next reboot.
1861          */
isStaged()1862         public boolean isStaged() {
1863             try {
1864                 return mSession.isStaged();
1865             } catch (RemoteException e) {
1866                 throw e.rethrowFromSystemServer();
1867             }
1868         }
1869 
1870         /**
1871          * @return Session's {@link SessionParams#installFlags}.
1872          * @hide
1873          */
getInstallFlags()1874         public int getInstallFlags() {
1875             try {
1876                 return mSession.getInstallFlags();
1877             } catch (RemoteException e) {
1878                 throw e.rethrowFromSystemServer();
1879             }
1880         }
1881 
1882         /**
1883          * @return the session ID of the multi-package session that this belongs to or
1884          * {@link SessionInfo#INVALID_ID} if it does not belong to a multi-package session.
1885          */
getParentSessionId()1886         public int getParentSessionId() {
1887             try {
1888                 return mSession.getParentSessionId();
1889             } catch (RemoteException e) {
1890                 throw e.rethrowFromSystemServer();
1891             }
1892         }
1893 
1894         /**
1895          * @return the set of session IDs that will be committed atomically when this session is
1896          * committed if this is a multi-package session or null if none exist.
1897          */
1898         @NonNull
getChildSessionIds()1899         public int[] getChildSessionIds() {
1900             try {
1901                 return mSession.getChildSessionIds();
1902             } catch (RemoteException e) {
1903                 throw e.rethrowFromSystemServer();
1904             }
1905         }
1906 
1907         /**
1908          * Adds a session ID to the set of sessions that will be committed atomically
1909          * when this session is committed.
1910          *
1911          * <p>If the parent is staged or has rollback enabled, all children must have
1912          * the same properties.</p>
1913          * <p>If the parent is abandoned, all children will also be abandoned.</p>
1914          *
1915          * @param sessionId the session ID to add to this multi-package session.
1916          */
addChildSessionId(int sessionId)1917         public void addChildSessionId(int sessionId) {
1918             try {
1919                 mSession.addChildSessionId(sessionId);
1920             } catch (RemoteException e) {
1921                 e.rethrowFromSystemServer();
1922             }
1923         }
1924 
1925         /**
1926          * Removes a session ID from the set of sessions that will be committed
1927          * atomically when this session is committed.
1928          *
1929          * @param sessionId the session ID to remove from this multi-package session.
1930          */
removeChildSessionId(int sessionId)1931         public void removeChildSessionId(int sessionId) {
1932             try {
1933                 mSession.removeChildSessionId(sessionId);
1934             } catch (RemoteException e) {
1935                 e.rethrowFromSystemServer();
1936             }
1937         }
1938 
1939         /**
1940          * @return A PersistableBundle containing the app metadata set with
1941          * {@link Session#setAppMetadata(PersistableBundle)}. In the case where this data does not
1942          * exist, an empty PersistableBundle is returned.
1943          */
1944         @NonNull
getAppMetadata()1945         public PersistableBundle getAppMetadata() {
1946             PersistableBundle data = null;
1947             try {
1948                 ParcelFileDescriptor pfd = mSession.getAppMetadataFd();
1949                 if (pfd != null) {
1950                     try (InputStream inputStream =
1951                             new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
1952                         data = PersistableBundle.readFromStream(inputStream);
1953                     }
1954                 }
1955             } catch (RemoteException e) {
1956                 e.rethrowFromSystemServer();
1957             } catch (IOException e) {
1958                 throw new RuntimeException(e);
1959             }
1960             return data != null ? data : new PersistableBundle();
1961         }
1962 
openWriteAppMetadata()1963         private OutputStream openWriteAppMetadata() throws IOException {
1964             try {
1965                 if (ENABLE_REVOCABLE_FD) {
1966                     return new ParcelFileDescriptor.AutoCloseOutputStream(
1967                             mSession.openWriteAppMetadata());
1968                 } else {
1969                     final ParcelFileDescriptor clientSocket = mSession.openWriteAppMetadata();
1970                     return new FileBridge.FileBridgeOutputStream(clientSocket);
1971                 }
1972             } catch (RuntimeException e) {
1973                 ExceptionUtils.maybeUnwrapIOException(e);
1974                 throw e;
1975             } catch (RemoteException e) {
1976                 throw e.rethrowFromSystemServer();
1977             }
1978         }
1979 
1980         /**
1981          * Optionally set the app metadata. The size of this data cannot exceed the maximum allowed.
1982          * Any existing data from the previous install will not be retained even if no data is set
1983          * for the current install session. Setting data to null or an empty PersistableBundle will
1984          * remove any metadata that has previously been set in the same session.
1985          *
1986          * @param data a PersistableBundle containing the app metadata.
1987          * @throws IOException if writing the data fails.
1988          */
setAppMetadata(@ullable PersistableBundle data)1989         public void setAppMetadata(@Nullable PersistableBundle data) throws IOException {
1990             if (data == null || data.isEmpty()) {
1991                 try {
1992                     mSession.removeAppMetadata();
1993                 } catch (RemoteException e) {
1994                     throw e.rethrowFromSystemServer();
1995                 }
1996                 return;
1997             }
1998             Objects.requireNonNull(data);
1999             try (OutputStream outputStream = openWriteAppMetadata()) {
2000                 data.writeToStream(outputStream);
2001             }
2002         }
2003 
2004         /**
2005          * Attempt to request the approval before committing this session.
2006          *
2007          * For installers that have been granted the
2008          * {@link android.Manifest.permission#REQUEST_INSTALL_PACKAGES REQUEST_INSTALL_PACKAGES}
2009          * permission, they can request the approval from users before
2010          * {@link Session#commit(IntentSender)} is called. This may require user intervention as
2011          * well. When user intervention is required, installers will receive a
2012          * {@link #STATUS_PENDING_USER_ACTION} callback, and {@link #STATUS_SUCCESS} otherwise.
2013          * In case that requesting user pre-approval is not available, installers will receive
2014          * {@link #STATUS_FAILURE_BLOCKED} instead. Note that if the users decline the request,
2015          * this session will be abandoned.
2016          *
2017          * If user intervention is required but never resolved, or requesting user
2018          * pre-approval is not available, you may still call {@link Session#commit(IntentSender)}
2019          * as the typical installation.
2020          *
2021          * @param details the adequate context to this session for requesting the approval from
2022          *                users prior to commit.
2023          * @param statusReceiver called when the state of the session changes.
2024          *                       Intents sent to this receiver contain {@link #EXTRA_STATUS}
2025          *                       and the {@link #EXTRA_PRE_APPROVAL} would be {@code true}.
2026          *                       Refer to the individual status codes on how to handle them.
2027          *
2028          * @throws IllegalArgumentException when {@link PreapprovalDetails} is {@code null}.
2029          * @throws IllegalArgumentException if {@link IntentSender} is {@code null}.
2030          * @throws IllegalStateException if called on a multi-package session (no matter
2031          *                               the parent session or any of the children sessions).
2032          * @throws IllegalStateException if called again after this method has been called on
2033          *                               this session.
2034          * @throws SecurityException when the caller does not own this session.
2035          * @throws SecurityException if called after the session has been committed or abandoned.
2036          */
requestUserPreapproval(@onNull PreapprovalDetails details, @NonNull IntentSender statusReceiver)2037         public void requestUserPreapproval(@NonNull PreapprovalDetails details,
2038                 @NonNull IntentSender statusReceiver) {
2039             Preconditions.checkArgument(details != null, "preapprovalDetails cannot be null.");
2040             Preconditions.checkArgument(statusReceiver != null, "statusReceiver cannot be null.");
2041             try {
2042                 mSession.requestUserPreapproval(details, statusReceiver);
2043             } catch (RemoteException e) {
2044                 e.rethrowFromSystemServer();
2045             }
2046         }
2047 
2048         /**
2049          * @return {@code true} if this session will keep the existing application enabled setting
2050          * after installation.
2051          */
isApplicationEnabledSettingPersistent()2052         public boolean isApplicationEnabledSettingPersistent() {
2053             try {
2054                 return mSession.isApplicationEnabledSettingPersistent();
2055             } catch (RemoteException e) {
2056                 throw e.rethrowFromSystemServer();
2057             }
2058         }
2059 
2060         /**
2061          * @return {@code true} if the installer requested the update ownership enforcement
2062          * for the packages in this session.
2063          *
2064          * @see PackageInstaller.SessionParams#setRequestUpdateOwnership
2065          */
isRequestUpdateOwnership()2066         public boolean isRequestUpdateOwnership() {
2067             try {
2068                 return mSession.isRequestUpdateOwnership();
2069             } catch (RemoteException e) {
2070                 throw e.rethrowFromSystemServer();
2071             }
2072         }
2073     }
2074 
2075     /**
2076      * Parse a single APK or a directory of APKs to get install relevant information about
2077      * the package wrapped in {@link InstallInfo}.
2078      * @throws PackageParsingException if the package source file(s) provided is(are) not valid,
2079      * or the parser isn't able to parse the supplied source(s).
2080      * @hide
2081      */
2082     @SystemApi
2083     @NonNull
readInstallInfo(@onNull File file, int flags)2084     public InstallInfo readInstallInfo(@NonNull File file, int flags)
2085             throws PackageParsingException {
2086         final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
2087         final ParseResult<PackageLite> result = ApkLiteParseUtils.parsePackageLite(
2088                 input.reset(), file, flags);
2089         if (result.isError()) {
2090             throw new PackageParsingException(result.getErrorCode(), result.getErrorMessage());
2091         }
2092         return new InstallInfo(result);
2093     }
2094 
2095     /**
2096      * Parse a single APK file passed as an FD to get install relevant information about
2097      * the package wrapped in {@link InstallInfo}.
2098      * @throws PackageParsingException if the package source file(s) provided is(are) not valid,
2099      * or the parser isn't able to parse the supplied source(s).
2100      * @hide
2101      */
2102     @NonNull
readInstallInfo(@onNull ParcelFileDescriptor pfd, @Nullable String debugPathName, int flags)2103     public InstallInfo readInstallInfo(@NonNull ParcelFileDescriptor pfd,
2104             @Nullable String debugPathName, int flags) throws PackageParsingException {
2105         final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
2106         final ParseResult<PackageLite> result = ApkLiteParseUtils.parseMonolithicPackageLite(input,
2107                 pfd.getFileDescriptor(), debugPathName, flags);
2108         if (result.isError()) {
2109             throw new PackageParsingException(result.getErrorCode(), result.getErrorMessage());
2110         }
2111         return new InstallInfo(result);
2112     }
2113 
2114     // (b/239722738) This class serves as a bridge between the PackageLite class, which
2115     // is a hidden class, and the consumers of this class. (e.g. InstallInstalling.java)
2116     // This is a part of an effort to remove dependency on hidden APIs and use SystemAPIs or
2117     // public APIs.
2118     /**
2119      * Install related details from an APK or a folder of APK(s).
2120      *
2121      * @hide
2122      */
2123     @SystemApi
2124     public static class InstallInfo {
2125 
2126         /** @hide */
2127         @IntDef(prefix = { "INSTALL_LOCATION_" }, value = {
2128                 INSTALL_LOCATION_AUTO,
2129                 INSTALL_LOCATION_INTERNAL_ONLY,
2130                 INSTALL_LOCATION_PREFER_EXTERNAL
2131         })
2132         @Retention(RetentionPolicy.SOURCE)
2133         public @interface InstallLocation{}
2134 
2135         private PackageLite mPkg;
2136 
InstallInfo(ParseResult<PackageLite> result)2137         InstallInfo(ParseResult<PackageLite> result) {
2138             mPkg = result.getResult();
2139         }
2140 
2141         /**
2142          * See {@link PackageLite#getPackageName()}
2143          */
2144         @NonNull
getPackageName()2145         public String getPackageName() {
2146             return mPkg.getPackageName();
2147         }
2148 
2149         /**
2150          * @return The default install location defined by an application in
2151          * {@link android.R.attr#installLocation} attribute.
2152          */
getInstallLocation()2153         public @InstallLocation int getInstallLocation() {
2154             return mPkg.getInstallLocation();
2155         }
2156 
2157         /**
2158          * @param params {@link SessionParams} of the installation
2159          * @return Total disk space occupied by an application after installation.
2160          * Includes the size of the raw APKs, possibly unpacked resources, raw dex metadata files,
2161          * and all relevant native code.
2162          * @throws IOException when size of native binaries cannot be calculated.
2163          */
calculateInstalledSize(@onNull SessionParams params)2164         public long calculateInstalledSize(@NonNull SessionParams params) throws IOException {
2165             return InstallLocationUtils.calculateInstalledSize(mPkg, params.abiOverride);
2166         }
2167 
2168         /**
2169          * @param params {@link SessionParams} of the installation
2170          * @param pfd of an APK opened for read
2171          * @return Total disk space occupied by an application after installation.
2172          * Includes the size of the raw APKs, possibly unpacked resources, raw dex metadata files,
2173          * and all relevant native code.
2174          * @throws IOException when size of native binaries cannot be calculated.
2175          * @hide
2176          */
calculateInstalledSize(@onNull SessionParams params, @NonNull ParcelFileDescriptor pfd)2177         public long calculateInstalledSize(@NonNull SessionParams params,
2178                 @NonNull ParcelFileDescriptor pfd) throws IOException {
2179             return InstallLocationUtils.calculateInstalledSize(mPkg, params.abiOverride,
2180                     pfd.getFileDescriptor());
2181         }
2182     }
2183 
2184     /**
2185      * Generic exception class for using with parsing operations.
2186      *
2187      * @hide
2188      */
2189     @SystemApi
2190     public static class PackageParsingException extends Exception {
2191         private final int mErrorCode;
2192 
2193         /** {@hide} */
PackageParsingException(int errorCode, @Nullable String detailedMessage)2194         public PackageParsingException(int errorCode, @Nullable String detailedMessage) {
2195             super(detailedMessage);
2196             mErrorCode = errorCode;
2197         }
2198 
getErrorCode()2199         public int getErrorCode() {
2200             return mErrorCode;
2201         }
2202     }
2203 
2204     /**
2205      * Parameters for creating a new {@link PackageInstaller.Session}.
2206      */
2207     public static class SessionParams implements Parcelable {
2208 
2209         /** {@hide} */
2210         public static final int MODE_INVALID = -1;
2211 
2212         /**
2213          * Mode for an install session whose staged APKs should fully replace any
2214          * existing APKs for the target app.
2215          */
2216         public static final int MODE_FULL_INSTALL = 1;
2217 
2218         /**
2219          * Mode for an install session that should inherit any existing APKs for the
2220          * target app, unless they have been explicitly overridden (based on split
2221          * name) by the session. For example, this can be used to add one or more
2222          * split APKs to an existing installation.
2223          * <p>
2224          * If there are no existing APKs for the target app, this behaves like
2225          * {@link #MODE_FULL_INSTALL}.
2226          */
2227         public static final int MODE_INHERIT_EXISTING = 2;
2228 
2229         /**
2230          * Special constant to refer to all restricted permissions.
2231          */
2232         public static final @NonNull Set<String> RESTRICTED_PERMISSIONS_ALL = new ArraySet<>();
2233 
2234         /** {@hide} */
2235         public static final int UID_UNKNOWN = -1;
2236 
2237         /**
2238          * This value is derived from the maximum file name length. No package above this limit
2239          * can ever be successfully installed on the device.
2240          * @hide
2241          */
2242         public static final int MAX_PACKAGE_NAME_LENGTH = 255;
2243 
2244         /** @hide */
2245         @IntDef(prefix = {"USER_ACTION_"}, value = {
2246                 USER_ACTION_UNSPECIFIED,
2247                 USER_ACTION_REQUIRED,
2248                 USER_ACTION_NOT_REQUIRED
2249         })
2250         @Retention(RetentionPolicy.SOURCE)
2251         public @interface UserActionRequirement {}
2252 
2253         /**
2254          * This value is passed by the installer to {@link SessionParams#setRequireUserAction(int)}
2255          * to indicate that user action is unspecified for this install.
2256          * {@code requireUserAction} also defaults to this value unless modified by
2257          * {@link SessionParams#setRequireUserAction(int)}
2258          */
2259         public static final int USER_ACTION_UNSPECIFIED = 0;
2260 
2261         /**
2262          * This value is passed by the installer to {@link SessionParams#setRequireUserAction(int)}
2263          * to indicate that user action is required for this install.
2264          */
2265         public static final int USER_ACTION_REQUIRED = 1;
2266 
2267         /**
2268          * This value is passed by the installer to {@link SessionParams#setRequireUserAction(int)}
2269          * to indicate that user action is not required for this install.
2270          */
2271         public static final int USER_ACTION_NOT_REQUIRED = 2;
2272 
2273         /** @hide */
2274         @IntDef(prefix = {"PERMISSION_STATE_"}, value = {
2275                 PERMISSION_STATE_DEFAULT,
2276                 PERMISSION_STATE_GRANTED,
2277                 PERMISSION_STATE_DENIED,
2278         })
2279         @Retention(RetentionPolicy.SOURCE)
2280         public @interface PermissionState {}
2281 
2282         /**
2283          * Value is passed by the installer to {@link #setPermissionState(String, int)} to set
2284          * the state of a permission. This indicates no preference by the installer, relying on
2285          * the device's default policy to set the grant state of the permission.
2286          */
2287         public static final int PERMISSION_STATE_DEFAULT = 0;
2288 
2289         /**
2290          * Value is passed by the installer to {@link #setPermissionState(String, int)} to set
2291          * the state of a permission. This indicates the installers wants to automatically grant
2292          * the permission to the package being installed. The user and other actors in the system
2293          * may still be able to deny the permission after installation.
2294          */
2295         public static final int PERMISSION_STATE_GRANTED = 1;
2296 
2297         /**
2298          * Value is passed by the installer to {@link #setPermissionState(String, int)} to set
2299          * the state of a permission. This indicates the installers wants to deny the permission
2300          * by default to the package being installed. The user and other actors in the system may
2301          * still be able to grant the permission after installation.
2302          */
2303         public static final int PERMISSION_STATE_DENIED = 2;
2304 
2305         /** {@hide} */
2306         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
2307         public int mode = MODE_INVALID;
2308         /** {@hide} */
2309         @UnsupportedAppUsage
2310         public int installFlags = PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS;
2311         /** {@hide} */
2312         public int installLocation = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY;
2313         /** {@hide} */
2314         public @InstallReason int installReason = PackageManager.INSTALL_REASON_UNKNOWN;
2315         /**
2316          * {@hide}
2317          *
2318          * This flag indicates which installation scenario best describes this session.  The system
2319          * may use this value when making decisions about how to handle the installation, such as
2320          * prioritizing system health or user experience.
2321          */
2322         public @InstallScenario int installScenario = PackageManager.INSTALL_SCENARIO_DEFAULT;
2323         /** {@hide} */
2324         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
2325         public long sizeBytes = -1;
2326         /** {@hide} */
2327         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
2328         public String appPackageName;
2329         /** {@hide} */
2330         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
2331         public Bitmap appIcon;
2332         /** {@hide} */
2333         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
2334         public String appLabel;
2335         /** {@hide} */
2336         public long appIconLastModified = -1;
2337         /** {@hide} */
2338         public Uri originatingUri;
2339         /** {@hide} */
2340         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
2341         public int originatingUid = UID_UNKNOWN;
2342         /** {@hide} */
2343         public Uri referrerUri;
2344         /** {@hide} */
2345         public String abiOverride;
2346         /** {@hide} */
2347         public String volumeUuid;
2348         /** {@hide} */
2349         public List<String> whitelistedRestrictedPermissions;
2350         /** {@hide} */
2351         public int autoRevokePermissionsMode = MODE_DEFAULT;
2352         /** {@hide} */
2353         public String installerPackageName;
2354         /** {@hide} */
2355         public boolean isMultiPackage;
2356         /** {@hide} */
2357         public int packageSource = PACKAGE_SOURCE_UNSPECIFIED;
2358         /** {@hide} */
2359         public boolean isStaged;
2360         /** {@hide} */
2361         public long requiredInstalledVersionCode = PackageManager.VERSION_CODE_HIGHEST;
2362         /** {@hide} */
2363         public DataLoaderParams dataLoaderParams;
2364         /** {@hide} */
2365         public int rollbackDataPolicy = PackageManager.ROLLBACK_DATA_POLICY_RESTORE;
2366         /** {@hide} */
2367         public boolean forceQueryableOverride;
2368         /** {@hide} */
2369         public int requireUserAction = USER_ACTION_UNSPECIFIED;
2370         /** {@hide} */
2371         public boolean applicationEnabledSettingPersistent = false;
2372 
2373         private final ArrayMap<String, Integer> mPermissionStates;
2374 
2375         /**
2376          * Construct parameters for a new package install session.
2377          *
2378          * @param mode one of {@link #MODE_FULL_INSTALL} or
2379          *            {@link #MODE_INHERIT_EXISTING} describing how the session
2380          *            should interact with an existing app.
2381          */
SessionParams(int mode)2382         public SessionParams(int mode) {
2383             this.mode = mode;
2384             mPermissionStates = new ArrayMap<>();
2385         }
2386 
2387         /** {@hide} */
SessionParams(Parcel source)2388         public SessionParams(Parcel source) {
2389             mode = source.readInt();
2390             installFlags = source.readInt();
2391             installLocation = source.readInt();
2392             installReason = source.readInt();
2393             installScenario = source.readInt();
2394             sizeBytes = source.readLong();
2395             appPackageName = source.readString();
2396             appIcon = source.readParcelable(null, android.graphics.Bitmap.class);
2397             appLabel = source.readString();
2398             originatingUri = source.readParcelable(null, android.net.Uri.class);
2399             originatingUid = source.readInt();
2400             referrerUri = source.readParcelable(null, android.net.Uri.class);
2401             abiOverride = source.readString();
2402             volumeUuid = source.readString();
2403             mPermissionStates = new ArrayMap<>();
2404             source.readMap(mPermissionStates, null, String.class, Integer.class);
2405             whitelistedRestrictedPermissions = source.createStringArrayList();
2406             autoRevokePermissionsMode = source.readInt();
2407             installerPackageName = source.readString();
2408             isMultiPackage = source.readBoolean();
2409             isStaged = source.readBoolean();
2410             forceQueryableOverride = source.readBoolean();
2411             requiredInstalledVersionCode = source.readLong();
2412             DataLoaderParamsParcel dataLoaderParamsParcel = source.readParcelable(
2413                     DataLoaderParamsParcel.class.getClassLoader(), android.content.pm.DataLoaderParamsParcel.class);
2414             if (dataLoaderParamsParcel != null) {
2415                 dataLoaderParams = new DataLoaderParams(dataLoaderParamsParcel);
2416             }
2417             rollbackDataPolicy = source.readInt();
2418             requireUserAction = source.readInt();
2419             packageSource = source.readInt();
2420             applicationEnabledSettingPersistent = source.readBoolean();
2421         }
2422 
2423         /** {@hide} */
copy()2424         public SessionParams copy() {
2425             SessionParams ret = new SessionParams(mode);
2426             ret.installFlags = installFlags;
2427             ret.installLocation = installLocation;
2428             ret.installReason = installReason;
2429             ret.installScenario = installScenario;
2430             ret.sizeBytes = sizeBytes;
2431             ret.appPackageName = appPackageName;
2432             ret.appIcon = appIcon;  // not a copy.
2433             ret.appLabel = appLabel;
2434             ret.originatingUri = originatingUri;  // not a copy, but immutable.
2435             ret.originatingUid = originatingUid;
2436             ret.referrerUri = referrerUri;  // not a copy, but immutable.
2437             ret.abiOverride = abiOverride;
2438             ret.volumeUuid = volumeUuid;
2439             ret.mPermissionStates.putAll(mPermissionStates);
2440             ret.whitelistedRestrictedPermissions = whitelistedRestrictedPermissions;
2441             ret.autoRevokePermissionsMode = autoRevokePermissionsMode;
2442             ret.installerPackageName = installerPackageName;
2443             ret.isMultiPackage = isMultiPackage;
2444             ret.isStaged = isStaged;
2445             ret.forceQueryableOverride = forceQueryableOverride;
2446             ret.requiredInstalledVersionCode = requiredInstalledVersionCode;
2447             ret.dataLoaderParams = dataLoaderParams;
2448             ret.rollbackDataPolicy = rollbackDataPolicy;
2449             ret.requireUserAction = requireUserAction;
2450             ret.packageSource = packageSource;
2451             ret.applicationEnabledSettingPersistent = applicationEnabledSettingPersistent;
2452             return ret;
2453         }
2454 
2455         /**
2456          * Check if there are hidden options set.
2457          *
2458          * <p>Hidden options are those options that cannot be verified via public or system-api
2459          * methods on {@link SessionInfo}.
2460          *
2461          * @return {@code true} if any hidden option is set.
2462          *
2463          * @hide
2464          */
areHiddenOptionsSet()2465         public boolean areHiddenOptionsSet() {
2466             return (installFlags & (PackageManager.INSTALL_REQUEST_DOWNGRADE
2467                     | PackageManager.INSTALL_ALLOW_DOWNGRADE
2468                     | PackageManager.INSTALL_DONT_KILL_APP
2469                     | PackageManager.INSTALL_INSTANT_APP
2470                     | PackageManager.INSTALL_FULL_APP
2471                     | PackageManager.INSTALL_VIRTUAL_PRELOAD
2472                     | PackageManager.INSTALL_ALLOCATE_AGGRESSIVE)) != installFlags
2473                     || abiOverride != null || volumeUuid != null;
2474         }
2475 
2476         /**
2477          * Provide value of {@link PackageInfo#installLocation}, which may be used
2478          * to determine where the app will be staged. Defaults to
2479          * {@link PackageInfo#INSTALL_LOCATION_INTERNAL_ONLY}.
2480          */
setInstallLocation(int installLocation)2481         public void setInstallLocation(int installLocation) {
2482             this.installLocation = installLocation;
2483         }
2484 
2485         /**
2486          * Optionally indicate the total size (in bytes) of all APKs that will be
2487          * delivered in this session. The system may use this to ensure enough disk
2488          * space exists before proceeding, or to estimate container size for
2489          * installations living on external storage.
2490          *
2491          * @see PackageInfo#INSTALL_LOCATION_AUTO
2492          * @see PackageInfo#INSTALL_LOCATION_PREFER_EXTERNAL
2493          */
setSize(long sizeBytes)2494         public void setSize(long sizeBytes) {
2495             this.sizeBytes = sizeBytes;
2496         }
2497 
2498         /**
2499          * Optionally set the package name of the app being installed. It's strongly
2500          * recommended that you provide this value when known, so that observers can
2501          * communicate installing apps to users.
2502          * <p>
2503          * If the APKs staged in the session aren't consistent with this package
2504          * name, the install will fail. Regardless of this value, all APKs in the
2505          * app must have the same package name.
2506          */
setAppPackageName(@ullable String appPackageName)2507         public void setAppPackageName(@Nullable String appPackageName) {
2508             this.appPackageName = appPackageName;
2509         }
2510 
2511         /**
2512          * Optionally set an icon representing the app being installed. This should
2513          * be roughly {@link ActivityManager#getLauncherLargeIconSize()} in both
2514          * dimensions.
2515          */
setAppIcon(@ullable Bitmap appIcon)2516         public void setAppIcon(@Nullable Bitmap appIcon) {
2517             this.appIcon = appIcon;
2518         }
2519 
2520         /**
2521          * Optionally set a label representing the app being installed.
2522          *
2523          * This value will be trimmed to the first 1000 characters.
2524          */
setAppLabel(@ullable CharSequence appLabel)2525         public void setAppLabel(@Nullable CharSequence appLabel) {
2526             this.appLabel = (appLabel != null) ? appLabel.toString() : null;
2527         }
2528 
2529         /**
2530          * Optionally set the URI where this package was downloaded from. This is
2531          * informational and may be used as a signal for anti-malware purposes.
2532          *
2533          * @see Intent#EXTRA_ORIGINATING_URI
2534          */
setOriginatingUri(@ullable Uri originatingUri)2535         public void setOriginatingUri(@Nullable Uri originatingUri) {
2536             this.originatingUri = originatingUri;
2537         }
2538 
2539         /**
2540          * Sets the UID that initiated the package installation. This is informational
2541          * and may be used as a signal for anti-malware purposes.
2542          */
setOriginatingUid(int originatingUid)2543         public void setOriginatingUid(int originatingUid) {
2544             this.originatingUid = originatingUid;
2545         }
2546 
2547         /**
2548          * Optionally set the URI that referred you to install this package. This is
2549          * informational and may be used as a signal for anti-malware purposes.
2550          *
2551          * @see Intent#EXTRA_REFERRER
2552          */
setReferrerUri(@ullable Uri referrerUri)2553         public void setReferrerUri(@Nullable Uri referrerUri) {
2554             this.referrerUri = referrerUri;
2555         }
2556 
2557         /**
2558          * Sets which runtime permissions to be granted to the package at installation.
2559          *
2560          * @param permissions The permissions to grant or null to grant all runtime
2561          *     permissions.
2562          *
2563          * @deprecated Prefer {@link #setPermissionState(String, int)} instead starting in
2564          * {@link Build.VERSION_CODES#UPSIDE_DOWN_CAKE}.
2565          * @hide
2566          */
2567         @Deprecated
2568         @SystemApi
2569         @RequiresPermission(android.Manifest.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS)
setGrantedRuntimePermissions(String[] permissions)2570         public void setGrantedRuntimePermissions(String[] permissions) {
2571             if (permissions == null) {
2572                 // The new API has no mechanism to grant all requested permissions
2573                 installFlags |= PackageManager.INSTALL_GRANT_ALL_REQUESTED_PERMISSIONS;
2574                 mPermissionStates.clear();
2575             } else {
2576                 installFlags &= ~PackageManager.INSTALL_GRANT_ALL_REQUESTED_PERMISSIONS;
2577                 // Otherwise call the new API to grant the permissions specified
2578                 for (String permission : permissions) {
2579                     setPermissionState(permission, PERMISSION_STATE_GRANTED);
2580                 }
2581             }
2582         }
2583 
2584         /**
2585          * Sets the state of permissions for the package at installation.
2586          * <p/>
2587          * Granting any runtime permissions require the
2588          * {@link android.Manifest.permission#INSTALL_GRANT_RUNTIME_PERMISSIONS
2589          * INSTALL_GRANT_RUNTIME_PERMISSIONS} permission to be held by the caller. Revoking runtime
2590          * permissions is not allowed, even during app update sessions.
2591          * <p/>
2592          * Holders without the permission are allowed to change the following special permissions:
2593          * <p/>
2594          * On platform {@link Build.VERSION_CODES#UPSIDE_DOWN_CAKE UPSIDE_DOWN_CAKE}:
2595          * <ul>
2596          *     <li>{@link Manifest.permission#USE_FULL_SCREEN_INTENT}</li>
2597          * </ul>
2598          * Install time permissions, which cannot be revoked by the user, cannot be changed by the
2599          * installer.
2600          * <p/>
2601          * See <a href="https://developer.android.com/guide/topics/permissions/overview">
2602          * Permissions on Android</a> for more information.
2603          *
2604          * @param permissionName The permission to change state for.
2605          * @param state          Either {@link #PERMISSION_STATE_DEFAULT},
2606          *                       {@link #PERMISSION_STATE_GRANTED},
2607          *                       or {@link #PERMISSION_STATE_DENIED} to set the permission to.
2608          *
2609          * @return This object for easier chaining.
2610          */
2611         @RequiresPermission(value = android.Manifest.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS,
2612                 conditional = true)
2613         @NonNull
setPermissionState(@onNull String permissionName, @PermissionState int state)2614         public SessionParams setPermissionState(@NonNull String permissionName,
2615                 @PermissionState int state) {
2616             if (TextUtils.isEmpty(permissionName)) {
2617                 throw new IllegalArgumentException("Provided permissionName cannot be "
2618                         + (permissionName == null ? "null" : "empty"));
2619             }
2620 
2621             switch (state) {
2622                 case PERMISSION_STATE_DEFAULT:
2623                     mPermissionStates.remove(permissionName);
2624                     break;
2625                 case PERMISSION_STATE_GRANTED:
2626                 case PERMISSION_STATE_DENIED:
2627                     mPermissionStates.put(permissionName, state);
2628                     break;
2629                 default:
2630                     throw new IllegalArgumentException("Unexpected permission state int: " + state);
2631             }
2632 
2633             return this;
2634         }
2635 
2636         /** @hide */
setPermissionStates(Collection<String> grantPermissions, Collection<String> denyPermissions)2637         public void setPermissionStates(Collection<String> grantPermissions,
2638                 Collection<String> denyPermissions) {
2639             for (String grantPermission : grantPermissions) {
2640                 mPermissionStates.put(grantPermission, PERMISSION_STATE_GRANTED);
2641             }
2642             for (String denyPermission : denyPermissions) {
2643                 mPermissionStates.put(denyPermission, PERMISSION_STATE_DENIED);
2644             }
2645         }
2646 
2647         /**
2648          * Optionally indicate the package source of the app being installed. This is
2649          * informational and may be used as a signal by the system.
2650          *
2651          * An installer should specify {@link #PACKAGE_SOURCE_OTHER} if no other package source
2652          * constant adequately reflects the source for this session.
2653          *
2654          * The default value is {@link #PACKAGE_SOURCE_UNSPECIFIED}.
2655          */
setPackageSource(@ackageSourceType int packageSource)2656         public void setPackageSource(@PackageSourceType int packageSource) {
2657             this.packageSource = packageSource;
2658         }
2659 
2660         /**
2661          * Sets which restricted permissions to be allowlisted for the app. Allowlisting
2662          * is not granting the permissions, rather it allows the app to hold permissions
2663          * which are otherwise restricted. Allowlisting a non restricted permission has
2664          * no effect.
2665          *
2666          * <p> Permissions can be hard restricted which means that the app cannot hold
2667          * them or soft restricted where the app can hold the permission but in a weaker
2668          * form. Whether a permission is {@link PermissionInfo#FLAG_HARD_RESTRICTED hard
2669          * restricted} or {@link PermissionInfo#FLAG_SOFT_RESTRICTED soft restricted}
2670          * depends on the permission declaration. Allowlisting a hard restricted permission
2671          * allows the app to hold that permission and allowlisting a soft restricted
2672          * permission allows the app to hold the permission in its full, unrestricted form.
2673          *
2674          * <p> Permissions can also be immutably restricted which means that the allowlist
2675          * state of the permission can be determined only at install time and cannot be
2676          * changed on updated or at a later point via the package manager APIs.
2677          *
2678          * <p>Initially, all restricted permissions are allowlisted but you can change
2679          * which ones are allowlisted by calling this method or the corresponding ones
2680          * on the {@link PackageManager}. Only soft or hard restricted permissions on the current
2681          * Android version are supported and any invalid entries will be removed.
2682          *
2683          * @see PackageManager#addWhitelistedRestrictedPermission(String, String, int)
2684          * @see PackageManager#removeWhitelistedRestrictedPermission(String, String, int)
2685          */
setWhitelistedRestrictedPermissions(@ullable Set<String> permissions)2686         public void setWhitelistedRestrictedPermissions(@Nullable Set<String> permissions) {
2687             if (permissions == RESTRICTED_PERMISSIONS_ALL) {
2688                 installFlags |= PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS;
2689                 whitelistedRestrictedPermissions = null;
2690             } else {
2691                 installFlags &= ~PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS;
2692                 whitelistedRestrictedPermissions = (permissions != null)
2693                         ? new ArrayList<>(permissions) : null;
2694             }
2695         }
2696 
2697         /**
2698          * Sets whether permissions should be auto-revoked if this package is unused for an
2699          * extended periodd of time.
2700          *
2701          * It's disabled by default but generally the installer should enable it for most packages,
2702          * excluding only those where doing so might cause breakage that cannot be easily addressed
2703          * by simply re-requesting the permission(s).
2704          *
2705          * If user explicitly enabled or disabled it via settings, this call is ignored.
2706          *
2707          * @param shouldAutoRevoke whether permissions should be auto-revoked.
2708          *
2709          * @deprecated No longer used
2710          */
2711         @Deprecated
setAutoRevokePermissionsMode(boolean shouldAutoRevoke)2712         public void setAutoRevokePermissionsMode(boolean shouldAutoRevoke) {
2713             autoRevokePermissionsMode = shouldAutoRevoke ? MODE_ALLOWED : MODE_IGNORED;
2714         }
2715 
2716         /**
2717          * Request that rollbacks be enabled or disabled for the given upgrade with rollback data
2718          * policy set to RESTORE.
2719          *
2720          * <p>If the parent session is staged or has rollback enabled, all children sessions
2721          * must have the same properties.
2722          *
2723          * @param enable set to {@code true} to enable, {@code false} to disable
2724          * @see SessionParams#setEnableRollback(boolean, int)
2725          * @hide
2726          */
2727         @SystemApi
setEnableRollback(boolean enable)2728         public void setEnableRollback(boolean enable) {
2729             if (enable) {
2730                 installFlags |= PackageManager.INSTALL_ENABLE_ROLLBACK;
2731             } else {
2732                 installFlags &= ~PackageManager.INSTALL_ENABLE_ROLLBACK;
2733             }
2734             rollbackDataPolicy = PackageManager.ROLLBACK_DATA_POLICY_RESTORE;
2735         }
2736 
2737         /**
2738          * Request that rollbacks be enabled or disabled for the given upgrade.
2739          *
2740          * <p>If the parent session is staged or has rollback enabled, all children sessions
2741          * must have the same properties.
2742          *
2743          * <p> For a multi-package install, this method must be called on each child session to
2744          * specify rollback data policies explicitly. Note each child session is allowed to have
2745          * different policies.
2746          *
2747          * @param enable set to {@code true} to enable, {@code false} to disable
2748          * @param dataPolicy the rollback data policy for this session
2749          * @hide
2750          */
2751         @SystemApi
setEnableRollback(boolean enable, @PackageManager.RollbackDataPolicy int dataPolicy)2752         public void setEnableRollback(boolean enable,
2753                 @PackageManager.RollbackDataPolicy int dataPolicy) {
2754             if (enable) {
2755                 installFlags |= PackageManager.INSTALL_ENABLE_ROLLBACK;
2756             } else {
2757                 installFlags &= ~PackageManager.INSTALL_ENABLE_ROLLBACK;
2758             }
2759             rollbackDataPolicy = dataPolicy;
2760         }
2761 
2762 
2763         /**
2764          * @deprecated use {@link #setRequestDowngrade(boolean)}.
2765          * {@hide}
2766          */
2767         @SystemApi
2768         @Deprecated
setAllowDowngrade(boolean allowDowngrade)2769         public void setAllowDowngrade(boolean allowDowngrade) {
2770             setRequestDowngrade(allowDowngrade);
2771         }
2772 
2773         /** {@hide} */
2774         @SystemApi
setRequestDowngrade(boolean requestDowngrade)2775         public void setRequestDowngrade(boolean requestDowngrade) {
2776             if (requestDowngrade) {
2777                 installFlags |= PackageManager.INSTALL_REQUEST_DOWNGRADE;
2778             } else {
2779                 installFlags &= ~PackageManager.INSTALL_REQUEST_DOWNGRADE;
2780             }
2781         }
2782 
2783         /**
2784          * Require the given version of the package be installed.
2785          * The install will only be allowed if the existing version code of
2786          * the package installed on the device matches the given version code.
2787          * Use {@link * PackageManager#VERSION_CODE_HIGHEST} to allow
2788          * installation regardless of the currently installed package version.
2789          *
2790          * @hide
2791          */
setRequiredInstalledVersionCode(long versionCode)2792         public void setRequiredInstalledVersionCode(long versionCode) {
2793             requiredInstalledVersionCode = versionCode;
2794         }
2795 
2796         /** {@hide} */
setInstallFlagsForcePermissionPrompt()2797         public void setInstallFlagsForcePermissionPrompt() {
2798             installFlags |= PackageManager.INSTALL_FORCE_PERMISSION_PROMPT;
2799         }
2800 
2801         /**
2802          * Requests that the system not kill any of the package's running
2803          * processes as part of a {@link SessionParams#MODE_INHERIT_EXISTING}
2804          * session in which splits being added. By default, all installs will
2805          * result in the package's running processes being killed before the
2806          * install completes.
2807          *
2808          * @param dontKillApp set to {@code true} to request that the processes
2809          *                    belonging to the package not be killed as part of
2810          *                    this install.
2811          */
setDontKillApp(boolean dontKillApp)2812         public void setDontKillApp(boolean dontKillApp) {
2813             if (dontKillApp) {
2814                 installFlags |= PackageManager.INSTALL_DONT_KILL_APP;
2815             } else {
2816                 installFlags &= ~PackageManager.INSTALL_DONT_KILL_APP;
2817             }
2818         }
2819 
2820         /** {@hide} */
2821         @SystemApi
setInstallAsInstantApp(boolean isInstantApp)2822         public void setInstallAsInstantApp(boolean isInstantApp) {
2823             if (isInstantApp) {
2824                 installFlags |= PackageManager.INSTALL_INSTANT_APP;
2825                 installFlags &= ~PackageManager.INSTALL_FULL_APP;
2826             } else {
2827                 installFlags &= ~PackageManager.INSTALL_INSTANT_APP;
2828                 installFlags |= PackageManager.INSTALL_FULL_APP;
2829             }
2830         }
2831 
2832         /**
2833          * Sets the install as a virtual preload. Will only have effect when called
2834          * by the verifier.
2835          * {@hide}
2836          */
2837         @SystemApi
setInstallAsVirtualPreload()2838         public void setInstallAsVirtualPreload() {
2839             installFlags |= PackageManager.INSTALL_VIRTUAL_PRELOAD;
2840         }
2841 
2842         /**
2843          * Set the reason for installing this package.
2844          * <p>
2845          * The install reason should be a pre-defined integer. The behavior is
2846          * undefined if other values are used.
2847          *
2848          * @see PackageManager#INSTALL_REASON_UNKNOWN
2849          * @see PackageManager#INSTALL_REASON_POLICY
2850          * @see PackageManager#INSTALL_REASON_DEVICE_RESTORE
2851          * @see PackageManager#INSTALL_REASON_DEVICE_SETUP
2852          * @see PackageManager#INSTALL_REASON_USER
2853          */
setInstallReason(@nstallReason int installReason)2854         public void setInstallReason(@InstallReason int installReason) {
2855             this.installReason = installReason;
2856         }
2857 
2858         /** {@hide} */
2859         @SystemApi
2860         @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE)
setAllocateAggressive(boolean allocateAggressive)2861         public void setAllocateAggressive(boolean allocateAggressive) {
2862             if (allocateAggressive) {
2863                 installFlags |= PackageManager.INSTALL_ALLOCATE_AGGRESSIVE;
2864             } else {
2865                 installFlags &= ~PackageManager.INSTALL_ALLOCATE_AGGRESSIVE;
2866             }
2867         }
2868 
2869         /**
2870          * @hide
2871          */
2872         @TestApi
setInstallFlagAllowTest()2873         public void setInstallFlagAllowTest() {
2874             installFlags |= PackageManager.INSTALL_ALLOW_TEST;
2875         }
2876 
2877         /**
2878          * Set the installer package for the app.
2879          *
2880          * By default this is the app that created the {@link PackageInstaller} object.
2881          *
2882          * @param installerPackageName name of the installer package
2883          */
setInstallerPackageName(@ullable String installerPackageName)2884         public void setInstallerPackageName(@Nullable String installerPackageName) {
2885             this.installerPackageName = installerPackageName;
2886         }
2887 
2888         /**
2889          * Set this session to be the parent of a multi-package install.
2890          *
2891          * A multi-package install session contains no APKs and only references other install
2892          * sessions via ID. When a multi-package session is committed, all of its children
2893          * are committed to the system in an atomic manner. If any children fail to install,
2894          * all of them do, including the multi-package session.
2895          */
setMultiPackage()2896         public void setMultiPackage() {
2897             this.isMultiPackage = true;
2898         }
2899 
2900         /**
2901          * Set this session to be staged to be installed at reboot.
2902          *
2903          * Staged sessions are scheduled to be installed at next reboot. Staged sessions can also be
2904          * multi-package. In that case, if any of the children sessions fail to install at reboot,
2905          * all the other children sessions are aborted as well.
2906          *
2907          * <p>If the parent session is staged or has rollback enabled, all children sessions
2908          * must have the same properties.
2909          *
2910          * {@hide}
2911          */
2912         @SystemApi
2913         @RequiresPermission(Manifest.permission.INSTALL_PACKAGES)
setStaged()2914         public void setStaged() {
2915             this.isStaged = true;
2916         }
2917 
2918         /**
2919          * Set this session to be installing an APEX package.
2920          *
2921          * {@hide}
2922          */
2923         @SystemApi
2924         @RequiresPermission(Manifest.permission.INSTALL_PACKAGES)
setInstallAsApex()2925         public void setInstallAsApex() {
2926             installFlags |= PackageManager.INSTALL_APEX;
2927         }
2928 
2929         /** @hide */
getEnableRollback()2930         public boolean getEnableRollback() {
2931             return (installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0;
2932         }
2933 
2934         /**
2935          * Set the data loader params for the session.
2936          * This also switches installation into data loading mode and disallow direct writes into
2937          * staging folder.
2938          *
2939          * @see android.service.dataloader.DataLoaderService.DataLoader
2940          *
2941          * {@hide}
2942          */
2943         @SystemApi
2944         @RequiresPermission(allOf = {
2945                 Manifest.permission.INSTALL_PACKAGES,
2946                 Manifest.permission.USE_INSTALLER_V2})
setDataLoaderParams(@onNull DataLoaderParams dataLoaderParams)2947         public void setDataLoaderParams(@NonNull DataLoaderParams dataLoaderParams) {
2948             this.dataLoaderParams = dataLoaderParams;
2949         }
2950 
2951         /**
2952          *
2953          * {@hide}
2954          */
setForceQueryable()2955         public void setForceQueryable() {
2956             this.forceQueryableOverride = true;
2957         }
2958 
2959         /**
2960          * Optionally indicate whether user action should be required when the session is
2961          * committed.
2962          * <p>
2963          * Defaults to {@link #USER_ACTION_UNSPECIFIED} unless otherwise set. When unspecified for
2964          * installers using the
2965          * {@link android.Manifest.permission#REQUEST_INSTALL_PACKAGES REQUEST_INSTALL_PACKAGES}
2966          * permission will behave as if set to {@link #USER_ACTION_REQUIRED}, and
2967          * {@link #USER_ACTION_NOT_REQUIRED} otherwise. When {@code requireUserAction} is set to
2968          * {@link #USER_ACTION_REQUIRED}, installers will receive a
2969          * {@link #STATUS_PENDING_USER_ACTION} callback once the session is committed, indicating
2970          * that user action is required for the install to proceed.
2971          * <p>
2972          * For installers that have been granted the
2973          * {@link android.Manifest.permission#REQUEST_INSTALL_PACKAGES REQUEST_INSTALL_PACKAGES}
2974          * permission, user action will not be required when all of the following conditions are
2975          * met:
2976          *
2977          * <ul>
2978          *     <li>{@code requireUserAction} is set to {@link #USER_ACTION_NOT_REQUIRED}.</li>
2979          *     <li>The app being installed targets:
2980          *          <ul>
2981          *              <li>{@link android.os.Build.VERSION_CODES#Q API 29} or higher on
2982          *              Android S  ({@link android.os.Build.VERSION_CODES#S API 31})</li>
2983          *              <li>{@link android.os.Build.VERSION_CODES#R API 30} or higher on
2984          *              Android T ({@link android.os.Build.VERSION_CODES#TIRAMISU API 33})</li>
2985          *              <li>{@link android.os.Build.VERSION_CODES#S API 31} or higher <b>after</b>
2986          *              Android T ({@link android.os.Build.VERSION_CODES#TIRAMISU API 33})</li>
2987          *          </ul>
2988          *     </li>
2989          *     <li>The installer is:
2990          *         <ul>
2991          *             <li>The {@link InstallSourceInfo#getUpdateOwnerPackageName() update owner}
2992          *             of an existing version of the app (in other words, this install session is
2993          *             an app update) if the update ownership enforcement is enabled.</li>
2994          *             <li>The
2995          *             {@link InstallSourceInfo#getInstallingPackageName() installer of record}
2996          *             of an existing version of the app (in other words, this install
2997          *             session is an app update) if the update ownership enforcement isn't
2998          *             enabled.</li>
2999          *             <li>Updating itself.</li>
3000          *         </ul>
3001          *     </li>
3002          *     <li>The installer declares the
3003          *     {@link android.Manifest.permission#UPDATE_PACKAGES_WITHOUT_USER_ACTION
3004          *     UPDATE_PACKAGES_WITHOUT_USER_ACTION} permission.</li>
3005          * </ul>
3006          * <p>
3007          * Note: The target API level requirement will advance in future Android versions.
3008          * Session owners should always be prepared to handle {@link #STATUS_PENDING_USER_ACTION}.
3009          *
3010          * @param requireUserAction whether user action should be required.
3011          */
setRequireUserAction( @essionParams.UserActionRequirement int requireUserAction)3012         public void setRequireUserAction(
3013                 @SessionParams.UserActionRequirement int requireUserAction) {
3014             if (requireUserAction != USER_ACTION_UNSPECIFIED
3015                     && requireUserAction != USER_ACTION_REQUIRED
3016                     && requireUserAction != USER_ACTION_NOT_REQUIRED) {
3017                 throw new IllegalArgumentException("requireUserAction set as invalid value of "
3018                         + requireUserAction + ", but must be one of ["
3019                         + "USER_ACTION_UNSPECIFIED, USER_ACTION_REQUIRED, USER_ACTION_NOT_REQUIRED"
3020                         + "]");
3021             }
3022             this.requireUserAction = requireUserAction;
3023         }
3024 
3025         /**
3026          * Sets the install scenario for this session, which describes the expected user journey.
3027          */
setInstallScenario(@nstallScenario int installScenario)3028         public void setInstallScenario(@InstallScenario int installScenario) {
3029             this.installScenario = installScenario;
3030         }
3031 
3032         /**
3033          * Request to keep the original application enabled setting. This will prevent the
3034          * application from being enabled if it was previously in a disabled state.
3035          */
setApplicationEnabledSettingPersistent()3036         public void setApplicationEnabledSettingPersistent() {
3037             this.applicationEnabledSettingPersistent = true;
3038         }
3039 
3040         /**
3041          * Optionally indicate whether the package being installed needs the update ownership
3042          * enforcement. Once the update ownership enforcement is enabled, the other installers
3043          * will need the user action to update the package even if the installers have been
3044          * granted the {@link android.Manifest.permission#INSTALL_PACKAGES INSTALL_PACKAGES}
3045          * permission. Default to {@code false}.
3046          *
3047          * The update ownership enforcement can only be enabled on initial installation. Set
3048          * this to {@code true} on package update is a no-op.
3049          *
3050          * Note: To enable the update ownership enforcement, the installer must have the
3051          * {@link android.Manifest.permission#ENFORCE_UPDATE_OWNERSHIP ENFORCE_UPDATE_OWNERSHIP}
3052          * permission.
3053          */
3054         @RequiresPermission(Manifest.permission.ENFORCE_UPDATE_OWNERSHIP)
setRequestUpdateOwnership(boolean enable)3055         public void setRequestUpdateOwnership(boolean enable) {
3056             if (enable) {
3057                 this.installFlags |= PackageManager.INSTALL_REQUEST_UPDATE_OWNERSHIP;
3058             } else {
3059                 this.installFlags &= ~PackageManager.INSTALL_REQUEST_UPDATE_OWNERSHIP;
3060             }
3061         }
3062 
3063         /** @hide */
3064         @NonNull
getPermissionStates()3065         public ArrayMap<String, Integer> getPermissionStates() {
3066             return mPermissionStates;
3067         }
3068 
3069         /** @hide */
3070         @Nullable
getLegacyGrantedRuntimePermissions()3071         public String[] getLegacyGrantedRuntimePermissions() {
3072             if ((installFlags & PackageManager.INSTALL_GRANT_ALL_REQUESTED_PERMISSIONS) != 0) {
3073                 return null;
3074             }
3075 
3076             var grantedPermissions = new ArrayList<String>();
3077             for (int index = 0; index < mPermissionStates.size(); index++) {
3078                 var permissionName = mPermissionStates.keyAt(index);
3079                 var state = mPermissionStates.valueAt(index);
3080                 if (state == PERMISSION_STATE_GRANTED) {
3081                     grantedPermissions.add(permissionName);
3082                 }
3083             }
3084 
3085             return grantedPermissions.toArray(ArrayUtils.emptyArray(String.class));
3086         }
3087 
3088         /** {@hide} */
dump(IndentingPrintWriter pw)3089         public void dump(IndentingPrintWriter pw) {
3090             pw.printPair("mode", mode);
3091             pw.printHexPair("installFlags", installFlags);
3092             pw.printPair("installLocation", installLocation);
3093             pw.printPair("installReason", installReason);
3094             pw.printPair("installScenario", installScenario);
3095             pw.printPair("sizeBytes", sizeBytes);
3096             pw.printPair("appPackageName", appPackageName);
3097             pw.printPair("appIcon", (appIcon != null));
3098             pw.printPair("appLabel", appLabel);
3099             pw.printPair("originatingUri", originatingUri);
3100             pw.printPair("originatingUid", originatingUid);
3101             pw.printPair("referrerUri", referrerUri);
3102             pw.printPair("abiOverride", abiOverride);
3103             pw.printPair("volumeUuid", volumeUuid);
3104             pw.printPair("mPermissionStates", mPermissionStates);
3105             pw.printPair("packageSource", packageSource);
3106             pw.printPair("whitelistedRestrictedPermissions", whitelistedRestrictedPermissions);
3107             pw.printPair("autoRevokePermissions", autoRevokePermissionsMode);
3108             pw.printPair("installerPackageName", installerPackageName);
3109             pw.printPair("isMultiPackage", isMultiPackage);
3110             pw.printPair("isStaged", isStaged);
3111             pw.printPair("forceQueryable", forceQueryableOverride);
3112             pw.printPair("requireUserAction", SessionInfo.userActionToString(requireUserAction));
3113             pw.printPair("requiredInstalledVersionCode", requiredInstalledVersionCode);
3114             pw.printPair("dataLoaderParams", dataLoaderParams);
3115             pw.printPair("rollbackDataPolicy", rollbackDataPolicy);
3116             pw.printPair("applicationEnabledSettingPersistent",
3117                     applicationEnabledSettingPersistent);
3118             pw.println();
3119         }
3120 
3121         @Override
describeContents()3122         public int describeContents() {
3123             return 0;
3124         }
3125 
3126         @Override
writeToParcel(Parcel dest, int flags)3127         public void writeToParcel(Parcel dest, int flags) {
3128             dest.writeInt(mode);
3129             dest.writeInt(installFlags);
3130             dest.writeInt(installLocation);
3131             dest.writeInt(installReason);
3132             dest.writeInt(installScenario);
3133             dest.writeLong(sizeBytes);
3134             dest.writeString(appPackageName);
3135             dest.writeParcelable(appIcon, flags);
3136             dest.writeString(appLabel);
3137             dest.writeParcelable(originatingUri, flags);
3138             dest.writeInt(originatingUid);
3139             dest.writeParcelable(referrerUri, flags);
3140             dest.writeString(abiOverride);
3141             dest.writeString(volumeUuid);
3142             dest.writeMap(mPermissionStates);
3143             dest.writeStringList(whitelistedRestrictedPermissions);
3144             dest.writeInt(autoRevokePermissionsMode);
3145             dest.writeString(installerPackageName);
3146             dest.writeBoolean(isMultiPackage);
3147             dest.writeBoolean(isStaged);
3148             dest.writeBoolean(forceQueryableOverride);
3149             dest.writeLong(requiredInstalledVersionCode);
3150             if (dataLoaderParams != null) {
3151                 dest.writeParcelable(dataLoaderParams.getData(), flags);
3152             } else {
3153                 dest.writeParcelable(null, flags);
3154             }
3155             dest.writeInt(rollbackDataPolicy);
3156             dest.writeInt(requireUserAction);
3157             dest.writeInt(packageSource);
3158             dest.writeBoolean(applicationEnabledSettingPersistent);
3159         }
3160 
3161         public static final Parcelable.Creator<SessionParams>
3162                 CREATOR = new Parcelable.Creator<SessionParams>() {
3163                     @Override
3164                     public SessionParams createFromParcel(Parcel p) {
3165                         return new SessionParams(p);
3166                     }
3167 
3168                     @Override
3169                     public SessionParams[] newArray(int size) {
3170                         return new SessionParams[size];
3171                     }
3172                 };
3173     }
3174 
3175     /**
3176      * Details for an active install session.
3177      */
3178     public static class SessionInfo implements Parcelable {
3179 
3180         /**
3181          * A session ID that does not exist or is invalid.
3182          */
3183         public static final int INVALID_ID = -1;
3184         /** {@hide} */
3185         private static final int[] NO_SESSIONS = {};
3186 
3187         /**
3188          * @deprecated use {@link #SESSION_NO_ERROR}.
3189          */
3190         @Deprecated
3191         public static final int STAGED_SESSION_NO_ERROR = 0;
3192 
3193         /**
3194          * @deprecated use {@link #SESSION_VERIFICATION_FAILED}.
3195          */
3196         @Deprecated
3197         public static final int STAGED_SESSION_VERIFICATION_FAILED = 1;
3198 
3199         /**
3200          * @deprecated use {@link #SESSION_ACTIVATION_FAILED}.
3201          */
3202         @Deprecated
3203         public static final int STAGED_SESSION_ACTIVATION_FAILED = 2;
3204 
3205         /**
3206          * @deprecated use {@link #SESSION_UNKNOWN_ERROR}.
3207          */
3208         @Deprecated
3209         public static final int STAGED_SESSION_UNKNOWN = 3;
3210 
3211         /**
3212          * @deprecated use {@link #SESSION_CONFLICT}.
3213          */
3214         @Deprecated
3215         public static final int STAGED_SESSION_CONFLICT = 4;
3216 
3217         /**
3218          * Constant indicating that no error occurred during the preparation or the activation of
3219          * this session.
3220          */
3221         public static final int SESSION_NO_ERROR = 0;
3222 
3223         /**
3224          * Constant indicating that an error occurred during the verification phase of
3225          * this session.
3226          */
3227         public static final int SESSION_VERIFICATION_FAILED = 1;
3228 
3229         /**
3230          * Constant indicating that an error occurred during the activation phase of
3231          * this session.
3232          */
3233         public static final int SESSION_ACTIVATION_FAILED = 2;
3234 
3235         /**
3236          * Constant indicating that an unknown error occurred while processing this session.
3237          */
3238         public static final int SESSION_UNKNOWN_ERROR = 3;
3239 
3240         /**
3241          * Constant indicating that the session was in conflict with another session and had
3242          * to be sacrificed for resolution.
3243          */
3244         public static final int SESSION_CONFLICT = 4;
3245 
userActionToString(int requireUserAction)3246         private static String userActionToString(int requireUserAction) {
3247             switch(requireUserAction) {
3248                 case SessionParams.USER_ACTION_REQUIRED:
3249                     return "REQUIRED";
3250                 case SessionParams.USER_ACTION_NOT_REQUIRED:
3251                     return "NOT_REQUIRED";
3252                 default:
3253                     return "UNSPECIFIED";
3254             }
3255         }
3256 
3257         /** {@hide} */
3258         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
3259         public int sessionId;
3260         /** {@hide} */
3261         public int userId;
3262         /** {@hide} */
3263         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
3264         public String installerPackageName;
3265         /** {@hide} */
3266         public String installerAttributionTag;
3267         /** {@hide} */
3268         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
3269         public String resolvedBaseCodePath;
3270         /** {@hide} */
3271         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
3272         public float progress;
3273         /** {@hide} */
3274         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
3275         public boolean sealed;
3276         /** {@hide} */
3277         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
3278         public boolean active;
3279 
3280         /** {@hide} */
3281         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
3282         public int mode;
3283         /** {@hide} */
3284         public @InstallReason int installReason;
3285         /** {@hide} */
3286         public @InstallScenario int installScenario;
3287         /** {@hide} */
3288         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
3289         public long sizeBytes;
3290         /** {@hide} */
3291         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
3292         public String appPackageName;
3293         /** {@hide} */
3294         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
3295         public Bitmap appIcon;
3296         /** {@hide} */
3297         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
3298         public CharSequence appLabel;
3299 
3300         /** {@hide} */
3301         public int installLocation;
3302         /** {@hide} */
3303         public Uri originatingUri;
3304         /** {@hide} */
3305         public int originatingUid;
3306         /** {@hide} */
3307         public Uri referrerUri;
3308         /** {@hide} */
3309         public String[] grantedRuntimePermissions;
3310         /** {@hide}*/
3311         public List<String> whitelistedRestrictedPermissions;
3312         /** {@hide}*/
3313         public int autoRevokePermissionsMode = MODE_DEFAULT;
3314         /** {@hide} */
3315         public int installFlags;
3316         /** {@hide} */
3317         public boolean isMultiPackage;
3318         /** {@hide} */
3319         public boolean isStaged;
3320         /** {@hide} */
3321         public boolean forceQueryable;
3322         /** {@hide} */
3323         public int parentSessionId = INVALID_ID;
3324         /** {@hide} */
3325         public int[] childSessionIds = NO_SESSIONS;
3326 
3327         /** {@hide} */
3328         public boolean isSessionApplied;
3329         /** {@hide} */
3330         public boolean isSessionReady;
3331         /** {@hide} */
3332         public boolean isSessionFailed;
3333         private int mSessionErrorCode;
3334         private String mSessionErrorMessage;
3335 
3336         /** {@hide} */
3337         public boolean isCommitted;
3338 
3339         /** {@hide} */
3340         public long createdMillis;
3341 
3342         /** {@hide} */
3343         public long updatedMillis;
3344 
3345         /** {@hide} */
3346         public int rollbackDataPolicy;
3347 
3348         /** {@hide} */
3349         public int requireUserAction;
3350 
3351         /** {@hide} */
3352         public int packageSource = PACKAGE_SOURCE_UNSPECIFIED;
3353 
3354         /** {@hide} */
3355         public int installerUid;
3356 
3357         /** @hide */
3358         public boolean isPreapprovalRequested;
3359 
3360         /** @hide */
3361         public boolean applicationEnabledSettingPersistent;
3362 
3363         /** @hide */
3364         public int pendingUserActionReason;
3365 
3366         /** {@hide} */
3367         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
SessionInfo()3368         public SessionInfo() {
3369         }
3370 
3371         /** {@hide} */
SessionInfo(Parcel source)3372         public SessionInfo(Parcel source) {
3373             sessionId = source.readInt();
3374             userId = source.readInt();
3375             installerPackageName = source.readString();
3376             installerAttributionTag = source.readString();
3377             resolvedBaseCodePath = source.readString();
3378             progress = source.readFloat();
3379             sealed = source.readInt() != 0;
3380             active = source.readInt() != 0;
3381 
3382             mode = source.readInt();
3383             installReason = source.readInt();
3384             installScenario = source.readInt();
3385             sizeBytes = source.readLong();
3386             appPackageName = source.readString();
3387             appIcon = source.readParcelable(null, android.graphics.Bitmap.class);
3388             appLabel = source.readString();
3389 
3390             installLocation = source.readInt();
3391             originatingUri = source.readParcelable(null, android.net.Uri.class);
3392             originatingUid = source.readInt();
3393             referrerUri = source.readParcelable(null, android.net.Uri.class);
3394             grantedRuntimePermissions = source.readStringArray();
3395             whitelistedRestrictedPermissions = source.createStringArrayList();
3396             autoRevokePermissionsMode = source.readInt();
3397 
3398             installFlags = source.readInt();
3399             isMultiPackage = source.readBoolean();
3400             isStaged = source.readBoolean();
3401             forceQueryable = source.readBoolean();
3402             parentSessionId = source.readInt();
3403             childSessionIds = source.createIntArray();
3404             if (childSessionIds == null) {
3405                 childSessionIds = NO_SESSIONS;
3406             }
3407             isSessionApplied = source.readBoolean();
3408             isSessionReady = source.readBoolean();
3409             isSessionFailed = source.readBoolean();
3410             mSessionErrorCode = source.readInt();
3411             mSessionErrorMessage = source.readString();
3412             isCommitted = source.readBoolean();
3413             isPreapprovalRequested = source.readBoolean();
3414             rollbackDataPolicy = source.readInt();
3415             createdMillis = source.readLong();
3416             requireUserAction = source.readInt();
3417             installerUid = source.readInt();
3418             packageSource = source.readInt();
3419             applicationEnabledSettingPersistent = source.readBoolean();
3420             pendingUserActionReason = source.readInt();
3421         }
3422 
3423         /**
3424          * Return the ID for this session.
3425          */
getSessionId()3426         public int getSessionId() {
3427             return sessionId;
3428         }
3429 
3430         /**
3431          * Return the user associated with this session.
3432          */
getUser()3433         public @NonNull UserHandle getUser() {
3434             return new UserHandle(userId);
3435         }
3436 
3437         /**
3438          * Return the package name of the app that owns this session.
3439          */
getInstallerPackageName()3440         public @Nullable String getInstallerPackageName() {
3441             return installerPackageName;
3442         }
3443 
3444         /**
3445          * @return {@link android.content.Context#getAttributionTag attribution tag} of the context
3446          * that created this session
3447          */
getInstallerAttributionTag()3448         public @Nullable String getInstallerAttributionTag() {
3449             return installerAttributionTag;
3450         }
3451 
3452         /**
3453          * Return current overall progress of this session, between 0 and 1.
3454          * <p>
3455          * Note that this progress may not directly correspond to the value
3456          * reported by
3457          * {@link PackageInstaller.Session#setStagingProgress(float)}, as the
3458          * system may carve out a portion of the overall progress to represent
3459          * its own internal installation work.
3460          */
getProgress()3461         public float getProgress() {
3462             return progress;
3463         }
3464 
3465         /**
3466          * Return if this session is currently active.
3467          * <p>
3468          * A session is considered active whenever there is ongoing forward
3469          * progress being made, such as the installer holding an open
3470          * {@link Session} instance while streaming data into place, or the
3471          * system optimizing code as the result of
3472          * {@link Session#commit(IntentSender)}.
3473          * <p>
3474          * If the installer closes the {@link Session} without committing, the
3475          * session is considered inactive until the installer opens the session
3476          * again.
3477          */
isActive()3478         public boolean isActive() {
3479             return active;
3480         }
3481 
3482         /**
3483          * Return if this session is sealed.
3484          * <p>
3485          * Once sealed, no further changes may be made to the session. A session
3486          * is sealed the moment {@link Session#commit(IntentSender)} is called.
3487          */
isSealed()3488         public boolean isSealed() {
3489             return sealed;
3490         }
3491 
3492         /**
3493          * Return the reason for installing this package.
3494          *
3495          * @return The install reason.
3496          */
getInstallReason()3497         public @InstallReason int getInstallReason() {
3498             return installReason;
3499         }
3500 
3501         /** {@hide} */
3502         @Deprecated
isOpen()3503         public boolean isOpen() {
3504             return isActive();
3505         }
3506 
3507         /**
3508          * Return the package name this session is working with. May be {@code null}
3509          * if unknown.
3510          */
getAppPackageName()3511         public @Nullable String getAppPackageName() {
3512             return appPackageName;
3513         }
3514 
3515         /**
3516          * Return an icon representing the app being installed. May be {@code null}
3517          * if unavailable.
3518          */
getAppIcon()3519         public @Nullable Bitmap getAppIcon() {
3520             if (appIcon == null) {
3521                 // Icon may have been omitted for calls that return bulk session
3522                 // lists, so try fetching the specific icon.
3523                 try {
3524                     final SessionInfo info = AppGlobals.getPackageManager().getPackageInstaller()
3525                             .getSessionInfo(sessionId);
3526                     appIcon = (info != null) ? info.appIcon : null;
3527                 } catch (RemoteException e) {
3528                     throw e.rethrowFromSystemServer();
3529                 }
3530             }
3531             return appIcon;
3532         }
3533 
3534         /**
3535          * Return a label representing the app being installed. May be {@code null}
3536          * if unavailable.
3537          */
getAppLabel()3538         public @Nullable CharSequence getAppLabel() {
3539             return appLabel;
3540         }
3541 
3542         /**
3543          * Return an Intent that can be started to view details about this install
3544          * session. This may surface actions such as pause, resume, or cancel.
3545          * <p>
3546          * In some cases, a matching Activity may not exist, so ensure you safeguard
3547          * against this.
3548          *
3549          * @see PackageInstaller#ACTION_SESSION_DETAILS
3550          */
createDetailsIntent()3551         public @Nullable Intent createDetailsIntent() {
3552             final Intent intent = new Intent(PackageInstaller.ACTION_SESSION_DETAILS);
3553             intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
3554             intent.setPackage(installerPackageName);
3555             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
3556             return intent;
3557         }
3558 
3559         /**
3560          * Get the mode of the session as set in the constructor of the {@link SessionParams}.
3561          *
3562          * @return One of {@link SessionParams#MODE_FULL_INSTALL}
3563          *         or {@link SessionParams#MODE_INHERIT_EXISTING}
3564          */
getMode()3565         public int getMode() {
3566             return mode;
3567         }
3568 
3569         /**
3570          * Get the value set in {@link SessionParams#setInstallLocation(int)}.
3571          */
getInstallLocation()3572         public int getInstallLocation() {
3573             return installLocation;
3574         }
3575 
3576         /**
3577          * Get the value as set in {@link SessionParams#setSize(long)}.
3578          *
3579          * <p>The value is a hint and does not have to match the actual size.
3580          */
getSize()3581         public long getSize() {
3582             return sizeBytes;
3583         }
3584 
3585         /**
3586          * Get the value set in {@link SessionParams#setOriginatingUri(Uri)}.
3587          * Note: This value will only be non-null for the owner of the session.
3588          */
getOriginatingUri()3589         public @Nullable Uri getOriginatingUri() {
3590             return originatingUri;
3591         }
3592 
3593         /**
3594          * Get the value set in {@link SessionParams#setOriginatingUid(int)}.
3595          */
getOriginatingUid()3596         public int getOriginatingUid() {
3597             return originatingUid;
3598         }
3599 
3600         /**
3601          * Get the value set in {@link SessionParams#setReferrerUri(Uri)}
3602          * Note: This value will only be non-null for the owner of the session.
3603          */
getReferrerUri()3604         public @Nullable Uri getReferrerUri() {
3605             return referrerUri;
3606         }
3607 
3608         /**
3609          * @return the path to the validated base APK for this session, which may point at an
3610          * APK inside the session (when the session defines the base), or it may
3611          * point at the existing base APK (when adding splits to an existing app).
3612          *
3613          * @hide
3614          */
3615         @RequiresPermission(Manifest.permission.READ_INSTALLED_SESSION_PATHS)
getResolvedBaseApkPath()3616         public @Nullable String getResolvedBaseApkPath() {
3617             return resolvedBaseCodePath;
3618         }
3619 
3620         /**
3621          * Get the value set in {@link SessionParams#setGrantedRuntimePermissions(String[])}.
3622          *
3623          * @hide
3624          */
3625         @SystemApi
getGrantedRuntimePermissions()3626         public @Nullable String[] getGrantedRuntimePermissions() {
3627             return grantedRuntimePermissions;
3628         }
3629 
3630         /**
3631          * Get the value set in {@link SessionParams#setWhitelistedRestrictedPermissions(Set)}.
3632          * Note that if all permissions are allowlisted this method returns {@link
3633          * SessionParams#RESTRICTED_PERMISSIONS_ALL}.
3634          *
3635          * @hide
3636          */
3637         @SystemApi
getWhitelistedRestrictedPermissions()3638         public @NonNull Set<String> getWhitelistedRestrictedPermissions() {
3639             if ((installFlags & PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS) != 0) {
3640                 return SessionParams.RESTRICTED_PERMISSIONS_ALL;
3641             }
3642             if (whitelistedRestrictedPermissions != null) {
3643                 return new ArraySet<>(whitelistedRestrictedPermissions);
3644             }
3645             return Collections.emptySet();
3646         }
3647 
3648         /**
3649          * Get the status of whether permission auto-revocation should be allowed, ignored, or
3650          * deferred to manifest data.
3651          *
3652          * @see android.app.AppOpsManager#MODE_ALLOWED
3653          * @see android.app.AppOpsManager#MODE_IGNORED
3654          * @see android.app.AppOpsManager#MODE_DEFAULT
3655          *
3656          * @return the status of auto-revoke for this package
3657          *
3658          * @hide
3659          */
3660         @SystemApi
getAutoRevokePermissionsMode()3661         public int getAutoRevokePermissionsMode() {
3662             return autoRevokePermissionsMode;
3663         }
3664 
3665         /**
3666          * Get the value set in {@link SessionParams#setAllowDowngrade(boolean)}.
3667          *
3668          * @deprecated use {@link #getRequestDowngrade()}.
3669          * @hide
3670          */
3671         @SystemApi
3672         @Deprecated
getAllowDowngrade()3673         public boolean getAllowDowngrade() {
3674             return getRequestDowngrade();
3675         }
3676 
3677         /**
3678          * Get the value set in {@link SessionParams#setRequestDowngrade(boolean)}.
3679          *
3680          * @hide
3681          */
3682         @SystemApi
getRequestDowngrade()3683         public boolean getRequestDowngrade() {
3684             return (installFlags & PackageManager.INSTALL_REQUEST_DOWNGRADE) != 0;
3685         }
3686 
3687         /**
3688          * Get the value set in {@link SessionParams#setDontKillApp(boolean)}.
3689          */
getDontKillApp()3690         public boolean getDontKillApp() {
3691             return (installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0;
3692         }
3693 
3694         /**
3695          * Get if this session is to be installed as Instant Apps.
3696          *
3697          * @param isInstantApp an unused parameter and is ignored.
3698          * @return {@code true} if {@link SessionParams#setInstallAsInstantApp(boolean)} was called
3699          * with {@code true}; {@code false} if it was called with {@code false} or if it was not
3700          * called.
3701          *
3702          * @see #getInstallAsFullApp
3703          *
3704          * @hide
3705          */
3706         @SystemApi
getInstallAsInstantApp(boolean isInstantApp)3707         public boolean getInstallAsInstantApp(boolean isInstantApp) {
3708             return (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
3709         }
3710 
3711         /**
3712          * Get if this session is to be installed as full apps.
3713          *
3714          * @param isInstantApp an unused parameter and is ignored.
3715          * @return {@code true} if {@link SessionParams#setInstallAsInstantApp(boolean)} was called
3716          * with {@code false}; {code false} if it was called with {@code true} or if it was not
3717          * called.
3718          *
3719          * @see #getInstallAsInstantApp
3720          *
3721          * @hide
3722          */
3723         @SystemApi
getInstallAsFullApp(boolean isInstantApp)3724         public boolean getInstallAsFullApp(boolean isInstantApp) {
3725             return (installFlags & PackageManager.INSTALL_FULL_APP) != 0;
3726         }
3727 
3728         /**
3729          * Get if {@link SessionParams#setInstallAsVirtualPreload()} was called.
3730          *
3731          * @hide
3732          */
3733         @SystemApi
getInstallAsVirtualPreload()3734         public boolean getInstallAsVirtualPreload() {
3735             return (installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0;
3736         }
3737 
3738         /**
3739          * Return whether rollback is enabled or disabled for the given upgrade.
3740          *
3741          * @hide
3742          */
3743         @SystemApi
getEnableRollback()3744         public boolean getEnableRollback() {
3745             return (installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0;
3746         }
3747 
3748         /**
3749          * Get the value set in {@link SessionParams#setAllocateAggressive(boolean)}.
3750          *
3751          * @hide
3752          */
3753         @SystemApi
getAllocateAggressive()3754         public boolean getAllocateAggressive() {
3755             return (installFlags & PackageManager.INSTALL_ALLOCATE_AGGRESSIVE) != 0;
3756         }
3757 
3758 
3759         /** {@hide} */
3760         @Deprecated
getDetailsIntent()3761         public @Nullable Intent getDetailsIntent() {
3762             return createDetailsIntent();
3763         }
3764 
3765         /**
3766          * Get the package source that was set in
3767          * {@link PackageInstaller.SessionParams#setPackageSource(int)}.
3768          */
getPackageSource()3769         public @PackageSourceType int getPackageSource() {
3770             return packageSource;
3771         }
3772 
3773         /**
3774          * Returns true if this session is a multi-package session containing references to other
3775          * sessions.
3776          */
isMultiPackage()3777         public boolean isMultiPackage() {
3778             return isMultiPackage;
3779         }
3780 
3781         /**
3782          * Returns true if this session is a staged session.
3783          */
isStaged()3784         public boolean isStaged() {
3785             return isStaged;
3786         }
3787 
3788         /**
3789          * Return the data policy associated with the rollback for the given upgrade.
3790          *
3791          * @hide
3792          */
3793         @SystemApi
3794         @PackageManager.RollbackDataPolicy
getRollbackDataPolicy()3795         public int getRollbackDataPolicy() {
3796             return rollbackDataPolicy;
3797         }
3798 
3799         /**
3800          * Returns true if this session is marked as forceQueryable
3801          * {@hide}
3802          */
isForceQueryable()3803         public boolean isForceQueryable() {
3804             return forceQueryable;
3805         }
3806 
3807         /**
3808          * Returns {@code true} if this session is an active staged session.
3809          *
3810          * We consider a session active if it has been committed and it is either pending
3811          * verification, or will be applied at next reboot.
3812          *
3813          * <p>Staged session is active iff:
3814          * <ul>
3815          *     <li>It is committed, i.e. {@link SessionInfo#isCommitted()} is {@code true}, and
3816          *     <li>it is not applied, i.e. {@link SessionInfo#isStagedSessionApplied()} is {@code
3817          *     false}, and
3818          *     <li>it is not failed, i.e. {@link SessionInfo#isStagedSessionFailed()} is
3819          *     {@code false}.
3820          * </ul>
3821          *
3822          * <p>In case of a multi-package session, reasoning above is applied to the parent session,
3823          * since that is the one that should have been {@link Session#commit committed}.
3824          */
isStagedSessionActive()3825         public boolean isStagedSessionActive() {
3826             return isStaged && isCommitted && !isSessionApplied && !isSessionFailed
3827                     && !hasParentSessionId();
3828         }
3829 
3830         /**
3831          * Returns the parent multi-package session ID if this session belongs to one,
3832          * {@link #INVALID_ID} otherwise.
3833          */
getParentSessionId()3834         public int getParentSessionId() {
3835             return parentSessionId;
3836         }
3837 
3838         /**
3839          * Returns true if session has a valid parent session, otherwise false.
3840          */
hasParentSessionId()3841         public boolean hasParentSessionId() {
3842             return parentSessionId != INVALID_ID;
3843         }
3844 
3845         /**
3846          * Returns the set of session IDs that will be committed when this session is committed if
3847          * this session is a multi-package session.
3848          */
3849         @NonNull
getChildSessionIds()3850         public int[] getChildSessionIds() {
3851             return childSessionIds;
3852         }
3853 
checkSessionIsStaged()3854         private void checkSessionIsStaged() {
3855             if (!isStaged) {
3856                 throw new IllegalStateException("Session is not marked as staged.");
3857             }
3858         }
3859 
3860         /**
3861          * Whether the staged session has been applied successfully, meaning that all of its
3862          * packages have been activated and no further action is required.
3863          * Only meaningful if {@code isStaged} is true.
3864          */
isStagedSessionApplied()3865         public boolean isStagedSessionApplied() {
3866             checkSessionIsStaged();
3867             return isSessionApplied;
3868         }
3869 
3870         /**
3871          * Whether the staged session is ready to be applied at next reboot. Only meaningful if
3872          * {@code isStaged} is true.
3873          */
isStagedSessionReady()3874         public boolean isStagedSessionReady() {
3875             checkSessionIsStaged();
3876             return isSessionReady;
3877         }
3878 
3879         /**
3880          * Whether something went wrong and the staged session is declared as failed, meaning that
3881          * it will be ignored at next reboot. Only meaningful if {@code isStaged} is true.
3882          */
isStagedSessionFailed()3883         public boolean isStagedSessionFailed() {
3884             checkSessionIsStaged();
3885             return isSessionFailed;
3886         }
3887 
3888         /**
3889          * If something went wrong with a staged session, clients can check this error code to
3890          * understand which kind of failure happened. Only meaningful if {@code isStaged} is true.
3891          */
getStagedSessionErrorCode()3892         public int getStagedSessionErrorCode() {
3893             checkSessionIsStaged();
3894             return mSessionErrorCode;
3895         }
3896 
3897         /**
3898          * Text description of the error code returned by {@code getStagedSessionErrorCode}, or
3899          * empty string if no error was encountered.
3900          */
getStagedSessionErrorMessage()3901         public @NonNull String getStagedSessionErrorMessage() {
3902             checkSessionIsStaged();
3903             return mSessionErrorMessage;
3904         }
3905 
3906         /** {@hide} */
setSessionErrorCode(int errorCode, String errorMessage)3907         public void setSessionErrorCode(int errorCode, String errorMessage) {
3908             mSessionErrorCode = errorCode;
3909             mSessionErrorMessage = errorMessage;
3910         }
3911 
3912         /**
3913          * Returns {@code true} if {@link Session#commit(IntentSender)}} was called for this
3914          * session.
3915          */
isCommitted()3916         public boolean isCommitted() {
3917             return isCommitted;
3918         }
3919 
3920         /**
3921          * The timestamp of the initial creation of the session.
3922          */
getCreatedMillis()3923         public long getCreatedMillis() {
3924             return createdMillis;
3925         }
3926 
3927         /**
3928          * The timestamp of the last update that occurred to the session, including changing of
3929          * states in case of staged sessions.
3930          */
3931         @CurrentTimeMillisLong
getUpdatedMillis()3932         public long getUpdatedMillis() {
3933             return updatedMillis;
3934         }
3935 
3936         /**
3937          * Whether user action was required by the installer.
3938          *
3939          * <p>
3940          * Note: a return value of {@code USER_ACTION_NOT_REQUIRED} does not guarantee that the
3941          * install will not result in user action.
3942          *
3943          * @return {@link SessionParams#USER_ACTION_NOT_REQUIRED},
3944          *         {@link SessionParams#USER_ACTION_REQUIRED} or
3945          *         {@link SessionParams#USER_ACTION_UNSPECIFIED}
3946          */
3947         @SessionParams.UserActionRequirement
getRequireUserAction()3948         public int getRequireUserAction() {
3949             return requireUserAction;
3950         }
3951 
3952         /**
3953          * Returns the Uid of the owner of the session.
3954          */
getInstallerUid()3955         public int getInstallerUid() {
3956             return installerUid;
3957         }
3958 
3959         /**
3960          * Returns {@code true} if this session will keep the existing application enabled setting
3961          * after installation.
3962          */
isApplicationEnabledSettingPersistent()3963         public boolean isApplicationEnabledSettingPersistent() {
3964             return applicationEnabledSettingPersistent;
3965         }
3966 
3967         /**
3968          * Returns whether this session has requested user pre-approval.
3969          */
isPreApprovalRequested()3970         public boolean isPreApprovalRequested() {
3971             return isPreapprovalRequested;
3972         }
3973 
3974         /**
3975          * @return {@code true} if the installer requested the update ownership enforcement
3976          * for the packages in this session.
3977          *
3978          * @see PackageInstaller.SessionParams#setRequestUpdateOwnership
3979          */
isRequestUpdateOwnership()3980         public boolean isRequestUpdateOwnership() {
3981             return (installFlags & PackageManager.INSTALL_REQUEST_UPDATE_OWNERSHIP) != 0;
3982         }
3983 
3984         /**
3985          * Return the reason for requiring the user action.
3986          * @hide
3987          */
3988         @SystemApi
getPendingUserActionReason()3989         public @UserActionReason int getPendingUserActionReason() {
3990             return pendingUserActionReason;
3991         }
3992 
3993         @Override
describeContents()3994         public int describeContents() {
3995             return 0;
3996         }
3997 
3998         @Override
writeToParcel(Parcel dest, int flags)3999         public void writeToParcel(Parcel dest, int flags) {
4000             dest.writeInt(sessionId);
4001             dest.writeInt(userId);
4002             dest.writeString(installerPackageName);
4003             dest.writeString(installerAttributionTag);
4004             dest.writeString(resolvedBaseCodePath);
4005             dest.writeFloat(progress);
4006             dest.writeInt(sealed ? 1 : 0);
4007             dest.writeInt(active ? 1 : 0);
4008 
4009             dest.writeInt(mode);
4010             dest.writeInt(installReason);
4011             dest.writeInt(installScenario);
4012             dest.writeLong(sizeBytes);
4013             dest.writeString(appPackageName);
4014             dest.writeParcelable(appIcon, flags);
4015             dest.writeString(appLabel != null ? appLabel.toString() : null);
4016 
4017             dest.writeInt(installLocation);
4018             dest.writeParcelable(originatingUri, flags);
4019             dest.writeInt(originatingUid);
4020             dest.writeParcelable(referrerUri, flags);
4021             dest.writeStringArray(grantedRuntimePermissions);
4022             dest.writeStringList(whitelistedRestrictedPermissions);
4023             dest.writeInt(autoRevokePermissionsMode);
4024             dest.writeInt(installFlags);
4025             dest.writeBoolean(isMultiPackage);
4026             dest.writeBoolean(isStaged);
4027             dest.writeBoolean(forceQueryable);
4028             dest.writeInt(parentSessionId);
4029             dest.writeIntArray(childSessionIds);
4030             dest.writeBoolean(isSessionApplied);
4031             dest.writeBoolean(isSessionReady);
4032             dest.writeBoolean(isSessionFailed);
4033             dest.writeInt(mSessionErrorCode);
4034             dest.writeString(mSessionErrorMessage);
4035             dest.writeBoolean(isCommitted);
4036             dest.writeBoolean(isPreapprovalRequested);
4037             dest.writeInt(rollbackDataPolicy);
4038             dest.writeLong(createdMillis);
4039             dest.writeInt(requireUserAction);
4040             dest.writeInt(installerUid);
4041             dest.writeInt(packageSource);
4042             dest.writeBoolean(applicationEnabledSettingPersistent);
4043             dest.writeInt(pendingUserActionReason);
4044         }
4045 
4046         public static final Parcelable.Creator<SessionInfo>
4047                 CREATOR = new Parcelable.Creator<SessionInfo>() {
4048                     @Override
4049                     public SessionInfo createFromParcel(Parcel p) {
4050                         return new SessionInfo(p);
4051                     }
4052 
4053                     @Override
4054                     public SessionInfo[] newArray(int size) {
4055                         return new SessionInfo[size];
4056                     }
4057                 };
4058     }
4059 
4060     /**
4061      * Details for requesting the pre-commit install approval.
4062      */
4063     @DataClass(genConstructor = false, genToString = true)
4064     public static final class PreapprovalDetails implements Parcelable {
4065         /**
4066          * The icon representing the app to be installed.
4067          */
4068         private final @Nullable Bitmap mIcon;
4069         /**
4070          * The label representing the app to be installed.
4071          */
4072         private final @NonNull CharSequence mLabel;
4073         /**
4074          * The locale of the app label being used.
4075          */
4076         private final @NonNull ULocale mLocale;
4077         /**
4078          * The package name of the app to be installed.
4079          */
4080         private final @NonNull String mPackageName;
4081 
4082         /**
4083          * Creates a new PreapprovalDetails.
4084          *
4085          * @param icon
4086          *   The icon representing the app to be installed.
4087          * @param label
4088          *   The label representing the app to be installed.
4089          * @param locale
4090          *   The locale of the app label being used.
4091          * @param packageName
4092          *   The package name of the app to be installed.
4093          * @hide
4094          */
PreapprovalDetails( @ullable Bitmap icon, @NonNull CharSequence label, @NonNull ULocale locale, @NonNull String packageName)4095         public PreapprovalDetails(
4096                 @Nullable Bitmap icon,
4097                 @NonNull CharSequence label,
4098                 @NonNull ULocale locale,
4099                 @NonNull String packageName) {
4100             mIcon = icon;
4101             mLabel = label;
4102             Preconditions.checkArgument(!TextUtils.isEmpty(mLabel),
4103                     "App label cannot be empty.");
4104             mLocale = locale;
4105             Preconditions.checkArgument(!Objects.isNull(mLocale),
4106                     "Locale cannot be null.");
4107             mPackageName = packageName;
4108             Preconditions.checkArgument(!TextUtils.isEmpty(mPackageName),
4109                     "Package name cannot be empty.");
4110         }
4111 
4112         @Override
writeToParcel(@onNull Parcel dest, int flags)4113         public void writeToParcel(@NonNull Parcel dest, int flags) {
4114             byte flg = 0;
4115             if (mIcon != null) flg |= 0x1;
4116             dest.writeByte(flg);
4117             if (mIcon != null) mIcon.writeToParcel(dest, flags);
4118             dest.writeCharSequence(mLabel);
4119             dest.writeString8(mLocale.toString());
4120             dest.writeString8(mPackageName);
4121         }
4122 
4123         @Override
describeContents()4124         public int describeContents() { return 0; }
4125 
4126         /** @hide */
PreapprovalDetails(@onNull Parcel in)4127         /* package-private */ PreapprovalDetails(@NonNull Parcel in) {
4128             byte flg = in.readByte();
4129             final Bitmap icon = (flg & 0x1) == 0 ? null : Bitmap.CREATOR.createFromParcel(in);
4130             final CharSequence label = in.readCharSequence();
4131             final ULocale locale = new ULocale(in.readString8());
4132             final String packageName = in.readString8();
4133 
4134             mIcon = icon;
4135             mLabel = label;
4136             Preconditions.checkArgument(!TextUtils.isEmpty(mLabel),
4137                     "App label cannot be empty.");
4138             mLocale = locale;
4139             Preconditions.checkArgument(!Objects.isNull(mLocale),
4140                     "Locale cannot be null.");
4141             mPackageName = packageName;
4142             Preconditions.checkArgument(!TextUtils.isEmpty(mPackageName),
4143                     "Package name cannot be empty.");
4144         }
4145 
4146         public static final @NonNull Parcelable.Creator<PreapprovalDetails> CREATOR
4147                 = new Parcelable.Creator<PreapprovalDetails>() {
4148             @Override
4149             public PreapprovalDetails[] newArray(int size) {
4150                 return new PreapprovalDetails[size];
4151             }
4152 
4153             @Override
4154             public PreapprovalDetails createFromParcel(@NonNull Parcel in) {
4155                 return new PreapprovalDetails(in);
4156             }
4157         };
4158 
4159         /**
4160          * A builder for {@link PreapprovalDetails}
4161          */
4162         public static final class Builder {
4163 
4164             private @Nullable Bitmap mIcon;
4165             private @NonNull CharSequence mLabel;
4166             private @NonNull ULocale mLocale;
4167             private @NonNull String mPackageName;
4168 
4169             private long mBuilderFieldsSet = 0L;
4170 
4171             /**
4172              * Creates a new Builder.
4173              */
Builder()4174             public Builder() {}
4175 
4176             /**
4177              * The icon representing the app to be installed.
4178              */
setIcon(@onNull Bitmap value)4179             public @NonNull Builder setIcon(@NonNull Bitmap value) {
4180                 checkNotUsed();
4181                 mBuilderFieldsSet |= 0x1;
4182                 mIcon = value;
4183                 return this;
4184             }
4185 
4186             /**
4187              * The label representing the app to be installed.
4188              */
setLabel(@onNull CharSequence value)4189             public @NonNull Builder setLabel(@NonNull CharSequence value) {
4190                 checkNotUsed();
4191                 mBuilderFieldsSet |= 0x2;
4192                 mLabel = value;
4193                 return this;
4194             }
4195 
4196             /**
4197              * The locale of the app label being used.
4198              */
setLocale(@onNull ULocale value)4199             public @NonNull Builder setLocale(@NonNull ULocale value) {
4200                 checkNotUsed();
4201                 mBuilderFieldsSet |= 0x4;
4202                 mLocale = value;
4203                 return this;
4204             }
4205 
4206             /**
4207              * The package name of the app to be installed.
4208              */
setPackageName(@onNull String value)4209             public @NonNull Builder setPackageName(@NonNull String value) {
4210                 checkNotUsed();
4211                 mBuilderFieldsSet |= 0x8;
4212                 mPackageName = value;
4213                 return this;
4214             }
4215 
4216             /** Builds the instance. This builder should not be touched after calling this! */
build()4217             public @NonNull PreapprovalDetails build() {
4218                 checkNotUsed();
4219                 mBuilderFieldsSet |= 0x10; // Mark builder used
4220 
4221                 PreapprovalDetails o = new PreapprovalDetails(
4222                         mIcon,
4223                         mLabel,
4224                         mLocale,
4225                         mPackageName);
4226                 return o;
4227             }
4228 
checkNotUsed()4229             private void checkNotUsed() {
4230                 if ((mBuilderFieldsSet & 0x10) != 0) {
4231                     throw new IllegalStateException("This Builder should not be reused. "
4232                             + "Use a new Builder instance instead");
4233                 }
4234             }
4235         }
4236 
4237 
4238 
4239 
4240         // Code below generated by codegen v1.0.23.
4241         //
4242         // DO NOT MODIFY!
4243         // CHECKSTYLE:OFF Generated code
4244         //
4245         // To regenerate run:
4246         // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/PackageInstaller.java
4247         //
4248         // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
4249         //   Settings > Editor > Code Style > Formatter Control
4250         //@formatter:off
4251 
4252 
4253         /**
4254          * The icon representing the app to be installed.
4255          */
4256         @DataClass.Generated.Member
getIcon()4257         public @Nullable Bitmap getIcon() {
4258             return mIcon;
4259         }
4260 
4261         /**
4262          * The label representing the app to be installed.
4263          */
4264         @DataClass.Generated.Member
getLabel()4265         public @NonNull CharSequence getLabel() {
4266             return mLabel;
4267         }
4268 
4269         /**
4270          * The locale of the app label being used.
4271          */
4272         @DataClass.Generated.Member
getLocale()4273         public @NonNull ULocale getLocale() {
4274             return mLocale;
4275         }
4276 
4277         /**
4278          * The package name of the app to be installed.
4279          */
4280         @DataClass.Generated.Member
getPackageName()4281         public @NonNull String getPackageName() {
4282             return mPackageName;
4283         }
4284 
4285         @Override
4286         @DataClass.Generated.Member
toString()4287         public String toString() {
4288             // You can override field toString logic by defining methods like:
4289             // String fieldNameToString() { ... }
4290 
4291             return "PreapprovalDetails { " +
4292                     "icon = " + mIcon + ", " +
4293                     "label = " + mLabel + ", " +
4294                     "locale = " + mLocale + ", " +
4295                     "packageName = " + mPackageName +
4296             " }";
4297         }
4298 
4299         @DataClass.Generated(
4300                 time = 1676970504308L,
4301                 codegenVersion = "1.0.23",
4302                 sourceFile = "frameworks/base/core/java/android/content/pm/PackageInstaller.java",
4303                 inputSignatures = "private final @android.annotation.Nullable android.graphics.Bitmap mIcon\nprivate final @android.annotation.NonNull java.lang.CharSequence mLabel\nprivate final @android.annotation.NonNull android.icu.util.ULocale mLocale\nprivate final @android.annotation.NonNull java.lang.String mPackageName\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<android.content.pm.PackageInstaller.PreapprovalDetails> CREATOR\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\npublic @java.lang.Override int describeContents()\nclass PreapprovalDetails extends java.lang.Object implements [android.os.Parcelable]\nprivate @android.annotation.Nullable android.graphics.Bitmap mIcon\nprivate @android.annotation.NonNull java.lang.CharSequence mLabel\nprivate @android.annotation.NonNull android.icu.util.ULocale mLocale\nprivate @android.annotation.NonNull java.lang.String mPackageName\nprivate  long mBuilderFieldsSet\npublic @android.annotation.NonNull android.content.pm.PackageInstaller.PreapprovalDetails.Builder setIcon(android.graphics.Bitmap)\npublic @android.annotation.NonNull android.content.pm.PackageInstaller.PreapprovalDetails.Builder setLabel(java.lang.CharSequence)\npublic @android.annotation.NonNull android.content.pm.PackageInstaller.PreapprovalDetails.Builder setLocale(android.icu.util.ULocale)\npublic @android.annotation.NonNull android.content.pm.PackageInstaller.PreapprovalDetails.Builder setPackageName(java.lang.String)\npublic @android.annotation.NonNull android.content.pm.PackageInstaller.PreapprovalDetails build()\nprivate  void checkNotUsed()\nclass Builder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genToString=true)")
4304         @Deprecated
__metadata()4305         private void __metadata() {}
4306 
4307 
4308         //@formatter:on
4309         // End of generated code
4310 
4311     }
4312 
4313     /**
4314      * The callback result of {@link #checkInstallConstraints(List, InstallConstraints, Executor, Consumer)}.
4315      */
4316     @DataClass(genParcelable = true, genHiddenConstructor = true)
4317     @DataClass.Suppress("isAllConstraintsSatisfied")
4318     public static final class InstallConstraintsResult implements Parcelable {
4319         /**
4320          * True if all constraints are satisfied.
4321          */
4322         private boolean mAllConstraintsSatisfied;
4323 
4324         /**
4325          * True if all constraints are satisfied.
4326          */
areAllConstraintsSatisfied()4327         public boolean areAllConstraintsSatisfied() {
4328             return mAllConstraintsSatisfied;
4329         }
4330 
4331 
4332 
4333         // Code below generated by codegen v1.0.23.
4334         //
4335         // DO NOT MODIFY!
4336         // CHECKSTYLE:OFF Generated code
4337         //
4338         // To regenerate run:
4339         // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/PackageInstaller.java
4340         //
4341         // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
4342         //   Settings > Editor > Code Style > Formatter Control
4343         //@formatter:off
4344 
4345 
4346         /**
4347          * Creates a new InstallConstraintsResult.
4348          *
4349          * @param allConstraintsSatisfied
4350          *   True if all constraints are satisfied.
4351          * @hide
4352          */
4353         @DataClass.Generated.Member
InstallConstraintsResult( boolean allConstraintsSatisfied)4354         public InstallConstraintsResult(
4355                 boolean allConstraintsSatisfied) {
4356             this.mAllConstraintsSatisfied = allConstraintsSatisfied;
4357 
4358             // onConstructed(); // You can define this method to get a callback
4359         }
4360 
4361         @Override
4362         @DataClass.Generated.Member
writeToParcel(@onNull Parcel dest, int flags)4363         public void writeToParcel(@NonNull Parcel dest, int flags) {
4364             // You can override field parcelling by defining methods like:
4365             // void parcelFieldName(Parcel dest, int flags) { ... }
4366 
4367             byte flg = 0;
4368             if (mAllConstraintsSatisfied) flg |= 0x1;
4369             dest.writeByte(flg);
4370         }
4371 
4372         @Override
4373         @DataClass.Generated.Member
describeContents()4374         public int describeContents() { return 0; }
4375 
4376         /** @hide */
4377         @SuppressWarnings({"unchecked", "RedundantCast"})
4378         @DataClass.Generated.Member
InstallConstraintsResult(@onNull Parcel in)4379         /* package-private */ InstallConstraintsResult(@NonNull Parcel in) {
4380             // You can override field unparcelling by defining methods like:
4381             // static FieldType unparcelFieldName(Parcel in) { ... }
4382 
4383             byte flg = in.readByte();
4384             boolean allConstraintsSatisfied = (flg & 0x1) != 0;
4385 
4386             this.mAllConstraintsSatisfied = allConstraintsSatisfied;
4387 
4388             // onConstructed(); // You can define this method to get a callback
4389         }
4390 
4391         @DataClass.Generated.Member
4392         public static final @NonNull Parcelable.Creator<InstallConstraintsResult> CREATOR
4393                 = new Parcelable.Creator<InstallConstraintsResult>() {
4394             @Override
4395             public InstallConstraintsResult[] newArray(int size) {
4396                 return new InstallConstraintsResult[size];
4397             }
4398 
4399             @Override
4400             public InstallConstraintsResult createFromParcel(@NonNull Parcel in) {
4401                 return new InstallConstraintsResult(in);
4402             }
4403         };
4404 
4405         @DataClass.Generated(
4406                 time = 1676970504336L,
4407                 codegenVersion = "1.0.23",
4408                 sourceFile = "frameworks/base/core/java/android/content/pm/PackageInstaller.java",
4409                 inputSignatures = "private  boolean mAllConstraintsSatisfied\npublic  boolean areAllConstraintsSatisfied()\nclass InstallConstraintsResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genHiddenConstructor=true)")
4410         @Deprecated
__metadata()4411         private void __metadata() {}
4412 
4413 
4414         //@formatter:on
4415         // End of generated code
4416 
4417     }
4418 
4419     /**
4420      * A class to encapsulate constraints for installation.
4421      *
4422      * When used with {@link #checkInstallConstraints(List, InstallConstraints, Executor, Consumer)}, it
4423      * specifies the conditions to check against for the packages in question. This can be used
4424      * by app stores to deliver auto updates without disrupting the user experience (referred as
4425      * gentle update) - for example, an app store might hold off updates when it find out the
4426      * app to update is interacting with the user.
4427      *
4428      * Use {@link Builder} to create a new instance and call mutator methods to add constraints.
4429      * If no mutators were called, default constraints will be generated which implies no
4430      * constraints. It is recommended to use preset constraints which are useful in most
4431      * cases.
4432      *
4433      * For the purpose of gentle update, it is recommended to always use {@link #GENTLE_UPDATE}
4434      * for the system knows best how to do it. It will also benefits the installer as the
4435      * platform evolves and add more constraints to improve the accuracy and efficiency of
4436      * gentle update.
4437      *
4438      * Note the constraints are applied transitively. If app Foo is used by app Bar (via shared
4439      * library or bounded service), the constraints will also be applied to Bar.
4440      */
4441     @DataClass(genParcelable = true, genHiddenConstructor = true, genEqualsHashCode=true)
4442     public static final class InstallConstraints implements Parcelable {
4443         /**
4444          * Preset constraints suitable for gentle update.
4445          */
4446         @NonNull
4447         public static final InstallConstraints GENTLE_UPDATE =
4448                 new Builder().setAppNotInteractingRequired().build();
4449 
4450         private final boolean mDeviceIdleRequired;
4451         private final boolean mAppNotForegroundRequired;
4452         private final boolean mAppNotInteractingRequired;
4453         private final boolean mAppNotTopVisibleRequired;
4454         private final boolean mNotInCallRequired;
4455 
4456         /**
4457          * Builder class for constructing {@link InstallConstraints}.
4458          */
4459         public static final class Builder {
4460             private boolean mDeviceIdleRequired;
4461             private boolean mAppNotForegroundRequired;
4462             private boolean mAppNotInteractingRequired;
4463             private boolean mAppNotTopVisibleRequired;
4464             private boolean mNotInCallRequired;
4465 
4466             /**
4467              * This constraint requires the device is idle.
4468              */
4469             @SuppressLint("MissingGetterMatchingBuilder")
4470             @NonNull
setDeviceIdleRequired()4471             public Builder setDeviceIdleRequired() {
4472                 mDeviceIdleRequired = true;
4473                 return this;
4474             }
4475 
4476             /**
4477              * This constraint requires the app in question is not in the foreground.
4478              */
4479             @SuppressLint("MissingGetterMatchingBuilder")
4480             @NonNull
setAppNotForegroundRequired()4481             public Builder setAppNotForegroundRequired() {
4482                 mAppNotForegroundRequired = true;
4483                 return this;
4484             }
4485 
4486             /**
4487              * This constraint requires the app in question is not interacting with the user.
4488              * User interaction includes:
4489              * <ul>
4490              *     <li>playing or recording audio/video</li>
4491              *     <li>sending or receiving network data</li>
4492              *     <li>being visible to the user</li>
4493              * </ul>
4494              */
4495             @SuppressLint("MissingGetterMatchingBuilder")
4496             @NonNull
setAppNotInteractingRequired()4497             public Builder setAppNotInteractingRequired() {
4498                 mAppNotInteractingRequired = true;
4499                 return this;
4500             }
4501 
4502             /**
4503              * This constraint requires the app in question is not top-visible to the user.
4504              * A top-visible app is showing UI at the top of the screen that the user is
4505              * interacting with.
4506              *
4507              * Note this constraint is a subset of {@link #setAppNotForegroundRequired()}
4508              * because a top-visible app is also a foreground app. This is also a subset
4509              * of {@link #setAppNotInteractingRequired()} because a top-visible app is interacting
4510              * with the user.
4511              *
4512              * @see ActivityManager.RunningAppProcessInfo#IMPORTANCE_FOREGROUND
4513              */
4514             @SuppressLint("MissingGetterMatchingBuilder")
4515             @NonNull
setAppNotTopVisibleRequired()4516             public Builder setAppNotTopVisibleRequired() {
4517                 mAppNotTopVisibleRequired = true;
4518                 return this;
4519             }
4520 
4521             /**
4522              * This constraint requires there is no ongoing call in the device.
4523              */
4524             @SuppressLint("MissingGetterMatchingBuilder")
4525             @NonNull
setNotInCallRequired()4526             public Builder setNotInCallRequired() {
4527                 mNotInCallRequired = true;
4528                 return this;
4529             }
4530 
4531             /**
4532              * Builds a new {@link InstallConstraints} instance.
4533              */
4534             @NonNull
build()4535             public InstallConstraints build() {
4536                 return new InstallConstraints(mDeviceIdleRequired, mAppNotForegroundRequired,
4537                         mAppNotInteractingRequired, mAppNotTopVisibleRequired, mNotInCallRequired);
4538             }
4539         }
4540 
4541 
4542 
4543         // Code below generated by codegen v1.0.23.
4544         //
4545         // DO NOT MODIFY!
4546         // CHECKSTYLE:OFF Generated code
4547         //
4548         // To regenerate run:
4549         // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/PackageInstaller.java
4550         //
4551         // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
4552         //   Settings > Editor > Code Style > Formatter Control
4553         //@formatter:off
4554 
4555 
4556         /**
4557          * Creates a new InstallConstraints.
4558          *
4559          * @hide
4560          */
4561         @DataClass.Generated.Member
InstallConstraints( boolean deviceIdleRequired, boolean appNotForegroundRequired, boolean appNotInteractingRequired, boolean appNotTopVisibleRequired, boolean notInCallRequired)4562         public InstallConstraints(
4563                 boolean deviceIdleRequired,
4564                 boolean appNotForegroundRequired,
4565                 boolean appNotInteractingRequired,
4566                 boolean appNotTopVisibleRequired,
4567                 boolean notInCallRequired) {
4568             this.mDeviceIdleRequired = deviceIdleRequired;
4569             this.mAppNotForegroundRequired = appNotForegroundRequired;
4570             this.mAppNotInteractingRequired = appNotInteractingRequired;
4571             this.mAppNotTopVisibleRequired = appNotTopVisibleRequired;
4572             this.mNotInCallRequired = notInCallRequired;
4573 
4574             // onConstructed(); // You can define this method to get a callback
4575         }
4576 
4577         @DataClass.Generated.Member
isDeviceIdleRequired()4578         public boolean isDeviceIdleRequired() {
4579             return mDeviceIdleRequired;
4580         }
4581 
4582         @DataClass.Generated.Member
isAppNotForegroundRequired()4583         public boolean isAppNotForegroundRequired() {
4584             return mAppNotForegroundRequired;
4585         }
4586 
4587         @DataClass.Generated.Member
isAppNotInteractingRequired()4588         public boolean isAppNotInteractingRequired() {
4589             return mAppNotInteractingRequired;
4590         }
4591 
4592         @DataClass.Generated.Member
isAppNotTopVisibleRequired()4593         public boolean isAppNotTopVisibleRequired() {
4594             return mAppNotTopVisibleRequired;
4595         }
4596 
4597         @DataClass.Generated.Member
isNotInCallRequired()4598         public boolean isNotInCallRequired() {
4599             return mNotInCallRequired;
4600         }
4601 
4602         @Override
4603         @DataClass.Generated.Member
equals(@ullable Object o)4604         public boolean equals(@Nullable Object o) {
4605             // You can override field equality logic by defining either of the methods like:
4606             // boolean fieldNameEquals(InstallConstraints other) { ... }
4607             // boolean fieldNameEquals(FieldType otherValue) { ... }
4608 
4609             if (this == o) return true;
4610             if (o == null || getClass() != o.getClass()) return false;
4611             @SuppressWarnings("unchecked")
4612             InstallConstraints that = (InstallConstraints) o;
4613             //noinspection PointlessBooleanExpression
4614             return true
4615                     && mDeviceIdleRequired == that.mDeviceIdleRequired
4616                     && mAppNotForegroundRequired == that.mAppNotForegroundRequired
4617                     && mAppNotInteractingRequired == that.mAppNotInteractingRequired
4618                     && mAppNotTopVisibleRequired == that.mAppNotTopVisibleRequired
4619                     && mNotInCallRequired == that.mNotInCallRequired;
4620         }
4621 
4622         @Override
4623         @DataClass.Generated.Member
hashCode()4624         public int hashCode() {
4625             // You can override field hashCode logic by defining methods like:
4626             // int fieldNameHashCode() { ... }
4627 
4628             int _hash = 1;
4629             _hash = 31 * _hash + Boolean.hashCode(mDeviceIdleRequired);
4630             _hash = 31 * _hash + Boolean.hashCode(mAppNotForegroundRequired);
4631             _hash = 31 * _hash + Boolean.hashCode(mAppNotInteractingRequired);
4632             _hash = 31 * _hash + Boolean.hashCode(mAppNotTopVisibleRequired);
4633             _hash = 31 * _hash + Boolean.hashCode(mNotInCallRequired);
4634             return _hash;
4635         }
4636 
4637         @Override
4638         @DataClass.Generated.Member
writeToParcel(@onNull Parcel dest, int flags)4639         public void writeToParcel(@NonNull Parcel dest, int flags) {
4640             // You can override field parcelling by defining methods like:
4641             // void parcelFieldName(Parcel dest, int flags) { ... }
4642 
4643             byte flg = 0;
4644             if (mDeviceIdleRequired) flg |= 0x1;
4645             if (mAppNotForegroundRequired) flg |= 0x2;
4646             if (mAppNotInteractingRequired) flg |= 0x4;
4647             if (mAppNotTopVisibleRequired) flg |= 0x8;
4648             if (mNotInCallRequired) flg |= 0x10;
4649             dest.writeByte(flg);
4650         }
4651 
4652         @Override
4653         @DataClass.Generated.Member
describeContents()4654         public int describeContents() { return 0; }
4655 
4656         /** @hide */
4657         @SuppressWarnings({"unchecked", "RedundantCast"})
4658         @DataClass.Generated.Member
InstallConstraints(@onNull Parcel in)4659         /* package-private */ InstallConstraints(@NonNull Parcel in) {
4660             // You can override field unparcelling by defining methods like:
4661             // static FieldType unparcelFieldName(Parcel in) { ... }
4662 
4663             byte flg = in.readByte();
4664             boolean deviceIdleRequired = (flg & 0x1) != 0;
4665             boolean appNotForegroundRequired = (flg & 0x2) != 0;
4666             boolean appNotInteractingRequired = (flg & 0x4) != 0;
4667             boolean appNotTopVisibleRequired = (flg & 0x8) != 0;
4668             boolean notInCallRequired = (flg & 0x10) != 0;
4669 
4670             this.mDeviceIdleRequired = deviceIdleRequired;
4671             this.mAppNotForegroundRequired = appNotForegroundRequired;
4672             this.mAppNotInteractingRequired = appNotInteractingRequired;
4673             this.mAppNotTopVisibleRequired = appNotTopVisibleRequired;
4674             this.mNotInCallRequired = notInCallRequired;
4675 
4676             // onConstructed(); // You can define this method to get a callback
4677         }
4678 
4679         @DataClass.Generated.Member
4680         public static final @NonNull Parcelable.Creator<InstallConstraints> CREATOR
4681                 = new Parcelable.Creator<InstallConstraints>() {
4682             @Override
4683             public InstallConstraints[] newArray(int size) {
4684                 return new InstallConstraints[size];
4685             }
4686 
4687             @Override
4688             public InstallConstraints createFromParcel(@NonNull Parcel in) {
4689                 return new InstallConstraints(in);
4690             }
4691         };
4692 
4693         @DataClass.Generated(
4694                 time = 1676970504352L,
4695                 codegenVersion = "1.0.23",
4696                 sourceFile = "frameworks/base/core/java/android/content/pm/PackageInstaller.java",
4697                 inputSignatures = "public static final @android.annotation.NonNull android.content.pm.PackageInstaller.InstallConstraints GENTLE_UPDATE\nprivate final  boolean mDeviceIdleRequired\nprivate final  boolean mAppNotForegroundRequired\nprivate final  boolean mAppNotInteractingRequired\nprivate final  boolean mAppNotTopVisibleRequired\nprivate final  boolean mNotInCallRequired\nclass InstallConstraints extends java.lang.Object implements [android.os.Parcelable]\nprivate  boolean mDeviceIdleRequired\nprivate  boolean mAppNotForegroundRequired\nprivate  boolean mAppNotInteractingRequired\nprivate  boolean mAppNotTopVisibleRequired\nprivate  boolean mNotInCallRequired\npublic @android.annotation.SuppressLint @android.annotation.NonNull android.content.pm.PackageInstaller.InstallConstraints.Builder setDeviceIdleRequired()\npublic @android.annotation.SuppressLint @android.annotation.NonNull android.content.pm.PackageInstaller.InstallConstraints.Builder setAppNotForegroundRequired()\npublic @android.annotation.SuppressLint @android.annotation.NonNull android.content.pm.PackageInstaller.InstallConstraints.Builder setAppNotInteractingRequired()\npublic @android.annotation.SuppressLint @android.annotation.NonNull android.content.pm.PackageInstaller.InstallConstraints.Builder setAppNotTopVisibleRequired()\npublic @android.annotation.SuppressLint @android.annotation.NonNull android.content.pm.PackageInstaller.InstallConstraints.Builder setNotInCallRequired()\npublic @android.annotation.NonNull android.content.pm.PackageInstaller.InstallConstraints build()\nclass Builder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genParcelable=true, genHiddenConstructor=true, genEqualsHashCode=true)")
4698         @Deprecated
__metadata()4699         private void __metadata() {}
4700 
4701 
4702         //@formatter:on
4703         // End of generated code
4704 
4705     }
4706 
4707 }
4708