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 android.Manifest;
20 import android.annotation.CurrentTimeMillisLong;
21 import android.annotation.IntDef;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.annotation.RequiresPermission;
25 import android.annotation.SdkConstant;
26 import android.annotation.SdkConstant.SdkConstantType;
27 import android.annotation.SystemApi;
28 import android.annotation.TestApi;
29 import android.app.ActivityManager;
30 import android.app.AppGlobals;
31 import android.compat.annotation.UnsupportedAppUsage;
32 import android.content.Intent;
33 import android.content.IntentSender;
34 import android.content.pm.PackageManager.DeleteFlags;
35 import android.content.pm.PackageManager.InstallReason;
36 import android.graphics.Bitmap;
37 import android.net.Uri;
38 import android.os.Build;
39 import android.os.FileBridge;
40 import android.os.Handler;
41 import android.os.HandlerExecutor;
42 import android.os.Parcel;
43 import android.os.ParcelFileDescriptor;
44 import android.os.Parcelable;
45 import android.os.ParcelableException;
46 import android.os.RemoteException;
47 import android.os.SystemProperties;
48 import android.os.UserHandle;
49 import android.system.ErrnoException;
50 import android.system.Os;
51 import android.util.ArraySet;
52 import android.util.ExceptionUtils;
53 
54 import com.android.internal.util.IndentingPrintWriter;
55 import com.android.internal.util.Preconditions;
56 import com.android.internal.util.function.pooled.PooledLambda;
57 
58 import java.io.Closeable;
59 import java.io.IOException;
60 import java.io.InputStream;
61 import java.io.OutputStream;
62 import java.lang.annotation.Retention;
63 import java.lang.annotation.RetentionPolicy;
64 import java.security.MessageDigest;
65 import java.util.ArrayList;
66 import java.util.Collections;
67 import java.util.Iterator;
68 import java.util.List;
69 import java.util.Set;
70 import java.util.concurrent.Executor;
71 import java.util.stream.Collectors;
72 
73 /**
74  * Offers the ability to install, upgrade, and remove applications on the
75  * device. This includes support for apps packaged either as a single
76  * "monolithic" APK, or apps packaged as multiple "split" APKs.
77  * <p>
78  * An app is delivered for installation through a
79  * {@link PackageInstaller.Session}, which any app can create. Once the session
80  * is created, the installer can stream one or more APKs into place until it
81  * decides to either commit or destroy the session. Committing may require user
82  * intervention to complete the installation, unless the caller falls into one of the
83  * following categories, in which case the installation will complete automatically.
84  * <ul>
85  * <li>the device owner
86  * <li>the affiliated profile owner
87  * </ul>
88  * <p>
89  * Sessions can install brand new apps, upgrade existing apps, or add new splits
90  * into an existing app.
91  * <p>
92  * Apps packaged as multiple split APKs always consist of a single "base" APK
93  * (with a {@code null} split name) and zero or more "split" APKs (with unique
94  * split names). Any subset of these APKs can be installed together, as long as
95  * the following constraints are met:
96  * <ul>
97  * <li>All APKs must have the exact same package name, version code, and signing
98  * certificates.
99  * <li>All APKs must have unique split names.
100  * <li>All installations must contain a single base APK.
101  * </ul>
102  * <p>
103  * The ApiDemos project contains examples of using this API:
104  * <code>ApiDemos/src/com/example/android/apis/content/InstallApk*.java</code>.
105  */
106 public class PackageInstaller {
107     private static final String TAG = "PackageInstaller";
108 
109     /** {@hide} */
110     public static final boolean ENABLE_REVOCABLE_FD =
111             SystemProperties.getBoolean("fw.revocable_fd", false);
112 
113     /**
114      * Activity Action: Show details about a particular install session. This
115      * may surface actions such as pause, resume, or cancel.
116      * <p>
117      * This should always be scoped to the installer package that owns the
118      * session. Clients should use {@link SessionInfo#createDetailsIntent()} to
119      * build this intent correctly.
120      * <p>
121      * In some cases, a matching Activity may not exist, so ensure you safeguard
122      * against this.
123      * <p>
124      * The session to show details for is defined in {@link #EXTRA_SESSION_ID}.
125      */
126     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
127     public static final String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS";
128 
129     /**
130      * Broadcast Action: Explicit broadcast sent to the last known default launcher when a session
131      * for a new install is committed. For managed profile, this is sent to the default launcher
132      * of the primary profile.
133      * <p>
134      * The associated session is defined in {@link #EXTRA_SESSION} and the user for which this
135      * session was created in {@link Intent#EXTRA_USER}.
136      */
137     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
138     public static final String ACTION_SESSION_COMMITTED =
139             "android.content.pm.action.SESSION_COMMITTED";
140 
141     /**
142      * Broadcast Action: Send information about a staged install session when its state is updated.
143      * <p>
144      * The associated session information is defined in {@link #EXTRA_SESSION}.
145      */
146     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
147     public static final String ACTION_SESSION_UPDATED =
148             "android.content.pm.action.SESSION_UPDATED";
149 
150     /** {@hide} */
151     public static final String ACTION_CONFIRM_INSTALL = "android.content.pm.action.CONFIRM_INSTALL";
152 
153     /**
154      * An integer session ID that an operation is working with.
155      *
156      * @see Intent#getIntExtra(String, int)
157      */
158     public static final String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID";
159 
160     /**
161      * {@link SessionInfo} that an operation is working with.
162      *
163      * @see Intent#getParcelableExtra(String)
164      */
165     public static final String EXTRA_SESSION = "android.content.pm.extra.SESSION";
166 
167     /**
168      * Package name that an operation is working with.
169      *
170      * @see Intent#getStringExtra(String)
171      */
172     public static final String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME";
173 
174     /**
175      * Current status of an operation. Will be one of
176      * {@link #STATUS_PENDING_USER_ACTION}, {@link #STATUS_SUCCESS},
177      * {@link #STATUS_FAILURE}, {@link #STATUS_FAILURE_ABORTED},
178      * {@link #STATUS_FAILURE_BLOCKED}, {@link #STATUS_FAILURE_CONFLICT},
179      * {@link #STATUS_FAILURE_INCOMPATIBLE}, {@link #STATUS_FAILURE_INVALID}, or
180      * {@link #STATUS_FAILURE_STORAGE}.
181      * <p>
182      * More information about a status may be available through additional
183      * extras; see the individual status documentation for details.
184      *
185      * @see Intent#getIntExtra(String, int)
186      */
187     public static final String EXTRA_STATUS = "android.content.pm.extra.STATUS";
188 
189     /**
190      * Detailed string representation of the status, including raw details that
191      * are useful for debugging.
192      *
193      * @see Intent#getStringExtra(String)
194      */
195     public static final String EXTRA_STATUS_MESSAGE = "android.content.pm.extra.STATUS_MESSAGE";
196 
197     /**
198      * Another package name relevant to a status. This is typically the package
199      * responsible for causing an operation failure.
200      *
201      * @see Intent#getStringExtra(String)
202      */
203     public static final String
204             EXTRA_OTHER_PACKAGE_NAME = "android.content.pm.extra.OTHER_PACKAGE_NAME";
205 
206     /**
207      * Storage path relevant to a status.
208      *
209      * @see Intent#getStringExtra(String)
210      */
211     public static final String EXTRA_STORAGE_PATH = "android.content.pm.extra.STORAGE_PATH";
212 
213     /** {@hide} */
214     @Deprecated
215     public static final String EXTRA_PACKAGE_NAMES = "android.content.pm.extra.PACKAGE_NAMES";
216 
217     /** {@hide} */
218     public static final String EXTRA_LEGACY_STATUS = "android.content.pm.extra.LEGACY_STATUS";
219     /** {@hide} */
220     public static final String EXTRA_LEGACY_BUNDLE = "android.content.pm.extra.LEGACY_BUNDLE";
221     /** {@hide} */
222     public static final String EXTRA_CALLBACK = "android.content.pm.extra.CALLBACK";
223 
224     /**
225      * User action is currently required to proceed. You can launch the intent
226      * activity described by {@link Intent#EXTRA_INTENT} to involve the user and
227      * continue.
228      * <p>
229      * You may choose to immediately launch the intent if the user is actively
230      * using your app. Otherwise, you should use a notification to guide the
231      * user back into your app before launching.
232      *
233      * @see Intent#getParcelableExtra(String)
234      */
235     public static final int STATUS_PENDING_USER_ACTION = -1;
236 
237     /**
238      * The operation succeeded.
239      */
240     public static final int STATUS_SUCCESS = 0;
241 
242     /**
243      * The operation failed in a generic way. The system will always try to
244      * provide a more specific failure reason, but in some rare cases this may
245      * be delivered.
246      *
247      * @see #EXTRA_STATUS_MESSAGE
248      */
249     public static final int STATUS_FAILURE = 1;
250 
251     /**
252      * The operation failed because it was blocked. For example, a device policy
253      * may be blocking the operation, a package verifier may have blocked the
254      * operation, or the app may be required for core system operation.
255      * <p>
256      * The result may also contain {@link #EXTRA_OTHER_PACKAGE_NAME} with the
257      * specific package blocking the install.
258      *
259      * @see #EXTRA_STATUS_MESSAGE
260      * @see #EXTRA_OTHER_PACKAGE_NAME
261      */
262     public static final int STATUS_FAILURE_BLOCKED = 2;
263 
264     /**
265      * The operation failed because it was actively aborted. For example, the
266      * user actively declined requested permissions, or the session was
267      * abandoned.
268      *
269      * @see #EXTRA_STATUS_MESSAGE
270      */
271     public static final int STATUS_FAILURE_ABORTED = 3;
272 
273     /**
274      * The operation failed because one or more of the APKs was invalid. For
275      * example, they might be malformed, corrupt, incorrectly signed,
276      * mismatched, etc.
277      *
278      * @see #EXTRA_STATUS_MESSAGE
279      */
280     public static final int STATUS_FAILURE_INVALID = 4;
281 
282     /**
283      * The operation failed because it conflicts (or is inconsistent with) with
284      * another package already installed on the device. For example, an existing
285      * permission, incompatible certificates, etc. The user may be able to
286      * uninstall another app to fix the issue.
287      * <p>
288      * The result may also contain {@link #EXTRA_OTHER_PACKAGE_NAME} with the
289      * specific package identified as the cause of the conflict.
290      *
291      * @see #EXTRA_STATUS_MESSAGE
292      * @see #EXTRA_OTHER_PACKAGE_NAME
293      */
294     public static final int STATUS_FAILURE_CONFLICT = 5;
295 
296     /**
297      * The operation failed because of storage issues. For example, the device
298      * may be running low on space, or external media may be unavailable. The
299      * user may be able to help free space or insert different external media.
300      * <p>
301      * The result may also contain {@link #EXTRA_STORAGE_PATH} with the path to
302      * the storage device that caused the failure.
303      *
304      * @see #EXTRA_STATUS_MESSAGE
305      * @see #EXTRA_STORAGE_PATH
306      */
307     public static final int STATUS_FAILURE_STORAGE = 6;
308 
309     /**
310      * The operation failed because it is fundamentally incompatible with this
311      * device. For example, the app may require a hardware feature that doesn't
312      * exist, it may be missing native code for the ABIs supported by the
313      * device, or it requires a newer SDK version, etc.
314      *
315      * @see #EXTRA_STATUS_MESSAGE
316      */
317     public static final int STATUS_FAILURE_INCOMPATIBLE = 7;
318 
319     private final IPackageInstaller mInstaller;
320     private final int mUserId;
321     private final String mInstallerPackageName;
322 
323     private final ArrayList<SessionCallbackDelegate> mDelegates = new ArrayList<>();
324 
325     /** {@hide} */
PackageInstaller(IPackageInstaller installer, String installerPackageName, int userId)326     public PackageInstaller(IPackageInstaller installer,
327             String installerPackageName, int userId) {
328         mInstaller = installer;
329         mInstallerPackageName = installerPackageName;
330         mUserId = userId;
331     }
332 
333     /**
334      * Create a new session using the given parameters, returning a unique ID
335      * that represents the session. Once created, the session can be opened
336      * multiple times across multiple device boots.
337      * <p>
338      * The system may automatically destroy sessions that have not been
339      * finalized (either committed or abandoned) within a reasonable period of
340      * time, typically on the order of a day.
341      *
342      * @throws IOException if parameters were unsatisfiable, such as lack of
343      *             disk space or unavailable media.
344      * @throws SecurityException when installation services are unavailable,
345      *             such as when called from a restricted user.
346      * @throws IllegalArgumentException when {@link SessionParams} is invalid.
347      * @return positive, non-zero unique ID that represents the created session.
348      *         This ID remains consistent across device reboots until the
349      *         session is finalized. IDs are not reused during a given boot.
350      */
createSession(@onNull SessionParams params)351     public int createSession(@NonNull SessionParams params) throws IOException {
352         try {
353             final String installerPackage;
354             if (params.installerPackageName == null) {
355                 installerPackage = mInstallerPackageName;
356             } else {
357                 installerPackage = params.installerPackageName;
358             }
359 
360             return mInstaller.createSession(params, installerPackage, mUserId);
361         } catch (RuntimeException e) {
362             ExceptionUtils.maybeUnwrapIOException(e);
363             throw e;
364         } catch (RemoteException e) {
365             throw e.rethrowFromSystemServer();
366         }
367     }
368 
369     /**
370      * Open an existing session to actively perform work. To succeed, the caller
371      * must be the owner of the install session.
372      *
373      * @throws IOException if parameters were unsatisfiable, such as lack of
374      *             disk space or unavailable media.
375      * @throws SecurityException when the caller does not own the session, or
376      *             the session is invalid.
377      */
openSession(int sessionId)378     public @NonNull Session openSession(int sessionId) throws IOException {
379         try {
380             try {
381                 return new Session(mInstaller.openSession(sessionId));
382             } catch (RemoteException e) {
383                 throw e.rethrowFromSystemServer();
384             }
385         } catch (RuntimeException e) {
386             ExceptionUtils.maybeUnwrapIOException(e);
387             throw e;
388         }
389     }
390 
391     /**
392      * Update the icon representing the app being installed in a specific
393      * session. This should be roughly
394      * {@link ActivityManager#getLauncherLargeIconSize()} in both dimensions.
395      *
396      * @throws SecurityException when the caller does not own the session, or
397      *             the session is invalid.
398      */
updateSessionAppIcon(int sessionId, @Nullable Bitmap appIcon)399     public void updateSessionAppIcon(int sessionId, @Nullable Bitmap appIcon) {
400         try {
401             mInstaller.updateSessionAppIcon(sessionId, appIcon);
402         } catch (RemoteException e) {
403             throw e.rethrowFromSystemServer();
404         }
405     }
406 
407     /**
408      * Update the label representing the app being installed in a specific
409      * session.
410      *
411      * @throws SecurityException when the caller does not own the session, or
412      *             the session is invalid.
413      */
updateSessionAppLabel(int sessionId, @Nullable CharSequence appLabel)414     public void updateSessionAppLabel(int sessionId, @Nullable CharSequence appLabel) {
415         try {
416             final String val = (appLabel != null) ? appLabel.toString() : null;
417             mInstaller.updateSessionAppLabel(sessionId, val);
418         } catch (RemoteException e) {
419             throw e.rethrowFromSystemServer();
420         }
421     }
422 
423     /**
424      * Completely abandon the given session, destroying all staged data and
425      * rendering it invalid. Abandoned sessions will be reported to
426      * {@link SessionCallback} listeners as failures. This is equivalent to
427      * opening the session and calling {@link Session#abandon()}.
428      *
429      * @throws SecurityException when the caller does not own the session, or
430      *             the session is invalid.
431      */
abandonSession(int sessionId)432     public void abandonSession(int sessionId) {
433         try {
434             mInstaller.abandonSession(sessionId);
435         } catch (RemoteException e) {
436             throw e.rethrowFromSystemServer();
437         }
438     }
439 
440     /**
441      * Return details for a specific session. No special permissions are
442      * required to retrieve these details.
443      *
444      * @return details for the requested session, or {@code null} if the session
445      *         does not exist.
446      */
getSessionInfo(int sessionId)447     public @Nullable SessionInfo getSessionInfo(int sessionId) {
448         try {
449             return mInstaller.getSessionInfo(sessionId);
450         } catch (RemoteException e) {
451             throw e.rethrowFromSystemServer();
452         }
453     }
454 
455     /**
456      * Return list of all known install sessions, regardless of the installer.
457      */
getAllSessions()458     public @NonNull List<SessionInfo> getAllSessions() {
459         try {
460             return mInstaller.getAllSessions(mUserId).getList();
461         } catch (RemoteException e) {
462             throw e.rethrowFromSystemServer();
463         }
464     }
465 
466     /**
467      * Return list of all known install sessions owned by the calling app.
468      */
getMySessions()469     public @NonNull List<SessionInfo> getMySessions() {
470         try {
471             return mInstaller.getMySessions(mInstallerPackageName, mUserId).getList();
472         } catch (RemoteException e) {
473             throw e.rethrowFromSystemServer();
474         }
475     }
476 
477     /**
478      * Return list of all staged install sessions.
479      */
getStagedSessions()480     public @NonNull List<SessionInfo> getStagedSessions() {
481         try {
482             // TODO: limit this to the mUserId?
483             return mInstaller.getStagedSessions().getList();
484         } catch (RemoteException e) {
485             throw e.rethrowFromSystemServer();
486         }
487     }
488 
489     /**
490      * Returns first active staged session, or {@code null} if there is none.
491      *
492      * <p>For more information on what sessions are considered active see
493      * {@link SessionInfo#isStagedSessionActive()}.
494      *
495      * @deprecated Use {@link #getActiveStagedSessions} as there can be more than one active staged
496      * session
497      */
498     @Deprecated
getActiveStagedSession()499     public @Nullable SessionInfo getActiveStagedSession() {
500         List<SessionInfo> activeSessions = getActiveStagedSessions();
501         return activeSessions.isEmpty() ? null : activeSessions.get(0);
502     }
503 
504     /**
505      * Returns list of active staged sessions. Returns empty list if there is none.
506      *
507      * <p>For more information on what sessions are considered active see
508      *      * {@link SessionInfo#isStagedSessionActive()}.
509      */
getActiveStagedSessions()510     public @NonNull List<SessionInfo> getActiveStagedSessions() {
511         return getStagedSessions().stream()
512                 .filter(s -> s.isStagedSessionActive())
513                 .collect(Collectors.toList());
514     }
515 
516     /**
517      * Uninstall the given package, removing it completely from the device. This
518      * method is available to:
519      * <ul>
520      * <li>the current "installer of record" for the package
521      * <li>the device owner
522      * <li>the affiliated profile owner
523      * </ul>
524      *
525      * @param packageName The package to uninstall.
526      * @param statusReceiver Where to deliver the result.
527      *
528      * @see android.app.admin.DevicePolicyManager
529      */
530     @RequiresPermission(anyOf = {
531             Manifest.permission.DELETE_PACKAGES,
532             Manifest.permission.REQUEST_DELETE_PACKAGES})
uninstall(@onNull String packageName, @NonNull IntentSender statusReceiver)533     public void uninstall(@NonNull String packageName, @NonNull IntentSender statusReceiver) {
534         uninstall(packageName, 0 /*flags*/, statusReceiver);
535     }
536 
537     /**
538      * Uninstall the given package, removing it completely from the device. This
539      * method is only available to the current "installer of record" for the
540      * package.
541      *
542      * @param packageName The package to uninstall.
543      * @param flags Flags for uninstall.
544      * @param statusReceiver Where to deliver the result.
545      *
546      * @hide
547      */
uninstall(@onNull String packageName, @DeleteFlags int flags, @NonNull IntentSender statusReceiver)548     public void uninstall(@NonNull String packageName, @DeleteFlags int flags,
549             @NonNull IntentSender statusReceiver) {
550         uninstall(new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST),
551                 flags, statusReceiver);
552     }
553 
554     /**
555      * Uninstall the given package with a specific version code, removing it
556      * completely from the device. If the version code of the package
557      * does not match the one passed in the versioned package argument this
558      * method is a no-op. Use {@link PackageManager#VERSION_CODE_HIGHEST} to
559      * uninstall the latest version of the package.
560      * <p>
561      * This method is available to:
562      * <ul>
563      * <li>the current "installer of record" for the package
564      * <li>the device owner
565      * <li>the affiliated profile owner
566      * </ul>
567      *
568      * @param versionedPackage The versioned package to uninstall.
569      * @param statusReceiver Where to deliver the result.
570      *
571      * @see android.app.admin.DevicePolicyManager
572      */
573     @RequiresPermission(anyOf = {
574             Manifest.permission.DELETE_PACKAGES,
575             Manifest.permission.REQUEST_DELETE_PACKAGES})
uninstall(@onNull VersionedPackage versionedPackage, @NonNull IntentSender statusReceiver)576     public void uninstall(@NonNull VersionedPackage versionedPackage,
577             @NonNull IntentSender statusReceiver) {
578         uninstall(versionedPackage, 0 /*flags*/, statusReceiver);
579     }
580 
581     /**
582      * Uninstall the given package with a specific version code, removing it
583      * completely from the device. This method is only available to the current
584      * "installer of record" for the package. If the version code of the package
585      * does not match the one passed in the versioned package argument this
586      * method is a no-op. Use {@link PackageManager#VERSION_CODE_HIGHEST} to
587      * uninstall the latest version of the package.
588      *
589      * @param versionedPackage The versioned package to uninstall.
590      * @param flags Flags for uninstall.
591      * @param statusReceiver Where to deliver the result.
592      *
593      * @hide
594      */
595     @RequiresPermission(anyOf = {
596             Manifest.permission.DELETE_PACKAGES,
597             Manifest.permission.REQUEST_DELETE_PACKAGES})
uninstall(@onNull VersionedPackage versionedPackage, @DeleteFlags int flags, @NonNull IntentSender statusReceiver)598     public void uninstall(@NonNull VersionedPackage versionedPackage, @DeleteFlags int flags,
599             @NonNull IntentSender statusReceiver) {
600         Preconditions.checkNotNull(versionedPackage, "versionedPackage cannot be null");
601         try {
602             mInstaller.uninstall(versionedPackage, mInstallerPackageName,
603                     flags, statusReceiver, mUserId);
604         } catch (RemoteException e) {
605             throw e.rethrowFromSystemServer();
606         }
607     }
608 
609     /**
610      * Install the given package, which already exists on the device, for the user for which this
611      * installer was created.
612      *
613      * <p>This will
614      * {@link PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set) whitelist
615      * all restricted permissions}.
616      *
617      * @param packageName The package to install.
618      * @param installReason Reason for install.
619      * @param statusReceiver Where to deliver the result.
620      */
621     @RequiresPermission(allOf = {
622             Manifest.permission.INSTALL_PACKAGES,
623             Manifest.permission.INSTALL_EXISTING_PACKAGES})
installExistingPackage(@onNull String packageName, @InstallReason int installReason, @Nullable IntentSender statusReceiver)624     public void installExistingPackage(@NonNull String packageName,
625             @InstallReason int installReason,
626             @Nullable IntentSender statusReceiver) {
627         Preconditions.checkNotNull(packageName, "packageName cannot be null");
628         try {
629             mInstaller.installExistingPackage(packageName,
630                     PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS, installReason,
631                     statusReceiver, mUserId, null);
632         } catch (RemoteException e) {
633             throw e.rethrowFromSystemServer();
634         }
635     }
636 
637 
638     /** {@hide} */
639     @SystemApi
640     @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES)
setPermissionsResult(int sessionId, boolean accepted)641     public void setPermissionsResult(int sessionId, boolean accepted) {
642         try {
643             mInstaller.setPermissionsResult(sessionId, accepted);
644         } catch (RemoteException e) {
645             throw e.rethrowFromSystemServer();
646         }
647     }
648 
649     /**
650      * Events for observing session lifecycle.
651      * <p>
652      * A typical session lifecycle looks like this:
653      * <ul>
654      * <li>An installer creates a session to indicate pending app delivery. All
655      * install details are available at this point.
656      * <li>The installer opens the session to deliver APK data. Note that a
657      * session may be opened and closed multiple times as network connectivity
658      * changes. The installer may deliver periodic progress updates.
659      * <li>The installer commits or abandons the session, resulting in the
660      * session being finished.
661      * </ul>
662      */
663     public static abstract class SessionCallback {
664         /**
665          * New session has been created. Details about the session can be
666          * obtained from {@link PackageInstaller#getSessionInfo(int)}.
667          */
onCreated(int sessionId)668         public abstract void onCreated(int sessionId);
669 
670         /**
671          * Badging details for an existing session has changed. For example, the
672          * app icon or label has been updated.
673          */
onBadgingChanged(int sessionId)674         public abstract void onBadgingChanged(int sessionId);
675 
676         /**
677          * Active state for session has been changed.
678          * <p>
679          * A session is considered active whenever there is ongoing forward
680          * progress being made, such as the installer holding an open
681          * {@link Session} instance while streaming data into place, or the
682          * system optimizing code as the result of
683          * {@link Session#commit(IntentSender)}.
684          * <p>
685          * If the installer closes the {@link Session} without committing, the
686          * session is considered inactive until the installer opens the session
687          * again.
688          */
onActiveChanged(int sessionId, boolean active)689         public abstract void onActiveChanged(int sessionId, boolean active);
690 
691         /**
692          * Progress for given session has been updated.
693          * <p>
694          * Note that this progress may not directly correspond to the value
695          * reported by
696          * {@link PackageInstaller.Session#setStagingProgress(float)}, as the
697          * system may carve out a portion of the overall progress to represent
698          * its own internal installation work.
699          */
onProgressChanged(int sessionId, float progress)700         public abstract void onProgressChanged(int sessionId, float progress);
701 
702         /**
703          * Session has completely finished, either with success or failure.
704          */
onFinished(int sessionId, boolean success)705         public abstract void onFinished(int sessionId, boolean success);
706     }
707 
708     /** {@hide} */
709     static class SessionCallbackDelegate extends IPackageInstallerCallback.Stub {
710         private static final int MSG_SESSION_CREATED = 1;
711         private static final int MSG_SESSION_BADGING_CHANGED = 2;
712         private static final int MSG_SESSION_ACTIVE_CHANGED = 3;
713         private static final int MSG_SESSION_PROGRESS_CHANGED = 4;
714         private static final int MSG_SESSION_FINISHED = 5;
715 
716         final SessionCallback mCallback;
717         final Executor mExecutor;
718 
SessionCallbackDelegate(SessionCallback callback, Executor executor)719         SessionCallbackDelegate(SessionCallback callback, Executor executor) {
720             mCallback = callback;
721             mExecutor = executor;
722         }
723 
724         @Override
onSessionCreated(int sessionId)725         public void onSessionCreated(int sessionId) {
726             mExecutor.execute(PooledLambda.obtainRunnable(SessionCallback::onCreated, mCallback,
727                     sessionId).recycleOnUse());
728         }
729 
730         @Override
onSessionBadgingChanged(int sessionId)731         public void onSessionBadgingChanged(int sessionId) {
732             mExecutor.execute(PooledLambda.obtainRunnable(SessionCallback::onBadgingChanged,
733                     mCallback, sessionId).recycleOnUse());
734         }
735 
736         @Override
onSessionActiveChanged(int sessionId, boolean active)737         public void onSessionActiveChanged(int sessionId, boolean active) {
738             mExecutor.execute(PooledLambda.obtainRunnable(SessionCallback::onActiveChanged,
739                     mCallback, sessionId, active).recycleOnUse());
740         }
741 
742         @Override
onSessionProgressChanged(int sessionId, float progress)743         public void onSessionProgressChanged(int sessionId, float progress) {
744             mExecutor.execute(PooledLambda.obtainRunnable(SessionCallback::onProgressChanged,
745                     mCallback, sessionId, progress).recycleOnUse());
746         }
747 
748         @Override
onSessionFinished(int sessionId, boolean success)749         public void onSessionFinished(int sessionId, boolean success) {
750             mExecutor.execute(PooledLambda.obtainRunnable(SessionCallback::onFinished,
751                     mCallback, sessionId, success).recycleOnUse());
752         }
753     }
754 
755     /** {@hide} */
756     @Deprecated
addSessionCallback(@onNull SessionCallback callback)757     public void addSessionCallback(@NonNull SessionCallback callback) {
758         registerSessionCallback(callback);
759     }
760 
761     /**
762      * Register to watch for session lifecycle events. No special permissions
763      * are required to watch for these events.
764      */
registerSessionCallback(@onNull SessionCallback callback)765     public void registerSessionCallback(@NonNull SessionCallback callback) {
766         registerSessionCallback(callback, new Handler());
767     }
768 
769     /** {@hide} */
770     @Deprecated
addSessionCallback(@onNull SessionCallback callback, @NonNull Handler handler)771     public void addSessionCallback(@NonNull SessionCallback callback, @NonNull Handler handler) {
772         registerSessionCallback(callback, handler);
773     }
774 
775     /**
776      * Register to watch for session lifecycle events. No special permissions
777      * are required to watch for these events.
778      *
779      * @param handler to dispatch callback events through, otherwise uses
780      *            calling thread.
781      */
registerSessionCallback(@onNull SessionCallback callback, @NonNull Handler handler)782     public void registerSessionCallback(@NonNull SessionCallback callback, @NonNull Handler handler) {
783         synchronized (mDelegates) {
784             final SessionCallbackDelegate delegate = new SessionCallbackDelegate(callback,
785                     new HandlerExecutor(handler));
786             try {
787                 mInstaller.registerCallback(delegate, mUserId);
788             } catch (RemoteException e) {
789                 throw e.rethrowFromSystemServer();
790             }
791             mDelegates.add(delegate);
792         }
793     }
794 
795     /** {@hide} */
796     @Deprecated
removeSessionCallback(@onNull SessionCallback callback)797     public void removeSessionCallback(@NonNull SessionCallback callback) {
798         unregisterSessionCallback(callback);
799     }
800 
801     /**
802      * Unregister a previously registered callback.
803      */
unregisterSessionCallback(@onNull SessionCallback callback)804     public void unregisterSessionCallback(@NonNull SessionCallback callback) {
805         synchronized (mDelegates) {
806             for (Iterator<SessionCallbackDelegate> i = mDelegates.iterator(); i.hasNext();) {
807                 final SessionCallbackDelegate delegate = i.next();
808                 if (delegate.mCallback == callback) {
809                     try {
810                         mInstaller.unregisterCallback(delegate);
811                     } catch (RemoteException e) {
812                         throw e.rethrowFromSystemServer();
813                     }
814                     i.remove();
815                 }
816             }
817         }
818     }
819 
820     /**
821      * An installation that is being actively staged. For an install to succeed,
822      * all existing and new packages must have identical package names, version
823      * codes, and signing certificates.
824      * <p>
825      * A session may contain any number of split packages. If the application
826      * does not yet exist, this session must include a base package.
827      * <p>
828      * If an APK included in this session is already defined by the existing
829      * installation (for example, the same split name), the APK in this session
830      * will replace the existing APK.
831      * <p>
832      * In such a case that multiple packages need to be committed simultaneously,
833      * multiple sessions can be referenced by a single multi-package session.
834      * This session is created with no package name and calling
835      * {@link SessionParams#setMultiPackage()}. The individual session IDs can be
836      * added with {@link #addChildSessionId(int)} and commit of the multi-package
837      * session will result in all child sessions being committed atomically.
838      */
839     public static class Session implements Closeable {
840         /** {@hide} */
841         protected final IPackageInstallerSession mSession;
842 
843         /** {@hide} */
Session(IPackageInstallerSession session)844         public Session(IPackageInstallerSession session) {
845             mSession = session;
846         }
847 
848         /** {@hide} */
849         @Deprecated
setProgress(float progress)850         public void setProgress(float progress) {
851             setStagingProgress(progress);
852         }
853 
854         /**
855          * Set current progress of staging this session. Valid values are
856          * anywhere between 0 and 1.
857          * <p>
858          * Note that this progress may not directly correspond to the value
859          * reported by {@link SessionCallback#onProgressChanged(int, float)}, as
860          * the system may carve out a portion of the overall progress to
861          * represent its own internal installation work.
862          */
setStagingProgress(float progress)863         public void setStagingProgress(float progress) {
864             try {
865                 mSession.setClientProgress(progress);
866             } catch (RemoteException e) {
867                 throw e.rethrowFromSystemServer();
868             }
869         }
870 
871         /** {@hide} */
872         @UnsupportedAppUsage
addProgress(float progress)873         public void addProgress(float progress) {
874             try {
875                 mSession.addClientProgress(progress);
876             } catch (RemoteException e) {
877                 throw e.rethrowFromSystemServer();
878             }
879         }
880 
881         /**
882          * Open a stream to write an APK file into the session.
883          * <p>
884          * The returned stream will start writing data at the requested offset
885          * in the underlying file, which can be used to resume a partially
886          * written file. If a valid file length is specified, the system will
887          * preallocate the underlying disk space to optimize placement on disk.
888          * It's strongly recommended to provide a valid file length when known.
889          * <p>
890          * You can write data into the returned stream, optionally call
891          * {@link #fsync(OutputStream)} as needed to ensure bytes have been
892          * persisted to disk, and then close when finished. All streams must be
893          * closed before calling {@link #commit(IntentSender)}.
894          *
895          * @param name arbitrary, unique name of your choosing to identify the
896          *            APK being written. You can open a file again for
897          *            additional writes (such as after a reboot) by using the
898          *            same name. This name is only meaningful within the context
899          *            of a single install session.
900          * @param offsetBytes offset into the file to begin writing at, or 0 to
901          *            start at the beginning of the file.
902          * @param lengthBytes total size of the file being written, used to
903          *            preallocate the underlying disk space, or -1 if unknown.
904          *            The system may clear various caches as needed to allocate
905          *            this space.
906          * @throws IOException if trouble opening the file for writing, such as
907          *             lack of disk space or unavailable media.
908          * @throws SecurityException if called after the session has been
909          *             sealed or abandoned
910          */
openWrite(@onNull String name, long offsetBytes, long lengthBytes)911         public @NonNull OutputStream openWrite(@NonNull String name, long offsetBytes,
912                 long lengthBytes) throws IOException {
913             try {
914                 if (ENABLE_REVOCABLE_FD) {
915                     return new ParcelFileDescriptor.AutoCloseOutputStream(
916                             mSession.openWrite(name, offsetBytes, lengthBytes));
917                 } else {
918                     final ParcelFileDescriptor clientSocket = mSession.openWrite(name,
919                             offsetBytes, lengthBytes);
920                     return new FileBridge.FileBridgeOutputStream(clientSocket);
921                 }
922             } catch (RuntimeException e) {
923                 ExceptionUtils.maybeUnwrapIOException(e);
924                 throw e;
925             } catch (RemoteException e) {
926                 throw e.rethrowFromSystemServer();
927             }
928         }
929 
930         /** {@hide} */
write(@onNull String name, long offsetBytes, long lengthBytes, @NonNull ParcelFileDescriptor fd)931         public void write(@NonNull String name, long offsetBytes, long lengthBytes,
932                 @NonNull ParcelFileDescriptor fd) throws IOException {
933             try {
934                 mSession.write(name, offsetBytes, lengthBytes, fd);
935             } catch (RuntimeException e) {
936                 ExceptionUtils.maybeUnwrapIOException(e);
937                 throw e;
938             } catch (RemoteException e) {
939                 throw e.rethrowFromSystemServer();
940             }
941         }
942 
943         /**
944          * Ensure that any outstanding data for given stream has been committed
945          * to disk. This is only valid for streams returned from
946          * {@link #openWrite(String, long, long)}.
947          */
fsync(@onNull OutputStream out)948         public void fsync(@NonNull OutputStream out) throws IOException {
949             if (ENABLE_REVOCABLE_FD) {
950                 if (out instanceof ParcelFileDescriptor.AutoCloseOutputStream) {
951                     try {
952                         Os.fsync(((ParcelFileDescriptor.AutoCloseOutputStream) out).getFD());
953                     } catch (ErrnoException e) {
954                         throw e.rethrowAsIOException();
955                     }
956                 } else {
957                     throw new IllegalArgumentException("Unrecognized stream");
958                 }
959             } else {
960                 if (out instanceof FileBridge.FileBridgeOutputStream) {
961                     ((FileBridge.FileBridgeOutputStream) out).fsync();
962                 } else {
963                     throw new IllegalArgumentException("Unrecognized stream");
964                 }
965             }
966         }
967 
968         /**
969          * Return all APK names contained in this session.
970          * <p>
971          * This returns all names which have been previously written through
972          * {@link #openWrite(String, long, long)} as part of this session.
973          *
974          * @throws SecurityException if called after the session has been
975          *             committed or abandoned.
976          */
getNames()977         public @NonNull String[] getNames() throws IOException {
978             try {
979                 return mSession.getNames();
980             } catch (RuntimeException e) {
981                 ExceptionUtils.maybeUnwrapIOException(e);
982                 throw e;
983             } catch (RemoteException e) {
984                 throw e.rethrowFromSystemServer();
985             }
986         }
987 
988         /**
989          * Open a stream to read an APK file from the session.
990          * <p>
991          * This is only valid for names which have been previously written
992          * through {@link #openWrite(String, long, long)} as part of this
993          * session. For example, this stream may be used to calculate a
994          * {@link MessageDigest} of a written APK before committing.
995          *
996          * @throws SecurityException if called after the session has been
997          *             committed or abandoned.
998          */
openRead(@onNull String name)999         public @NonNull InputStream openRead(@NonNull String name) throws IOException {
1000             try {
1001                 final ParcelFileDescriptor pfd = mSession.openRead(name);
1002                 return new ParcelFileDescriptor.AutoCloseInputStream(pfd);
1003             } catch (RuntimeException e) {
1004                 ExceptionUtils.maybeUnwrapIOException(e);
1005                 throw e;
1006             } catch (RemoteException e) {
1007                 throw e.rethrowFromSystemServer();
1008             }
1009         }
1010 
1011         /**
1012          * Removes a split.
1013          * <p>
1014          * Split removals occur prior to adding new APKs. If upgrading a feature
1015          * split, it is not expected nor desirable to remove the split prior to
1016          * upgrading.
1017          * <p>
1018          * When split removal is bundled with new APKs, the packageName must be
1019          * identical.
1020          */
removeSplit(@onNull String splitName)1021         public void removeSplit(@NonNull String splitName) throws IOException {
1022             try {
1023                 mSession.removeSplit(splitName);
1024             } catch (RuntimeException e) {
1025                 ExceptionUtils.maybeUnwrapIOException(e);
1026                 throw e;
1027             } catch (RemoteException e) {
1028                 throw e.rethrowFromSystemServer();
1029             }
1030         }
1031 
1032         /**
1033          * Attempt to commit everything staged in this session. This may require
1034          * user intervention, and so it may not happen immediately. The final
1035          * result of the commit will be reported through the given callback.
1036          * <p>
1037          * Once this method is called, the session is sealed and no additional
1038          * mutations may be performed on the session. If the device reboots
1039          * before the session has been finalized, you may commit the session again.
1040          * <p>
1041          * If the installer is the device owner or the affiliated profile owner, there will be no
1042          * user intervention.
1043          *
1044          * @param statusReceiver Called when the state of the session changes. Intents
1045          *                       sent to this receiver contain {@link #EXTRA_STATUS}. Refer to the
1046          *                       individual status codes on how to handle them.
1047          *
1048          * @throws SecurityException if streams opened through
1049          *             {@link #openWrite(String, long, long)} are still open.
1050          *
1051          * @see android.app.admin.DevicePolicyManager
1052          */
commit(@onNull IntentSender statusReceiver)1053         public void commit(@NonNull IntentSender statusReceiver) {
1054             try {
1055                 mSession.commit(statusReceiver, false);
1056             } catch (RemoteException e) {
1057                 throw e.rethrowFromSystemServer();
1058             }
1059         }
1060 
1061         /**
1062          * Attempt to commit a session that has been {@link #transfer(String) transferred}.
1063          *
1064          * <p>If the device reboots before the session has been finalized, you may commit the
1065          * session again.
1066          *
1067          * <p>The caller of this method is responsible to ensure the safety of the session. As the
1068          * session was created by another - usually less trusted - app, it is paramount that before
1069          * committing <u>all</u> public and system {@link SessionInfo properties of the session}
1070          * and <u>all</u> {@link #openRead(String) APKs} are verified by the caller. It might happen
1071          * that new properties are added to the session with a new API revision. In this case the
1072          * callers need to be updated.
1073          *
1074          * @param statusReceiver Called when the state of the session changes. Intents
1075          *                       sent to this receiver contain {@link #EXTRA_STATUS}. Refer to the
1076          *                       individual status codes on how to handle them.
1077          *
1078          * @hide
1079          */
1080         @SystemApi
1081         @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES)
commitTransferred(@onNull IntentSender statusReceiver)1082         public void commitTransferred(@NonNull IntentSender statusReceiver) {
1083             try {
1084                 mSession.commit(statusReceiver, true);
1085             } catch (RemoteException e) {
1086                 throw e.rethrowFromSystemServer();
1087             }
1088         }
1089 
1090         /**
1091          * Transfer the session to a new owner.
1092          * <p>
1093          * Only sessions that update the installing app can be transferred.
1094          * <p>
1095          * After the transfer to a package with a different uid all method calls on the session
1096          * will cause {@link SecurityException}s.
1097          * <p>
1098          * Once this method is called, the session is sealed and no additional mutations beside
1099          * committing it may be performed on the session.
1100          *
1101          * @param packageName The package of the new owner. Needs to hold the INSTALL_PACKAGES
1102          *                    permission.
1103          *
1104          * @throws PackageManager.NameNotFoundException if the new owner could not be found.
1105          * @throws SecurityException if called after the session has been committed or abandoned.
1106          * @throws SecurityException if the session does not update the original installer
1107          * @throws SecurityException if streams opened through
1108          *                           {@link #openWrite(String, long, long) are still open.
1109          */
transfer(@onNull String packageName)1110         public void transfer(@NonNull String packageName)
1111                 throws PackageManager.NameNotFoundException {
1112             Preconditions.checkNotNull(packageName);
1113 
1114             try {
1115                 mSession.transfer(packageName);
1116             } catch (ParcelableException e) {
1117                 e.maybeRethrow(PackageManager.NameNotFoundException.class);
1118                 throw new RuntimeException(e);
1119             } catch (RemoteException e) {
1120                 throw e.rethrowFromSystemServer();
1121             }
1122         }
1123 
1124         /**
1125          * Release this session object. You can open the session again if it
1126          * hasn't been finalized.
1127          */
1128         @Override
close()1129         public void close() {
1130             try {
1131                 mSession.close();
1132             } catch (RemoteException e) {
1133                 throw e.rethrowFromSystemServer();
1134             }
1135         }
1136 
1137         /**
1138          * Completely abandon this session, destroying all staged data and
1139          * rendering it invalid. Abandoned sessions will be reported to
1140          * {@link SessionCallback} listeners as failures. This is equivalent to
1141          * opening the session and calling {@link Session#abandon()}.
1142          */
abandon()1143         public void abandon() {
1144             try {
1145                 mSession.abandon();
1146             } catch (RemoteException e) {
1147                 throw e.rethrowFromSystemServer();
1148             }
1149         }
1150 
1151         /**
1152          * @return {@code true} if this session will commit more than one package when it is
1153          * committed.
1154          */
isMultiPackage()1155         public boolean isMultiPackage() {
1156             try {
1157                 return mSession.isMultiPackage();
1158             } catch (RemoteException e) {
1159                 throw e.rethrowFromSystemServer();
1160             }
1161         }
1162 
1163         /**
1164          * @return {@code true} if this session will be staged and applied at next reboot.
1165          */
isStaged()1166         public boolean isStaged() {
1167             try {
1168                 return mSession.isStaged();
1169             } catch (RemoteException e) {
1170                 throw e.rethrowFromSystemServer();
1171             }
1172         }
1173 
1174         /**
1175          * @return the session ID of the multi-package session that this belongs to or
1176          * {@link SessionInfo#INVALID_ID} if it does not belong to a multi-package session.
1177          */
getParentSessionId()1178         public int getParentSessionId() {
1179             try {
1180                 return mSession.getParentSessionId();
1181             } catch (RemoteException e) {
1182                 throw e.rethrowFromSystemServer();
1183             }
1184         }
1185 
1186         /**
1187          * @return the set of session IDs that will be committed atomically when this session is
1188          * committed if this is a multi-package session or null if none exist.
1189          */
1190         @NonNull
getChildSessionIds()1191         public int[] getChildSessionIds() {
1192             try {
1193                 return mSession.getChildSessionIds();
1194             } catch (RemoteException e) {
1195                 throw e.rethrowFromSystemServer();
1196             }
1197         }
1198 
1199         /**
1200          * Adds a session ID to the set of sessions that will be committed atomically
1201          * when this session is committed.
1202          *
1203          * <p>If the parent is staged or has rollback enabled, all children must have
1204          * the same properties.
1205          *
1206          * @param sessionId the session ID to add to this multi-package session.
1207          */
addChildSessionId(int sessionId)1208         public void addChildSessionId(int sessionId) {
1209             try {
1210                 mSession.addChildSessionId(sessionId);
1211             } catch (RemoteException e) {
1212                 e.rethrowFromSystemServer();
1213             }
1214         }
1215 
1216         /**
1217          * Removes a session ID from the set of sessions that will be committed
1218          * atomically when this session is committed.
1219          *
1220          * @param sessionId the session ID to remove from this multi-package session.
1221          */
removeChildSessionId(int sessionId)1222         public void removeChildSessionId(int sessionId) {
1223             try {
1224                 mSession.removeChildSessionId(sessionId);
1225             } catch (RemoteException e) {
1226                 e.rethrowFromSystemServer();
1227             }
1228         }
1229     }
1230 
1231     /**
1232      * Parameters for creating a new {@link PackageInstaller.Session}.
1233      */
1234     public static class SessionParams implements Parcelable {
1235 
1236         /** {@hide} */
1237         public static final int MODE_INVALID = -1;
1238 
1239         /**
1240          * Mode for an install session whose staged APKs should fully replace any
1241          * existing APKs for the target app.
1242          */
1243         public static final int MODE_FULL_INSTALL = 1;
1244 
1245         /**
1246          * Mode for an install session that should inherit any existing APKs for the
1247          * target app, unless they have been explicitly overridden (based on split
1248          * name) by the session. For example, this can be used to add one or more
1249          * split APKs to an existing installation.
1250          * <p>
1251          * If there are no existing APKs for the target app, this behaves like
1252          * {@link #MODE_FULL_INSTALL}.
1253          */
1254         public static final int MODE_INHERIT_EXISTING = 2;
1255 
1256         /**
1257          * Special constant to refer to all restricted permissions.
1258          */
1259         public static final @NonNull Set<String> RESTRICTED_PERMISSIONS_ALL = new ArraySet<>();
1260 
1261         /** {@hide} */
1262         public static final int UID_UNKNOWN = -1;
1263 
1264         /** {@hide} */
1265         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
1266         public int mode = MODE_INVALID;
1267         /** {@hide} */
1268         @UnsupportedAppUsage
1269         public int installFlags = PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS;
1270         /** {@hide} */
1271         public int installLocation = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY;
1272         /** {@hide} */
1273         public @InstallReason int installReason = PackageManager.INSTALL_REASON_UNKNOWN;
1274         /** {@hide} */
1275         @UnsupportedAppUsage
1276         public long sizeBytes = -1;
1277         /** {@hide} */
1278         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
1279         public String appPackageName;
1280         /** {@hide} */
1281         @UnsupportedAppUsage
1282         public Bitmap appIcon;
1283         /** {@hide} */
1284         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
1285         public String appLabel;
1286         /** {@hide} */
1287         public long appIconLastModified = -1;
1288         /** {@hide} */
1289         public Uri originatingUri;
1290         /** {@hide} */
1291         @UnsupportedAppUsage
1292         public int originatingUid = UID_UNKNOWN;
1293         /** {@hide} */
1294         public Uri referrerUri;
1295         /** {@hide} */
1296         public String abiOverride;
1297         /** {@hide} */
1298         public String volumeUuid;
1299         /** {@hide} */
1300         public String[] grantedRuntimePermissions;
1301         /** {@hide} */
1302         public List<String> whitelistedRestrictedPermissions;
1303         /** {@hide} */
1304         public String installerPackageName;
1305         /** {@hide} */
1306         public boolean isMultiPackage;
1307         /** {@hide} */
1308         public boolean isStaged;
1309         /** {@hide} */
1310         public long requiredInstalledVersionCode = PackageManager.VERSION_CODE_HIGHEST;
1311 
1312         /**
1313          * Construct parameters for a new package install session.
1314          *
1315          * @param mode one of {@link #MODE_FULL_INSTALL} or
1316          *            {@link #MODE_INHERIT_EXISTING} describing how the session
1317          *            should interact with an existing app.
1318          */
SessionParams(int mode)1319         public SessionParams(int mode) {
1320             this.mode = mode;
1321         }
1322 
1323         /** {@hide} */
SessionParams(Parcel source)1324         public SessionParams(Parcel source) {
1325             mode = source.readInt();
1326             installFlags = source.readInt();
1327             installLocation = source.readInt();
1328             installReason = source.readInt();
1329             sizeBytes = source.readLong();
1330             appPackageName = source.readString();
1331             appIcon = source.readParcelable(null);
1332             appLabel = source.readString();
1333             originatingUri = source.readParcelable(null);
1334             originatingUid = source.readInt();
1335             referrerUri = source.readParcelable(null);
1336             abiOverride = source.readString();
1337             volumeUuid = source.readString();
1338             grantedRuntimePermissions = source.readStringArray();
1339             whitelistedRestrictedPermissions = source.createStringArrayList();
1340             installerPackageName = source.readString();
1341             isMultiPackage = source.readBoolean();
1342             isStaged = source.readBoolean();
1343             requiredInstalledVersionCode = source.readLong();
1344         }
1345 
1346         /** {@hide} */
copy()1347         public SessionParams copy() {
1348             SessionParams ret = new SessionParams(mode);
1349             ret.installFlags = installFlags;
1350             ret.installLocation = installLocation;
1351             ret.installReason = installReason;
1352             ret.sizeBytes = sizeBytes;
1353             ret.appPackageName = appPackageName;
1354             ret.appIcon = appIcon;  // not a copy.
1355             ret.appLabel = appLabel;
1356             ret.originatingUri = originatingUri;  // not a copy, but immutable.
1357             ret.originatingUid = originatingUid;
1358             ret.referrerUri = referrerUri;  // not a copy, but immutable.
1359             ret.abiOverride = abiOverride;
1360             ret.volumeUuid = volumeUuid;
1361             ret.grantedRuntimePermissions = grantedRuntimePermissions;
1362             ret.whitelistedRestrictedPermissions = whitelistedRestrictedPermissions;
1363             ret.installerPackageName = installerPackageName;
1364             ret.isMultiPackage = isMultiPackage;
1365             ret.isStaged = isStaged;
1366             ret.requiredInstalledVersionCode = requiredInstalledVersionCode;
1367             return ret;
1368         }
1369 
1370         /**
1371          * Check if there are hidden options set.
1372          *
1373          * <p>Hidden options are those options that cannot be verified via public or system-api
1374          * methods on {@link SessionInfo}.
1375          *
1376          * @return {@code true} if any hidden option is set.
1377          *
1378          * @hide
1379          */
areHiddenOptionsSet()1380         public boolean areHiddenOptionsSet() {
1381             return (installFlags & (PackageManager.INSTALL_REQUEST_DOWNGRADE
1382                     | PackageManager.INSTALL_ALLOW_DOWNGRADE
1383                     | PackageManager.INSTALL_DONT_KILL_APP
1384                     | PackageManager.INSTALL_INSTANT_APP
1385                     | PackageManager.INSTALL_FULL_APP
1386                     | PackageManager.INSTALL_VIRTUAL_PRELOAD
1387                     | PackageManager.INSTALL_ALLOCATE_AGGRESSIVE)) != installFlags
1388                     || abiOverride != null || volumeUuid != null;
1389         }
1390 
1391         /**
1392          * Provide value of {@link PackageInfo#installLocation}, which may be used
1393          * to determine where the app will be staged. Defaults to
1394          * {@link PackageInfo#INSTALL_LOCATION_INTERNAL_ONLY}.
1395          */
setInstallLocation(int installLocation)1396         public void setInstallLocation(int installLocation) {
1397             this.installLocation = installLocation;
1398         }
1399 
1400         /**
1401          * Optionally indicate the total size (in bytes) of all APKs that will be
1402          * delivered in this session. The system may use this to ensure enough disk
1403          * space exists before proceeding, or to estimate container size for
1404          * installations living on external storage.
1405          *
1406          * @see PackageInfo#INSTALL_LOCATION_AUTO
1407          * @see PackageInfo#INSTALL_LOCATION_PREFER_EXTERNAL
1408          */
setSize(long sizeBytes)1409         public void setSize(long sizeBytes) {
1410             this.sizeBytes = sizeBytes;
1411         }
1412 
1413         /**
1414          * Optionally set the package name of the app being installed. It's strongly
1415          * recommended that you provide this value when known, so that observers can
1416          * communicate installing apps to users.
1417          * <p>
1418          * If the APKs staged in the session aren't consistent with this package
1419          * name, the install will fail. Regardless of this value, all APKs in the
1420          * app must have the same package name.
1421          */
setAppPackageName(@ullable String appPackageName)1422         public void setAppPackageName(@Nullable String appPackageName) {
1423             this.appPackageName = appPackageName;
1424         }
1425 
1426         /**
1427          * Optionally set an icon representing the app being installed. This should
1428          * be roughly {@link ActivityManager#getLauncherLargeIconSize()} in both
1429          * dimensions.
1430          */
setAppIcon(@ullable Bitmap appIcon)1431         public void setAppIcon(@Nullable Bitmap appIcon) {
1432             this.appIcon = appIcon;
1433         }
1434 
1435         /**
1436          * Optionally set a label representing the app being installed.
1437          */
setAppLabel(@ullable CharSequence appLabel)1438         public void setAppLabel(@Nullable CharSequence appLabel) {
1439             this.appLabel = (appLabel != null) ? appLabel.toString() : null;
1440         }
1441 
1442         /**
1443          * Optionally set the URI where this package was downloaded from. This is
1444          * informational and may be used as a signal for anti-malware purposes.
1445          *
1446          * @see Intent#EXTRA_ORIGINATING_URI
1447          */
setOriginatingUri(@ullable Uri originatingUri)1448         public void setOriginatingUri(@Nullable Uri originatingUri) {
1449             this.originatingUri = originatingUri;
1450         }
1451 
1452         /**
1453          * Sets the UID that initiated the package installation. This is informational
1454          * and may be used as a signal for anti-malware purposes.
1455          */
setOriginatingUid(int originatingUid)1456         public void setOriginatingUid(int originatingUid) {
1457             this.originatingUid = originatingUid;
1458         }
1459 
1460         /**
1461          * Optionally set the URI that referred you to install this package. This is
1462          * informational and may be used as a signal for anti-malware purposes.
1463          *
1464          * @see Intent#EXTRA_REFERRER
1465          */
setReferrerUri(@ullable Uri referrerUri)1466         public void setReferrerUri(@Nullable Uri referrerUri) {
1467             this.referrerUri = referrerUri;
1468         }
1469 
1470         /**
1471          * Sets which runtime permissions to be granted to the package at installation.
1472          *
1473          * @param permissions The permissions to grant or null to grant all runtime
1474          *     permissions.
1475          *
1476          * @hide
1477          */
1478         @TestApi
1479         @SystemApi
1480         @RequiresPermission(android.Manifest.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS)
setGrantedRuntimePermissions(String[] permissions)1481         public void setGrantedRuntimePermissions(String[] permissions) {
1482             installFlags |= PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS;
1483             this.grantedRuntimePermissions = permissions;
1484         }
1485 
1486         /**
1487          * Sets which restricted permissions to be whitelisted for the app. Whitelisting
1488          * is not granting the permissions, rather it allows the app to hold permissions
1489          * which are otherwise restricted. Whitelisting a non restricted permission has
1490          * no effect.
1491          *
1492          * <p> Permissions can be hard restricted which means that the app cannot hold
1493          * them or soft restricted where the app can hold the permission but in a weaker
1494          * form. Whether a permission is {@link PermissionInfo#FLAG_HARD_RESTRICTED hard
1495          * restricted} or {@link PermissionInfo#FLAG_SOFT_RESTRICTED soft restricted}
1496          * depends on the permission declaration. Whitelisting a hard restricted permission
1497          * allows the app to hold that permission and whitelisting a soft restricted
1498          * permission allows the app to hold the permission in its full, unrestricted form.
1499          *
1500          * <p> Permissions can also be immutably restricted which means that the whitelist
1501          * state of the permission can be determined only at install time and cannot be
1502          * changed on updated or at a later point via the package manager APIs.
1503          *
1504          * <p>Initially, all restricted permissions are whitelisted but you can change
1505          * which ones are whitelisted by calling this method or the corresponding ones
1506          * on the {@link PackageManager}.
1507          *
1508          * @see PackageManager#addWhitelistedRestrictedPermission(String, String, int)
1509          * @see PackageManager#removeWhitelistedRestrictedPermission(String, String, int)
1510          */
setWhitelistedRestrictedPermissions(@ullable Set<String> permissions)1511         public void setWhitelistedRestrictedPermissions(@Nullable Set<String> permissions) {
1512             if (permissions == RESTRICTED_PERMISSIONS_ALL) {
1513                 installFlags |= PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS;
1514                 whitelistedRestrictedPermissions = null;
1515             } else {
1516                 installFlags &= ~PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS;
1517                 whitelistedRestrictedPermissions = (permissions != null)
1518                         ? new ArrayList<>(permissions) : null;
1519             }
1520         }
1521 
1522         /**
1523          * Request that rollbacks be enabled or disabled for the given upgrade.
1524          *
1525          * <p>If the parent session is staged or has rollback enabled, all children sessions
1526          * must have the same properties.
1527          *
1528          * @param enable set to {@code true} to enable, {@code false} to disable
1529          * @hide
1530          */
1531         @SystemApi @TestApi
setEnableRollback(boolean enable)1532         public void setEnableRollback(boolean enable) {
1533             if (enable) {
1534                 installFlags |= PackageManager.INSTALL_ENABLE_ROLLBACK;
1535             } else {
1536                 installFlags &= ~PackageManager.INSTALL_ENABLE_ROLLBACK;
1537             }
1538         }
1539 
1540         /**
1541          * @deprecated use {@link #setRequestDowngrade(boolean)}.
1542          * {@hide}
1543          */
1544         @SystemApi
1545         @Deprecated
setAllowDowngrade(boolean allowDowngrade)1546         public void setAllowDowngrade(boolean allowDowngrade) {
1547             setRequestDowngrade(allowDowngrade);
1548         }
1549 
1550         /** {@hide} */
1551         @SystemApi @TestApi
setRequestDowngrade(boolean requestDowngrade)1552         public void setRequestDowngrade(boolean requestDowngrade) {
1553             if (requestDowngrade) {
1554                 installFlags |= PackageManager.INSTALL_REQUEST_DOWNGRADE;
1555             } else {
1556                 installFlags &= ~PackageManager.INSTALL_REQUEST_DOWNGRADE;
1557             }
1558         }
1559 
1560         /**
1561          * Require the given version of the package be installed.
1562          * The install will only be allowed if the existing version code of
1563          * the package installed on the device matches the given version code.
1564          * Use {@link * PackageManager#VERSION_CODE_HIGHEST} to allow
1565          * installation regardless of the currently installed package version.
1566          *
1567          * @hide
1568          */
setRequiredInstalledVersionCode(long versionCode)1569         public void setRequiredInstalledVersionCode(long versionCode) {
1570             requiredInstalledVersionCode = versionCode;
1571         }
1572 
1573         /** {@hide} */
setInstallFlagsForcePermissionPrompt()1574         public void setInstallFlagsForcePermissionPrompt() {
1575             installFlags |= PackageManager.INSTALL_FORCE_PERMISSION_PROMPT;
1576         }
1577 
1578         /** {@hide} */
1579         @SystemApi
setDontKillApp(boolean dontKillApp)1580         public void setDontKillApp(boolean dontKillApp) {
1581             if (dontKillApp) {
1582                 installFlags |= PackageManager.INSTALL_DONT_KILL_APP;
1583             } else {
1584                 installFlags &= ~PackageManager.INSTALL_DONT_KILL_APP;
1585             }
1586         }
1587 
1588         /** {@hide} */
1589         @SystemApi
setInstallAsInstantApp(boolean isInstantApp)1590         public void setInstallAsInstantApp(boolean isInstantApp) {
1591             if (isInstantApp) {
1592                 installFlags |= PackageManager.INSTALL_INSTANT_APP;
1593                 installFlags &= ~PackageManager.INSTALL_FULL_APP;
1594             } else {
1595                 installFlags &= ~PackageManager.INSTALL_INSTANT_APP;
1596                 installFlags |= PackageManager.INSTALL_FULL_APP;
1597             }
1598         }
1599 
1600         /**
1601          * Sets the install as a virtual preload. Will only have effect when called
1602          * by the verifier.
1603          * {@hide}
1604          */
1605         @SystemApi
setInstallAsVirtualPreload()1606         public void setInstallAsVirtualPreload() {
1607             installFlags |= PackageManager.INSTALL_VIRTUAL_PRELOAD;
1608         }
1609 
1610         /**
1611          * Set the reason for installing this package.
1612          * <p>
1613          * The install reason should be a pre-defined integer. The behavior is
1614          * undefined if other values are used.
1615          *
1616          * @see PackageManager#INSTALL_REASON_UNKNOWN
1617          * @see PackageManager#INSTALL_REASON_POLICY
1618          * @see PackageManager#INSTALL_REASON_DEVICE_RESTORE
1619          * @see PackageManager#INSTALL_REASON_DEVICE_SETUP
1620          * @see PackageManager#INSTALL_REASON_USER
1621          */
setInstallReason(@nstallReason int installReason)1622         public void setInstallReason(@InstallReason int installReason) {
1623             this.installReason = installReason;
1624         }
1625 
1626         /** {@hide} */
1627         @SystemApi
1628         @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE)
setAllocateAggressive(boolean allocateAggressive)1629         public void setAllocateAggressive(boolean allocateAggressive) {
1630             if (allocateAggressive) {
1631                 installFlags |= PackageManager.INSTALL_ALLOCATE_AGGRESSIVE;
1632             } else {
1633                 installFlags &= ~PackageManager.INSTALL_ALLOCATE_AGGRESSIVE;
1634             }
1635         }
1636 
1637         /**
1638          * Set the installer package for the app.
1639          *
1640          * By default this is the app that created the {@link PackageInstaller} object.
1641          *
1642          * @param installerPackageName name of the installer package
1643          * {@hide}
1644          */
setInstallerPackageName(String installerPackageName)1645         public void setInstallerPackageName(String installerPackageName) {
1646             this.installerPackageName = installerPackageName;
1647         }
1648 
1649         /**
1650          * Set this session to be the parent of a multi-package install.
1651          *
1652          * A multi-package install session contains no APKs and only references other install
1653          * sessions via ID. When a multi-package session is committed, all of its children
1654          * are committed to the system in an atomic manner. If any children fail to install,
1655          * all of them do, including the multi-package session.
1656          */
setMultiPackage()1657         public void setMultiPackage() {
1658             this.isMultiPackage = true;
1659         }
1660 
1661         /**
1662          * Set this session to be staged to be installed at reboot.
1663          *
1664          * Staged sessions are scheduled to be installed at next reboot. Staged sessions can also be
1665          * multi-package. In that case, if any of the children sessions fail to install at reboot,
1666          * all the other children sessions are aborted as well.
1667          *
1668          * <p>If the parent session is staged or has rollback enabled, all children sessions
1669          * must have the same properties.
1670          *
1671          * {@hide}
1672          */
1673         @SystemApi @TestApi
1674         @RequiresPermission(Manifest.permission.INSTALL_PACKAGES)
setStaged()1675         public void setStaged() {
1676             this.isStaged = true;
1677         }
1678 
1679         /**
1680          * Set this session to be installing an APEX package.
1681          *
1682          * {@hide}
1683          */
1684         @SystemApi @TestApi
1685         @RequiresPermission(Manifest.permission.INSTALL_PACKAGES)
setInstallAsApex()1686         public void setInstallAsApex() {
1687             installFlags |= PackageManager.INSTALL_APEX;
1688         }
1689 
1690         /** @hide */
getEnableRollback()1691         public boolean getEnableRollback() {
1692             return (installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0;
1693         }
1694 
1695         /** {@hide} */
dump(IndentingPrintWriter pw)1696         public void dump(IndentingPrintWriter pw) {
1697             pw.printPair("mode", mode);
1698             pw.printHexPair("installFlags", installFlags);
1699             pw.printPair("installLocation", installLocation);
1700             pw.printPair("sizeBytes", sizeBytes);
1701             pw.printPair("appPackageName", appPackageName);
1702             pw.printPair("appIcon", (appIcon != null));
1703             pw.printPair("appLabel", appLabel);
1704             pw.printPair("originatingUri", originatingUri);
1705             pw.printPair("originatingUid", originatingUid);
1706             pw.printPair("referrerUri", referrerUri);
1707             pw.printPair("abiOverride", abiOverride);
1708             pw.printPair("volumeUuid", volumeUuid);
1709             pw.printPair("grantedRuntimePermissions", grantedRuntimePermissions);
1710             pw.printPair("whitelistedRestrictedPermissions", whitelistedRestrictedPermissions);
1711             pw.printPair("installerPackageName", installerPackageName);
1712             pw.printPair("isMultiPackage", isMultiPackage);
1713             pw.printPair("isStaged", isStaged);
1714             pw.printPair("requiredInstalledVersionCode", requiredInstalledVersionCode);
1715             pw.println();
1716         }
1717 
1718         @Override
describeContents()1719         public int describeContents() {
1720             return 0;
1721         }
1722 
1723         @Override
writeToParcel(Parcel dest, int flags)1724         public void writeToParcel(Parcel dest, int flags) {
1725             dest.writeInt(mode);
1726             dest.writeInt(installFlags);
1727             dest.writeInt(installLocation);
1728             dest.writeInt(installReason);
1729             dest.writeLong(sizeBytes);
1730             dest.writeString(appPackageName);
1731             dest.writeParcelable(appIcon, flags);
1732             dest.writeString(appLabel);
1733             dest.writeParcelable(originatingUri, flags);
1734             dest.writeInt(originatingUid);
1735             dest.writeParcelable(referrerUri, flags);
1736             dest.writeString(abiOverride);
1737             dest.writeString(volumeUuid);
1738             dest.writeStringArray(grantedRuntimePermissions);
1739             dest.writeStringList(whitelistedRestrictedPermissions);
1740             dest.writeString(installerPackageName);
1741             dest.writeBoolean(isMultiPackage);
1742             dest.writeBoolean(isStaged);
1743             dest.writeLong(requiredInstalledVersionCode);
1744         }
1745 
1746         public static final Parcelable.Creator<SessionParams>
1747                 CREATOR = new Parcelable.Creator<SessionParams>() {
1748                     @Override
1749                     public SessionParams createFromParcel(Parcel p) {
1750                         return new SessionParams(p);
1751                     }
1752 
1753                     @Override
1754                     public SessionParams[] newArray(int size) {
1755                         return new SessionParams[size];
1756                     }
1757                 };
1758     }
1759 
1760     /**
1761      * Details for an active install session.
1762      */
1763     public static class SessionInfo implements Parcelable {
1764 
1765         /**
1766          * A session ID that does not exist or is invalid.
1767          */
1768         public static final int INVALID_ID = -1;
1769         /** {@hide} */
1770         private static final int[] NO_SESSIONS = {};
1771 
1772         /** @hide */
1773         @IntDef(prefix = { "STAGED_SESSION_" }, value = {
1774                 STAGED_SESSION_NO_ERROR,
1775                 STAGED_SESSION_VERIFICATION_FAILED,
1776                 STAGED_SESSION_ACTIVATION_FAILED,
1777                 STAGED_SESSION_UNKNOWN})
1778         @Retention(RetentionPolicy.SOURCE)
1779         public @interface StagedSessionErrorCode{}
1780         /**
1781          * Constant indicating that no error occurred during the preparation or the activation of
1782          * this staged session.
1783          */
1784         public static final int STAGED_SESSION_NO_ERROR = 0;
1785 
1786         /**
1787          * Constant indicating that an error occurred during the verification phase (pre-reboot) of
1788          * this staged session.
1789          */
1790         public static final int STAGED_SESSION_VERIFICATION_FAILED = 1;
1791 
1792         /**
1793          * Constant indicating that an error occurred during the activation phase (post-reboot) of
1794          * this staged session.
1795          */
1796         public static final int STAGED_SESSION_ACTIVATION_FAILED = 2;
1797 
1798         /**
1799          * Constant indicating that an unknown error occurred while processing this staged session.
1800          */
1801         public static final int STAGED_SESSION_UNKNOWN = 3;
1802 
1803         /** {@hide} */
1804         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
1805         public int sessionId;
1806         /** {@hide} */
1807         public int userId;
1808         /** {@hide} */
1809         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
1810         public String installerPackageName;
1811         /** {@hide} */
1812         @UnsupportedAppUsage
1813         public String resolvedBaseCodePath;
1814         /** {@hide} */
1815         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
1816         public float progress;
1817         /** {@hide} */
1818         @UnsupportedAppUsage
1819         public boolean sealed;
1820         /** {@hide} */
1821         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
1822         public boolean active;
1823 
1824         /** {@hide} */
1825         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
1826         public int mode;
1827         /** {@hide} */
1828         public @InstallReason int installReason;
1829         /** {@hide} */
1830         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
1831         public long sizeBytes;
1832         /** {@hide} */
1833         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
1834         public String appPackageName;
1835         /** {@hide} */
1836         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
1837         public Bitmap appIcon;
1838         /** {@hide} */
1839         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
1840         public CharSequence appLabel;
1841 
1842         /** {@hide} */
1843         public int installLocation;
1844         /** {@hide} */
1845         public Uri originatingUri;
1846         /** {@hide} */
1847         public int originatingUid;
1848         /** {@hide} */
1849         public Uri referrerUri;
1850         /** {@hide} */
1851         public String[] grantedRuntimePermissions;
1852         /** {@hide}*/
1853         public List<String> whitelistedRestrictedPermissions;
1854         /** {@hide} */
1855         public int installFlags;
1856         /** {@hide} */
1857         public boolean isMultiPackage;
1858         /** {@hide} */
1859         public boolean isStaged;
1860         /** {@hide} */
1861         public int parentSessionId = INVALID_ID;
1862         /** {@hide} */
1863         public int[] childSessionIds = NO_SESSIONS;
1864 
1865         /** {@hide} */
1866         public boolean isStagedSessionApplied;
1867         /** {@hide} */
1868         public boolean isStagedSessionReady;
1869         /** {@hide} */
1870         public boolean isStagedSessionFailed;
1871         private int mStagedSessionErrorCode;
1872         private String mStagedSessionErrorMessage;
1873 
1874         /** {@hide} */
1875         public boolean isCommitted;
1876 
1877         /** {@hide} */
1878         public long updatedMillis;
1879 
1880         /** {@hide} */
1881         @UnsupportedAppUsage
SessionInfo()1882         public SessionInfo() {
1883         }
1884 
1885         /** {@hide} */
SessionInfo(Parcel source)1886         public SessionInfo(Parcel source) {
1887             sessionId = source.readInt();
1888             userId = source.readInt();
1889             installerPackageName = source.readString();
1890             resolvedBaseCodePath = source.readString();
1891             progress = source.readFloat();
1892             sealed = source.readInt() != 0;
1893             active = source.readInt() != 0;
1894 
1895             mode = source.readInt();
1896             installReason = source.readInt();
1897             sizeBytes = source.readLong();
1898             appPackageName = source.readString();
1899             appIcon = source.readParcelable(null);
1900             appLabel = source.readString();
1901 
1902             installLocation = source.readInt();
1903             originatingUri = source.readParcelable(null);
1904             originatingUid = source.readInt();
1905             referrerUri = source.readParcelable(null);
1906             grantedRuntimePermissions = source.readStringArray();
1907             whitelistedRestrictedPermissions = source.createStringArrayList();
1908 
1909             installFlags = source.readInt();
1910             isMultiPackage = source.readBoolean();
1911             isStaged = source.readBoolean();
1912             parentSessionId = source.readInt();
1913             childSessionIds = source.createIntArray();
1914             if (childSessionIds == null) {
1915                 childSessionIds = NO_SESSIONS;
1916             }
1917             isStagedSessionApplied = source.readBoolean();
1918             isStagedSessionReady = source.readBoolean();
1919             isStagedSessionFailed = source.readBoolean();
1920             mStagedSessionErrorCode = source.readInt();
1921             mStagedSessionErrorMessage = source.readString();
1922             isCommitted = source.readBoolean();
1923         }
1924 
1925         /**
1926          * Return the ID for this session.
1927          */
getSessionId()1928         public int getSessionId() {
1929             return sessionId;
1930         }
1931 
1932         /**
1933          * Return the user associated with this session.
1934          */
getUser()1935         public @NonNull UserHandle getUser() {
1936             return new UserHandle(userId);
1937         }
1938 
1939         /**
1940          * Return the package name of the app that owns this session.
1941          */
getInstallerPackageName()1942         public @Nullable String getInstallerPackageName() {
1943             return installerPackageName;
1944         }
1945 
1946         /**
1947          * Return current overall progress of this session, between 0 and 1.
1948          * <p>
1949          * Note that this progress may not directly correspond to the value
1950          * reported by
1951          * {@link PackageInstaller.Session#setStagingProgress(float)}, as the
1952          * system may carve out a portion of the overall progress to represent
1953          * its own internal installation work.
1954          */
getProgress()1955         public float getProgress() {
1956             return progress;
1957         }
1958 
1959         /**
1960          * Return if this session is currently active.
1961          * <p>
1962          * A session is considered active whenever there is ongoing forward
1963          * progress being made, such as the installer holding an open
1964          * {@link Session} instance while streaming data into place, or the
1965          * system optimizing code as the result of
1966          * {@link Session#commit(IntentSender)}.
1967          * <p>
1968          * If the installer closes the {@link Session} without committing, the
1969          * session is considered inactive until the installer opens the session
1970          * again.
1971          */
isActive()1972         public boolean isActive() {
1973             return active;
1974         }
1975 
1976         /**
1977          * Return if this session is sealed.
1978          * <p>
1979          * Once sealed, no further changes may be made to the session. A session
1980          * is sealed the moment {@link Session#commit(IntentSender)} is called.
1981          */
isSealed()1982         public boolean isSealed() {
1983             return sealed;
1984         }
1985 
1986         /**
1987          * Return the reason for installing this package.
1988          *
1989          * @return The install reason.
1990          */
getInstallReason()1991         public @InstallReason int getInstallReason() {
1992             return installReason;
1993         }
1994 
1995         /** {@hide} */
1996         @Deprecated
isOpen()1997         public boolean isOpen() {
1998             return isActive();
1999         }
2000 
2001         /**
2002          * Return the package name this session is working with. May be {@code null}
2003          * if unknown.
2004          */
getAppPackageName()2005         public @Nullable String getAppPackageName() {
2006             return appPackageName;
2007         }
2008 
2009         /**
2010          * Return an icon representing the app being installed. May be {@code null}
2011          * if unavailable.
2012          */
getAppIcon()2013         public @Nullable Bitmap getAppIcon() {
2014             if (appIcon == null) {
2015                 // Icon may have been omitted for calls that return bulk session
2016                 // lists, so try fetching the specific icon.
2017                 try {
2018                     final SessionInfo info = AppGlobals.getPackageManager().getPackageInstaller()
2019                             .getSessionInfo(sessionId);
2020                     appIcon = (info != null) ? info.appIcon : null;
2021                 } catch (RemoteException e) {
2022                     throw e.rethrowFromSystemServer();
2023                 }
2024             }
2025             return appIcon;
2026         }
2027 
2028         /**
2029          * Return a label representing the app being installed. May be {@code null}
2030          * if unavailable.
2031          */
getAppLabel()2032         public @Nullable CharSequence getAppLabel() {
2033             return appLabel;
2034         }
2035 
2036         /**
2037          * Return an Intent that can be started to view details about this install
2038          * session. This may surface actions such as pause, resume, or cancel.
2039          * <p>
2040          * In some cases, a matching Activity may not exist, so ensure you safeguard
2041          * against this.
2042          *
2043          * @see PackageInstaller#ACTION_SESSION_DETAILS
2044          */
createDetailsIntent()2045         public @Nullable Intent createDetailsIntent() {
2046             final Intent intent = new Intent(PackageInstaller.ACTION_SESSION_DETAILS);
2047             intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
2048             intent.setPackage(installerPackageName);
2049             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2050             return intent;
2051         }
2052 
2053         /**
2054          * Get the mode of the session as set in the constructor of the {@link SessionParams}.
2055          *
2056          * @return One of {@link SessionParams#MODE_FULL_INSTALL}
2057          *         or {@link SessionParams#MODE_INHERIT_EXISTING}
2058          */
getMode()2059         public int getMode() {
2060             return mode;
2061         }
2062 
2063         /**
2064          * Get the value set in {@link SessionParams#setInstallLocation(int)}.
2065          */
getInstallLocation()2066         public int getInstallLocation() {
2067             return installLocation;
2068         }
2069 
2070         /**
2071          * Get the value as set in {@link SessionParams#setSize(long)}.
2072          *
2073          * <p>The value is a hint and does not have to match the actual size.
2074          */
getSize()2075         public long getSize() {
2076             return sizeBytes;
2077         }
2078 
2079         /**
2080          * Get the value set in {@link SessionParams#setOriginatingUri(Uri)}.
2081          */
getOriginatingUri()2082         public @Nullable Uri getOriginatingUri() {
2083             return originatingUri;
2084         }
2085 
2086         /**
2087          * Get the value set in {@link SessionParams#setOriginatingUid(int)}.
2088          */
getOriginatingUid()2089         public int getOriginatingUid() {
2090             return originatingUid;
2091         }
2092 
2093         /**
2094          * Get the value set in {@link SessionParams#setReferrerUri(Uri)}
2095          */
getReferrerUri()2096         public @Nullable Uri getReferrerUri() {
2097             return referrerUri;
2098         }
2099 
2100         /**
2101          * Get the value set in {@link SessionParams#setGrantedRuntimePermissions(String[])}.
2102          *
2103          * @hide
2104          */
2105         @SystemApi
getGrantedRuntimePermissions()2106         public @Nullable String[] getGrantedRuntimePermissions() {
2107             return grantedRuntimePermissions;
2108         }
2109 
2110         /**
2111          * Get the value set in {@link SessionParams#setWhitelistedRestrictedPermissions(Set)}.
2112          * Note that if all permissions are whitelisted this method returns {@link
2113          * SessionParams#RESTRICTED_PERMISSIONS_ALL}.
2114          *
2115          * @hide
2116          */
2117         @TestApi
2118         @SystemApi
getWhitelistedRestrictedPermissions()2119         public @NonNull Set<String> getWhitelistedRestrictedPermissions() {
2120             if ((installFlags & PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS) != 0) {
2121                 return SessionParams.RESTRICTED_PERMISSIONS_ALL;
2122             }
2123             if (whitelistedRestrictedPermissions != null) {
2124                 return new ArraySet<>(whitelistedRestrictedPermissions);
2125             }
2126             return Collections.emptySet();
2127         }
2128 
2129         /**
2130          * Get the value set in {@link SessionParams#setAllowDowngrade(boolean)}.
2131          *
2132          * @deprecated use {@link #getRequestDowngrade()}.
2133          * @hide
2134          */
2135         @SystemApi
2136         @Deprecated
getAllowDowngrade()2137         public boolean getAllowDowngrade() {
2138             return getRequestDowngrade();
2139         }
2140 
2141         /**
2142          * Get the value set in {@link SessionParams#setRequestDowngrade(boolean)}.
2143          *
2144          * @hide
2145          */
2146         @SystemApi
getRequestDowngrade()2147         public boolean getRequestDowngrade() {
2148             return (installFlags & PackageManager.INSTALL_REQUEST_DOWNGRADE) != 0;
2149         }
2150 
2151         /**
2152          * Get the value set in {@link SessionParams#setDontKillApp(boolean)}.
2153          *
2154          * @hide
2155          */
2156         @SystemApi
getDontKillApp()2157         public boolean getDontKillApp() {
2158             return (installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0;
2159         }
2160 
2161         /**
2162          * If {@link SessionParams#setInstallAsInstantApp(boolean)} was called with {@code true},
2163          * return true. If it was called with {@code false} or if it was not called return false.
2164          *
2165          * @hide
2166          *
2167          * @see #getInstallAsFullApp
2168          */
2169         @SystemApi
getInstallAsInstantApp(boolean isInstantApp)2170         public boolean getInstallAsInstantApp(boolean isInstantApp) {
2171             return (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
2172         }
2173 
2174         /**
2175          * If {@link SessionParams#setInstallAsInstantApp(boolean)} was called with {@code false},
2176          * return true. If it was called with {@code true} or if it was not called return false.
2177          *
2178          * @hide
2179          *
2180          * @see #getInstallAsInstantApp
2181          */
2182         @SystemApi
getInstallAsFullApp(boolean isInstantApp)2183         public boolean getInstallAsFullApp(boolean isInstantApp) {
2184             return (installFlags & PackageManager.INSTALL_FULL_APP) != 0;
2185         }
2186 
2187         /**
2188          * Get if {@link SessionParams#setInstallAsVirtualPreload()} was called.
2189          *
2190          * @hide
2191          */
2192         @SystemApi
getInstallAsVirtualPreload()2193         public boolean getInstallAsVirtualPreload() {
2194             return (installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0;
2195         }
2196 
2197         /**
2198          * Return whether rollback is enabled or disabled for the given upgrade.
2199          *
2200          * @hide
2201          */
2202         @SystemApi
getEnableRollback()2203         public boolean getEnableRollback() {
2204             return (installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0;
2205         }
2206 
2207         /**
2208          * Get the value set in {@link SessionParams#setAllocateAggressive(boolean)}.
2209          *
2210          * @hide
2211          */
2212         @SystemApi
getAllocateAggressive()2213         public boolean getAllocateAggressive() {
2214             return (installFlags & PackageManager.INSTALL_ALLOCATE_AGGRESSIVE) != 0;
2215         }
2216 
2217 
2218         /** {@hide} */
2219         @Deprecated
getDetailsIntent()2220         public @Nullable Intent getDetailsIntent() {
2221             return createDetailsIntent();
2222         }
2223 
2224         /**
2225          * Returns true if this session is a multi-package session containing references to other
2226          * sessions.
2227          */
isMultiPackage()2228         public boolean isMultiPackage() {
2229             return isMultiPackage;
2230         }
2231 
2232         /**
2233          * Returns true if this session is a staged session.
2234          */
isStaged()2235         public boolean isStaged() {
2236             return isStaged;
2237         }
2238 
2239         /**
2240          * Returns {@code true} if this session is an active staged session.
2241          *
2242          * We consider a session active if it has been committed and it is either pending
2243          * verification, or will be applied at next reboot.
2244          *
2245          * <p>Staged session is active iff:
2246          * <ul>
2247          *     <li>It is committed, i.e. {@link SessionInfo#isCommitted()} is {@code true}, and
2248          *     <li>it is not applied, i.e. {@link SessionInfo#isStagedSessionApplied()} is {@code
2249          *     false}, and
2250          *     <li>it is not failed, i.e. {@link SessionInfo#isStagedSessionFailed()} is
2251          *     {@code false}.
2252          * </ul>
2253          *
2254          * <p>In case of a multi-package session, reasoning above is applied to the parent session,
2255          * since that is the one that should have been {@link Session#commit committed}.
2256          */
isStagedSessionActive()2257         public boolean isStagedSessionActive() {
2258             return isStaged && isCommitted && !isStagedSessionApplied && !isStagedSessionFailed
2259                     && !hasParentSessionId();
2260         }
2261 
2262         /**
2263          * Returns the parent multi-package session ID if this session belongs to one,
2264          * {@link #INVALID_ID} otherwise.
2265          */
getParentSessionId()2266         public int getParentSessionId() {
2267             return parentSessionId;
2268         }
2269 
2270         /**
2271          * Returns true if session has a valid parent session, otherwise false.
2272          */
hasParentSessionId()2273         public boolean hasParentSessionId() {
2274             return parentSessionId != INVALID_ID;
2275         }
2276 
2277         /**
2278          * Returns the set of session IDs that will be committed when this session is commited if
2279          * this session is a multi-package session.
2280          */
2281         @NonNull
getChildSessionIds()2282         public int[] getChildSessionIds() {
2283             return childSessionIds;
2284         }
2285 
checkSessionIsStaged()2286         private void checkSessionIsStaged() {
2287             if (!isStaged) {
2288                 throw new IllegalStateException("Session is not marked as staged.");
2289             }
2290         }
2291 
2292         /**
2293          * Whether the staged session has been applied successfully, meaning that all of its
2294          * packages have been activated and no further action is required.
2295          * Only meaningful if {@code isStaged} is true.
2296          */
isStagedSessionApplied()2297         public boolean isStagedSessionApplied() {
2298             checkSessionIsStaged();
2299             return isStagedSessionApplied;
2300         }
2301 
2302         /**
2303          * Whether the staged session is ready to be applied at next reboot. Only meaningful if
2304          * {@code isStaged} is true.
2305          */
isStagedSessionReady()2306         public boolean isStagedSessionReady() {
2307             checkSessionIsStaged();
2308             return isStagedSessionReady;
2309         }
2310 
2311         /**
2312          * Whether something went wrong and the staged session is declared as failed, meaning that
2313          * it will be ignored at next reboot. Only meaningful if {@code isStaged} is true.
2314          */
isStagedSessionFailed()2315         public boolean isStagedSessionFailed() {
2316             checkSessionIsStaged();
2317             return isStagedSessionFailed;
2318         }
2319 
2320         /**
2321          * If something went wrong with a staged session, clients can check this error code to
2322          * understand which kind of failure happened. Only meaningful if {@code isStaged} is true.
2323          */
getStagedSessionErrorCode()2324         public @StagedSessionErrorCode int getStagedSessionErrorCode() {
2325             checkSessionIsStaged();
2326             return mStagedSessionErrorCode;
2327         }
2328 
2329         /**
2330          * Text description of the error code returned by {@code getStagedSessionErrorCode}, or
2331          * empty string if no error was encountered.
2332          */
getStagedSessionErrorMessage()2333         public @NonNull String getStagedSessionErrorMessage() {
2334             checkSessionIsStaged();
2335             return mStagedSessionErrorMessage;
2336         }
2337 
2338         /** {@hide} */
setStagedSessionErrorCode(@tagedSessionErrorCode int errorCode, String errorMessage)2339         public void setStagedSessionErrorCode(@StagedSessionErrorCode int errorCode,
2340                                               String errorMessage) {
2341             mStagedSessionErrorCode = errorCode;
2342             mStagedSessionErrorMessage = errorMessage;
2343         }
2344 
2345         /**
2346          * Returns {@code true} if {@link Session#commit(IntentSender)}} was called for this
2347          * session.
2348          */
isCommitted()2349         public boolean isCommitted() {
2350             return isCommitted;
2351         }
2352 
2353         /**
2354          * The timestamp of the last update that occurred to the session, including changing of
2355          * states in case of staged sessions.
2356          */
2357         @CurrentTimeMillisLong
getUpdatedMillis()2358         public long getUpdatedMillis() {
2359             return updatedMillis;
2360         }
2361 
2362         @Override
describeContents()2363         public int describeContents() {
2364             return 0;
2365         }
2366 
2367         @Override
writeToParcel(Parcel dest, int flags)2368         public void writeToParcel(Parcel dest, int flags) {
2369             dest.writeInt(sessionId);
2370             dest.writeInt(userId);
2371             dest.writeString(installerPackageName);
2372             dest.writeString(resolvedBaseCodePath);
2373             dest.writeFloat(progress);
2374             dest.writeInt(sealed ? 1 : 0);
2375             dest.writeInt(active ? 1 : 0);
2376 
2377             dest.writeInt(mode);
2378             dest.writeInt(installReason);
2379             dest.writeLong(sizeBytes);
2380             dest.writeString(appPackageName);
2381             dest.writeParcelable(appIcon, flags);
2382             dest.writeString(appLabel != null ? appLabel.toString() : null);
2383 
2384             dest.writeInt(installLocation);
2385             dest.writeParcelable(originatingUri, flags);
2386             dest.writeInt(originatingUid);
2387             dest.writeParcelable(referrerUri, flags);
2388             dest.writeStringArray(grantedRuntimePermissions);
2389             dest.writeStringList(whitelistedRestrictedPermissions);
2390             dest.writeInt(installFlags);
2391             dest.writeBoolean(isMultiPackage);
2392             dest.writeBoolean(isStaged);
2393             dest.writeInt(parentSessionId);
2394             dest.writeIntArray(childSessionIds);
2395             dest.writeBoolean(isStagedSessionApplied);
2396             dest.writeBoolean(isStagedSessionReady);
2397             dest.writeBoolean(isStagedSessionFailed);
2398             dest.writeInt(mStagedSessionErrorCode);
2399             dest.writeString(mStagedSessionErrorMessage);
2400             dest.writeBoolean(isCommitted);
2401         }
2402 
2403         public static final Parcelable.Creator<SessionInfo>
2404                 CREATOR = new Parcelable.Creator<SessionInfo>() {
2405                     @Override
2406                     public SessionInfo createFromParcel(Parcel p) {
2407                         return new SessionInfo(p);
2408                     }
2409 
2410                     @Override
2411                     public SessionInfo[] newArray(int size) {
2412                         return new SessionInfo[size];
2413                     }
2414                 };
2415     }
2416 }
2417