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.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.RequiresPermission;
23 import android.annotation.SdkConstant;
24 import android.annotation.SdkConstant.SdkConstantType;
25 import android.annotation.SystemApi;
26 import android.app.ActivityManager;
27 import android.app.AppGlobals;
28 import android.content.Intent;
29 import android.content.IntentSender;
30 import android.content.pm.PackageManager.DeleteFlags;
31 import android.content.pm.PackageManager.InstallReason;
32 import android.graphics.Bitmap;
33 import android.net.Uri;
34 import android.os.FileBridge;
35 import android.os.Handler;
36 import android.os.Looper;
37 import android.os.Message;
38 import android.os.Parcel;
39 import android.os.ParcelFileDescriptor;
40 import android.os.Parcelable;
41 import android.os.ParcelableException;
42 import android.os.RemoteException;
43 import android.os.SystemProperties;
44 import android.system.ErrnoException;
45 import android.system.Os;
46 import android.util.ExceptionUtils;
47 
48 import com.android.internal.util.IndentingPrintWriter;
49 import com.android.internal.util.Preconditions;
50 
51 import java.io.Closeable;
52 import java.io.IOException;
53 import java.io.InputStream;
54 import java.io.OutputStream;
55 import java.security.MessageDigest;
56 import java.util.ArrayList;
57 import java.util.Iterator;
58 import java.util.List;
59 
60 /**
61  * Offers the ability to install, upgrade, and remove applications on the
62  * device. This includes support for apps packaged either as a single
63  * "monolithic" APK, or apps packaged as multiple "split" APKs.
64  * <p>
65  * An app is delivered for installation through a
66  * {@link PackageInstaller.Session}, which any app can create. Once the session
67  * is created, the installer can stream one or more APKs into place until it
68  * decides to either commit or destroy the session. Committing may require user
69  * intervention to complete the installation.
70  * <p>
71  * Sessions can install brand new apps, upgrade existing apps, or add new splits
72  * into an existing app.
73  * <p>
74  * Apps packaged as multiple split APKs always consist of a single "base" APK
75  * (with a {@code null} split name) and zero or more "split" APKs (with unique
76  * split names). Any subset of these APKs can be installed together, as long as
77  * the following constraints are met:
78  * <ul>
79  * <li>All APKs must have the exact same package name, version code, and signing
80  * certificates.
81  * <li>All APKs must have unique split names.
82  * <li>All installations must contain a single base APK.
83  * </ul>
84  * <p>
85  * The ApiDemos project contains examples of using this API:
86  * <code>ApiDemos/src/com/example/android/apis/content/InstallApk*.java</code>.
87  */
88 public class PackageInstaller {
89     private static final String TAG = "PackageInstaller";
90 
91     /** {@hide} */
92     public static final boolean ENABLE_REVOCABLE_FD =
93             SystemProperties.getBoolean("fw.revocable_fd", false);
94 
95     /**
96      * Activity Action: Show details about a particular install session. This
97      * may surface actions such as pause, resume, or cancel.
98      * <p>
99      * This should always be scoped to the installer package that owns the
100      * session. Clients should use {@link SessionInfo#createDetailsIntent()} to
101      * build this intent correctly.
102      * <p>
103      * In some cases, a matching Activity may not exist, so ensure you safeguard
104      * against this.
105      * <p>
106      * The session to show details for is defined in {@link #EXTRA_SESSION_ID}.
107      */
108     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
109     public static final String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS";
110 
111     /**
112      * Broadcast Action: Explicit broadcast sent to the last known default launcher when a session
113      * for a new install is committed. For managed profile, this is sent to the default launcher
114      * of the primary profile.
115      * <p>
116      * The associated session is defined in {@link #EXTRA_SESSION} and the user for which this
117      * session was created in {@link Intent#EXTRA_USER}.
118      */
119     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
120     public static final String ACTION_SESSION_COMMITTED =
121             "android.content.pm.action.SESSION_COMMITTED";
122 
123     /** {@hide} */
124     public static final String
125             ACTION_CONFIRM_PERMISSIONS = "android.content.pm.action.CONFIRM_PERMISSIONS";
126 
127     /**
128      * An integer session ID that an operation is working with.
129      *
130      * @see Intent#getIntExtra(String, int)
131      */
132     public static final String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID";
133 
134     /**
135      * {@link SessionInfo} that an operation is working with.
136      *
137      * @see Intent#getParcelableExtra(String)
138      */
139     public static final String EXTRA_SESSION = "android.content.pm.extra.SESSION";
140 
141     /**
142      * Package name that an operation is working with.
143      *
144      * @see Intent#getStringExtra(String)
145      */
146     public static final String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME";
147 
148     /**
149      * Current status of an operation. Will be one of
150      * {@link #STATUS_PENDING_USER_ACTION}, {@link #STATUS_SUCCESS},
151      * {@link #STATUS_FAILURE}, {@link #STATUS_FAILURE_ABORTED},
152      * {@link #STATUS_FAILURE_BLOCKED}, {@link #STATUS_FAILURE_CONFLICT},
153      * {@link #STATUS_FAILURE_INCOMPATIBLE}, {@link #STATUS_FAILURE_INVALID}, or
154      * {@link #STATUS_FAILURE_STORAGE}.
155      * <p>
156      * More information about a status may be available through additional
157      * extras; see the individual status documentation for details.
158      *
159      * @see Intent#getIntExtra(String, int)
160      */
161     public static final String EXTRA_STATUS = "android.content.pm.extra.STATUS";
162 
163     /**
164      * Detailed string representation of the status, including raw details that
165      * are useful for debugging.
166      *
167      * @see Intent#getStringExtra(String)
168      */
169     public static final String EXTRA_STATUS_MESSAGE = "android.content.pm.extra.STATUS_MESSAGE";
170 
171     /**
172      * Another package name relevant to a status. This is typically the package
173      * responsible for causing an operation failure.
174      *
175      * @see Intent#getStringExtra(String)
176      */
177     public static final String
178             EXTRA_OTHER_PACKAGE_NAME = "android.content.pm.extra.OTHER_PACKAGE_NAME";
179 
180     /**
181      * Storage path relevant to a status.
182      *
183      * @see Intent#getStringExtra(String)
184      */
185     public static final String EXTRA_STORAGE_PATH = "android.content.pm.extra.STORAGE_PATH";
186 
187     /** {@hide} */
188     @Deprecated
189     public static final String EXTRA_PACKAGE_NAMES = "android.content.pm.extra.PACKAGE_NAMES";
190 
191     /** {@hide} */
192     public static final String EXTRA_LEGACY_STATUS = "android.content.pm.extra.LEGACY_STATUS";
193     /** {@hide} */
194     public static final String EXTRA_LEGACY_BUNDLE = "android.content.pm.extra.LEGACY_BUNDLE";
195     /** {@hide} */
196     public static final String EXTRA_CALLBACK = "android.content.pm.extra.CALLBACK";
197 
198     /**
199      * User action is currently required to proceed. You can launch the intent
200      * activity described by {@link Intent#EXTRA_INTENT} to involve the user and
201      * continue.
202      * <p>
203      * You may choose to immediately launch the intent if the user is actively
204      * using your app. Otherwise, you should use a notification to guide the
205      * user back into your app before launching.
206      *
207      * @see Intent#getParcelableExtra(String)
208      */
209     public static final int STATUS_PENDING_USER_ACTION = -1;
210 
211     /**
212      * The operation succeeded.
213      */
214     public static final int STATUS_SUCCESS = 0;
215 
216     /**
217      * The operation failed in a generic way. The system will always try to
218      * provide a more specific failure reason, but in some rare cases this may
219      * be delivered.
220      *
221      * @see #EXTRA_STATUS_MESSAGE
222      */
223     public static final int STATUS_FAILURE = 1;
224 
225     /**
226      * The operation failed because it was blocked. For example, a device policy
227      * may be blocking the operation, a package verifier may have blocked the
228      * operation, or the app may be required for core system operation.
229      * <p>
230      * The result may also contain {@link #EXTRA_OTHER_PACKAGE_NAME} with the
231      * specific package blocking the install.
232      *
233      * @see #EXTRA_STATUS_MESSAGE
234      * @see #EXTRA_OTHER_PACKAGE_NAME
235      */
236     public static final int STATUS_FAILURE_BLOCKED = 2;
237 
238     /**
239      * The operation failed because it was actively aborted. For example, the
240      * user actively declined requested permissions, or the session was
241      * abandoned.
242      *
243      * @see #EXTRA_STATUS_MESSAGE
244      */
245     public static final int STATUS_FAILURE_ABORTED = 3;
246 
247     /**
248      * The operation failed because one or more of the APKs was invalid. For
249      * example, they might be malformed, corrupt, incorrectly signed,
250      * mismatched, etc.
251      *
252      * @see #EXTRA_STATUS_MESSAGE
253      */
254     public static final int STATUS_FAILURE_INVALID = 4;
255 
256     /**
257      * The operation failed because it conflicts (or is inconsistent with) with
258      * another package already installed on the device. For example, an existing
259      * permission, incompatible certificates, etc. The user may be able to
260      * uninstall another app to fix the issue.
261      * <p>
262      * The result may also contain {@link #EXTRA_OTHER_PACKAGE_NAME} with the
263      * specific package identified as the cause of the conflict.
264      *
265      * @see #EXTRA_STATUS_MESSAGE
266      * @see #EXTRA_OTHER_PACKAGE_NAME
267      */
268     public static final int STATUS_FAILURE_CONFLICT = 5;
269 
270     /**
271      * The operation failed because of storage issues. For example, the device
272      * may be running low on space, or external media may be unavailable. The
273      * user may be able to help free space or insert different external media.
274      * <p>
275      * The result may also contain {@link #EXTRA_STORAGE_PATH} with the path to
276      * the storage device that caused the failure.
277      *
278      * @see #EXTRA_STATUS_MESSAGE
279      * @see #EXTRA_STORAGE_PATH
280      */
281     public static final int STATUS_FAILURE_STORAGE = 6;
282 
283     /**
284      * The operation failed because it is fundamentally incompatible with this
285      * device. For example, the app may require a hardware feature that doesn't
286      * exist, it may be missing native code for the ABIs supported by the
287      * device, or it requires a newer SDK version, etc.
288      *
289      * @see #EXTRA_STATUS_MESSAGE
290      */
291     public static final int STATUS_FAILURE_INCOMPATIBLE = 7;
292 
293     private final IPackageInstaller mInstaller;
294     private final int mUserId;
295     private final String mInstallerPackageName;
296 
297     private final ArrayList<SessionCallbackDelegate> mDelegates = new ArrayList<>();
298 
299     /** {@hide} */
PackageInstaller(IPackageInstaller installer, String installerPackageName, int userId)300     public PackageInstaller(IPackageInstaller installer,
301             String installerPackageName, int userId) {
302         mInstaller = installer;
303         mInstallerPackageName = installerPackageName;
304         mUserId = userId;
305     }
306 
307     /**
308      * Create a new session using the given parameters, returning a unique ID
309      * that represents the session. Once created, the session can be opened
310      * multiple times across multiple device boots.
311      * <p>
312      * The system may automatically destroy sessions that have not been
313      * finalized (either committed or abandoned) within a reasonable period of
314      * time, typically on the order of a day.
315      *
316      * @throws IOException if parameters were unsatisfiable, such as lack of
317      *             disk space or unavailable media.
318      * @throws SecurityException when installation services are unavailable,
319      *             such as when called from a restricted user.
320      * @throws IllegalArgumentException when {@link SessionParams} is invalid.
321      * @return positive, non-zero unique ID that represents the created session.
322      *         This ID remains consistent across device reboots until the
323      *         session is finalized. IDs are not reused during a given boot.
324      */
createSession(@onNull SessionParams params)325     public int createSession(@NonNull SessionParams params) throws IOException {
326         try {
327             final String installerPackage;
328             if (params.installerPackageName == null) {
329                 installerPackage = mInstallerPackageName;
330             } else {
331                 installerPackage = params.installerPackageName;
332             }
333 
334             return mInstaller.createSession(params, installerPackage, mUserId);
335         } catch (RuntimeException e) {
336             ExceptionUtils.maybeUnwrapIOException(e);
337             throw e;
338         } catch (RemoteException e) {
339             throw e.rethrowFromSystemServer();
340         }
341     }
342 
343     /**
344      * Open an existing session to actively perform work. To succeed, the caller
345      * must be the owner of the install session.
346      *
347      * @throws IOException if parameters were unsatisfiable, such as lack of
348      *             disk space or unavailable media.
349      * @throws SecurityException when the caller does not own the session, or
350      *             the session is invalid.
351      */
openSession(int sessionId)352     public @NonNull Session openSession(int sessionId) throws IOException {
353         try {
354             return new Session(mInstaller.openSession(sessionId));
355         } catch (RuntimeException e) {
356             ExceptionUtils.maybeUnwrapIOException(e);
357             throw e;
358         } catch (RemoteException e) {
359             throw e.rethrowFromSystemServer();
360         }
361     }
362 
363     /**
364      * Update the icon representing the app being installed in a specific
365      * session. This should be roughly
366      * {@link ActivityManager#getLauncherLargeIconSize()} in both dimensions.
367      *
368      * @throws SecurityException when the caller does not own the session, or
369      *             the session is invalid.
370      */
updateSessionAppIcon(int sessionId, @Nullable Bitmap appIcon)371     public void updateSessionAppIcon(int sessionId, @Nullable Bitmap appIcon) {
372         try {
373             mInstaller.updateSessionAppIcon(sessionId, appIcon);
374         } catch (RemoteException e) {
375             throw e.rethrowFromSystemServer();
376         }
377     }
378 
379     /**
380      * Update the label representing the app being installed in a specific
381      * session.
382      *
383      * @throws SecurityException when the caller does not own the session, or
384      *             the session is invalid.
385      */
updateSessionAppLabel(int sessionId, @Nullable CharSequence appLabel)386     public void updateSessionAppLabel(int sessionId, @Nullable CharSequence appLabel) {
387         try {
388             final String val = (appLabel != null) ? appLabel.toString() : null;
389             mInstaller.updateSessionAppLabel(sessionId, val);
390         } catch (RemoteException e) {
391             throw e.rethrowFromSystemServer();
392         }
393     }
394 
395     /**
396      * Completely abandon the given session, destroying all staged data and
397      * rendering it invalid. Abandoned sessions will be reported to
398      * {@link SessionCallback} listeners as failures. This is equivalent to
399      * opening the session and calling {@link Session#abandon()}.
400      *
401      * @throws SecurityException when the caller does not own the session, or
402      *             the session is invalid.
403      */
abandonSession(int sessionId)404     public void abandonSession(int sessionId) {
405         try {
406             mInstaller.abandonSession(sessionId);
407         } catch (RemoteException e) {
408             throw e.rethrowFromSystemServer();
409         }
410     }
411 
412     /**
413      * Return details for a specific session. No special permissions are
414      * required to retrieve these details.
415      *
416      * @return details for the requested session, or {@code null} if the session
417      *         does not exist.
418      */
getSessionInfo(int sessionId)419     public @Nullable SessionInfo getSessionInfo(int sessionId) {
420         try {
421             return mInstaller.getSessionInfo(sessionId);
422         } catch (RemoteException e) {
423             throw e.rethrowFromSystemServer();
424         }
425     }
426 
427     /**
428      * Return list of all known install sessions, regardless of the installer.
429      */
getAllSessions()430     public @NonNull List<SessionInfo> getAllSessions() {
431         try {
432             return mInstaller.getAllSessions(mUserId).getList();
433         } catch (RemoteException e) {
434             throw e.rethrowFromSystemServer();
435         }
436     }
437 
438     /**
439      * Return list of all known install sessions owned by the calling app.
440      */
getMySessions()441     public @NonNull List<SessionInfo> getMySessions() {
442         try {
443             return mInstaller.getMySessions(mInstallerPackageName, mUserId).getList();
444         } catch (RemoteException e) {
445             throw e.rethrowFromSystemServer();
446         }
447     }
448 
449     /**
450      * Uninstall the given package, removing it completely from the device. This
451      * method is available to:
452      * <ul>
453      * <li>the current "installer of record" for the package
454      * <li>the device owner
455      * <li>the affiliated profile owner
456      * </ul>
457      *
458      * @param packageName The package to uninstall.
459      * @param statusReceiver Where to deliver the result.
460      *
461      * @see android.app.admin.DevicePolicyManager
462      */
463     @RequiresPermission(anyOf = {
464             Manifest.permission.DELETE_PACKAGES,
465             Manifest.permission.REQUEST_DELETE_PACKAGES})
uninstall(@onNull String packageName, @NonNull IntentSender statusReceiver)466     public void uninstall(@NonNull String packageName, @NonNull IntentSender statusReceiver) {
467         uninstall(packageName, 0 /*flags*/, statusReceiver);
468     }
469 
470     /**
471      * Uninstall the given package, removing it completely from the device. This
472      * method is only available to the current "installer of record" for the
473      * package.
474      *
475      * @param packageName The package to uninstall.
476      * @param flags Flags for uninstall.
477      * @param statusReceiver Where to deliver the result.
478      *
479      * @hide
480      */
uninstall(@onNull String packageName, @DeleteFlags int flags, @NonNull IntentSender statusReceiver)481     public void uninstall(@NonNull String packageName, @DeleteFlags int flags,
482             @NonNull IntentSender statusReceiver) {
483         uninstall(new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST),
484                 flags, statusReceiver);
485     }
486 
487     /**
488      * Uninstall the given package with a specific version code, removing it
489      * completely from the device. If the version code of the package
490      * does not match the one passed in the versioned package argument this
491      * method is a no-op. Use {@link PackageManager#VERSION_CODE_HIGHEST} to
492      * uninstall the latest version of the package.
493      * <p>
494      * This method is available to:
495      * <ul>
496      * <li>the current "installer of record" for the package
497      * <li>the device owner
498      * <li>the affiliated profile owner
499      * </ul>
500      *
501      * @param versionedPackage The versioned package to uninstall.
502      * @param statusReceiver Where to deliver the result.
503      *
504      * @see android.app.admin.DevicePolicyManager
505      */
506     @RequiresPermission(anyOf = {
507             Manifest.permission.DELETE_PACKAGES,
508             Manifest.permission.REQUEST_DELETE_PACKAGES})
uninstall(@onNull VersionedPackage versionedPackage, @NonNull IntentSender statusReceiver)509     public void uninstall(@NonNull VersionedPackage versionedPackage,
510             @NonNull IntentSender statusReceiver) {
511         uninstall(versionedPackage, 0 /*flags*/, statusReceiver);
512     }
513 
514     /**
515      * Uninstall the given package with a specific version code, removing it
516      * completely from the device. This method is only available to the current
517      * "installer of record" for the package. If the version code of the package
518      * does not match the one passed in the versioned package argument this
519      * method is a no-op. Use {@link PackageManager#VERSION_CODE_HIGHEST} to
520      * uninstall the latest version of the package.
521      *
522      * @param versionedPackage The versioned package to uninstall.
523      * @param flags Flags for uninstall.
524      * @param statusReceiver Where to deliver the result.
525      *
526      * @hide
527      */
528     @RequiresPermission(anyOf = {
529             Manifest.permission.DELETE_PACKAGES,
530             Manifest.permission.REQUEST_DELETE_PACKAGES})
uninstall(@onNull VersionedPackage versionedPackage, @DeleteFlags int flags, @NonNull IntentSender statusReceiver)531     public void uninstall(@NonNull VersionedPackage versionedPackage, @DeleteFlags int flags,
532             @NonNull IntentSender statusReceiver) {
533         Preconditions.checkNotNull(versionedPackage, "versionedPackage cannot be null");
534         try {
535             mInstaller.uninstall(versionedPackage, mInstallerPackageName,
536                     flags, statusReceiver, mUserId);
537         } catch (RemoteException e) {
538             throw e.rethrowFromSystemServer();
539         }
540     }
541 
542     /** {@hide} */
543     @SystemApi
544     @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES)
setPermissionsResult(int sessionId, boolean accepted)545     public void setPermissionsResult(int sessionId, boolean accepted) {
546         try {
547             mInstaller.setPermissionsResult(sessionId, accepted);
548         } catch (RemoteException e) {
549             throw e.rethrowFromSystemServer();
550         }
551     }
552 
553     /**
554      * Events for observing session lifecycle.
555      * <p>
556      * A typical session lifecycle looks like this:
557      * <ul>
558      * <li>An installer creates a session to indicate pending app delivery. All
559      * install details are available at this point.
560      * <li>The installer opens the session to deliver APK data. Note that a
561      * session may be opened and closed multiple times as network connectivity
562      * changes. The installer may deliver periodic progress updates.
563      * <li>The installer commits or abandons the session, resulting in the
564      * session being finished.
565      * </ul>
566      */
567     public static abstract class SessionCallback {
568         /**
569          * New session has been created. Details about the session can be
570          * obtained from {@link PackageInstaller#getSessionInfo(int)}.
571          */
onCreated(int sessionId)572         public abstract void onCreated(int sessionId);
573 
574         /**
575          * Badging details for an existing session has changed. For example, the
576          * app icon or label has been updated.
577          */
onBadgingChanged(int sessionId)578         public abstract void onBadgingChanged(int sessionId);
579 
580         /**
581          * Active state for session has been changed.
582          * <p>
583          * A session is considered active whenever there is ongoing forward
584          * progress being made, such as the installer holding an open
585          * {@link Session} instance while streaming data into place, or the
586          * system optimizing code as the result of
587          * {@link Session#commit(IntentSender)}.
588          * <p>
589          * If the installer closes the {@link Session} without committing, the
590          * session is considered inactive until the installer opens the session
591          * again.
592          */
onActiveChanged(int sessionId, boolean active)593         public abstract void onActiveChanged(int sessionId, boolean active);
594 
595         /**
596          * Progress for given session has been updated.
597          * <p>
598          * Note that this progress may not directly correspond to the value
599          * reported by
600          * {@link PackageInstaller.Session#setStagingProgress(float)}, as the
601          * system may carve out a portion of the overall progress to represent
602          * its own internal installation work.
603          */
onProgressChanged(int sessionId, float progress)604         public abstract void onProgressChanged(int sessionId, float progress);
605 
606         /**
607          * Session has completely finished, either with success or failure.
608          */
onFinished(int sessionId, boolean success)609         public abstract void onFinished(int sessionId, boolean success);
610     }
611 
612     /** {@hide} */
613     private static class SessionCallbackDelegate extends IPackageInstallerCallback.Stub implements
614             Handler.Callback {
615         private static final int MSG_SESSION_CREATED = 1;
616         private static final int MSG_SESSION_BADGING_CHANGED = 2;
617         private static final int MSG_SESSION_ACTIVE_CHANGED = 3;
618         private static final int MSG_SESSION_PROGRESS_CHANGED = 4;
619         private static final int MSG_SESSION_FINISHED = 5;
620 
621         final SessionCallback mCallback;
622         final Handler mHandler;
623 
SessionCallbackDelegate(SessionCallback callback, Looper looper)624         public SessionCallbackDelegate(SessionCallback callback, Looper looper) {
625             mCallback = callback;
626             mHandler = new Handler(looper, this);
627         }
628 
629         @Override
handleMessage(Message msg)630         public boolean handleMessage(Message msg) {
631             final int sessionId = msg.arg1;
632             switch (msg.what) {
633                 case MSG_SESSION_CREATED:
634                     mCallback.onCreated(sessionId);
635                     return true;
636                 case MSG_SESSION_BADGING_CHANGED:
637                     mCallback.onBadgingChanged(sessionId);
638                     return true;
639                 case MSG_SESSION_ACTIVE_CHANGED:
640                     final boolean active = msg.arg2 != 0;
641                     mCallback.onActiveChanged(sessionId, active);
642                     return true;
643                 case MSG_SESSION_PROGRESS_CHANGED:
644                     mCallback.onProgressChanged(sessionId, (float) msg.obj);
645                     return true;
646                 case MSG_SESSION_FINISHED:
647                     mCallback.onFinished(sessionId, msg.arg2 != 0);
648                     return true;
649             }
650             return false;
651         }
652 
653         @Override
onSessionCreated(int sessionId)654         public void onSessionCreated(int sessionId) {
655             mHandler.obtainMessage(MSG_SESSION_CREATED, sessionId, 0).sendToTarget();
656         }
657 
658         @Override
onSessionBadgingChanged(int sessionId)659         public void onSessionBadgingChanged(int sessionId) {
660             mHandler.obtainMessage(MSG_SESSION_BADGING_CHANGED, sessionId, 0).sendToTarget();
661         }
662 
663         @Override
onSessionActiveChanged(int sessionId, boolean active)664         public void onSessionActiveChanged(int sessionId, boolean active) {
665             mHandler.obtainMessage(MSG_SESSION_ACTIVE_CHANGED, sessionId, active ? 1 : 0)
666                     .sendToTarget();
667         }
668 
669         @Override
onSessionProgressChanged(int sessionId, float progress)670         public void onSessionProgressChanged(int sessionId, float progress) {
671             mHandler.obtainMessage(MSG_SESSION_PROGRESS_CHANGED, sessionId, 0, progress)
672                     .sendToTarget();
673         }
674 
675         @Override
onSessionFinished(int sessionId, boolean success)676         public void onSessionFinished(int sessionId, boolean success) {
677             mHandler.obtainMessage(MSG_SESSION_FINISHED, sessionId, success ? 1 : 0)
678                     .sendToTarget();
679         }
680     }
681 
682     /** {@hide} */
683     @Deprecated
addSessionCallback(@onNull SessionCallback callback)684     public void addSessionCallback(@NonNull SessionCallback callback) {
685         registerSessionCallback(callback);
686     }
687 
688     /**
689      * Register to watch for session lifecycle events. No special permissions
690      * are required to watch for these events.
691      */
registerSessionCallback(@onNull SessionCallback callback)692     public void registerSessionCallback(@NonNull SessionCallback callback) {
693         registerSessionCallback(callback, new Handler());
694     }
695 
696     /** {@hide} */
697     @Deprecated
addSessionCallback(@onNull SessionCallback callback, @NonNull Handler handler)698     public void addSessionCallback(@NonNull SessionCallback callback, @NonNull Handler handler) {
699         registerSessionCallback(callback, handler);
700     }
701 
702     /**
703      * Register to watch for session lifecycle events. No special permissions
704      * are required to watch for these events.
705      *
706      * @param handler to dispatch callback events through, otherwise uses
707      *            calling thread.
708      */
registerSessionCallback(@onNull SessionCallback callback, @NonNull Handler handler)709     public void registerSessionCallback(@NonNull SessionCallback callback, @NonNull Handler handler) {
710         synchronized (mDelegates) {
711             final SessionCallbackDelegate delegate = new SessionCallbackDelegate(callback,
712                     handler.getLooper());
713             try {
714                 mInstaller.registerCallback(delegate, mUserId);
715             } catch (RemoteException e) {
716                 throw e.rethrowFromSystemServer();
717             }
718             mDelegates.add(delegate);
719         }
720     }
721 
722     /** {@hide} */
723     @Deprecated
removeSessionCallback(@onNull SessionCallback callback)724     public void removeSessionCallback(@NonNull SessionCallback callback) {
725         unregisterSessionCallback(callback);
726     }
727 
728     /**
729      * Unregister a previously registered callback.
730      */
unregisterSessionCallback(@onNull SessionCallback callback)731     public void unregisterSessionCallback(@NonNull SessionCallback callback) {
732         synchronized (mDelegates) {
733             for (Iterator<SessionCallbackDelegate> i = mDelegates.iterator(); i.hasNext();) {
734                 final SessionCallbackDelegate delegate = i.next();
735                 if (delegate.mCallback == callback) {
736                     try {
737                         mInstaller.unregisterCallback(delegate);
738                     } catch (RemoteException e) {
739                         throw e.rethrowFromSystemServer();
740                     }
741                     i.remove();
742                 }
743             }
744         }
745     }
746 
747     /**
748      * An installation that is being actively staged. For an install to succeed,
749      * all existing and new packages must have identical package names, version
750      * codes, and signing certificates.
751      * <p>
752      * A session may contain any number of split packages. If the application
753      * does not yet exist, this session must include a base package.
754      * <p>
755      * If an APK included in this session is already defined by the existing
756      * installation (for example, the same split name), the APK in this session
757      * will replace the existing APK.
758      */
759     public static class Session implements Closeable {
760         private IPackageInstallerSession mSession;
761 
762         /** {@hide} */
Session(IPackageInstallerSession session)763         public Session(IPackageInstallerSession session) {
764             mSession = session;
765         }
766 
767         /** {@hide} */
768         @Deprecated
setProgress(float progress)769         public void setProgress(float progress) {
770             setStagingProgress(progress);
771         }
772 
773         /**
774          * Set current progress of staging this session. Valid values are
775          * anywhere between 0 and 1.
776          * <p>
777          * Note that this progress may not directly correspond to the value
778          * reported by {@link SessionCallback#onProgressChanged(int, float)}, as
779          * the system may carve out a portion of the overall progress to
780          * represent its own internal installation work.
781          */
setStagingProgress(float progress)782         public void setStagingProgress(float progress) {
783             try {
784                 mSession.setClientProgress(progress);
785             } catch (RemoteException e) {
786                 throw e.rethrowFromSystemServer();
787             }
788         }
789 
790         /** {@hide} */
addProgress(float progress)791         public void addProgress(float progress) {
792             try {
793                 mSession.addClientProgress(progress);
794             } catch (RemoteException e) {
795                 throw e.rethrowFromSystemServer();
796             }
797         }
798 
799         /**
800          * Open a stream to write an APK file into the session.
801          * <p>
802          * The returned stream will start writing data at the requested offset
803          * in the underlying file, which can be used to resume a partially
804          * written file. If a valid file length is specified, the system will
805          * preallocate the underlying disk space to optimize placement on disk.
806          * It's strongly recommended to provide a valid file length when known.
807          * <p>
808          * You can write data into the returned stream, optionally call
809          * {@link #fsync(OutputStream)} as needed to ensure bytes have been
810          * persisted to disk, and then close when finished. All streams must be
811          * closed before calling {@link #commit(IntentSender)}.
812          *
813          * @param name arbitrary, unique name of your choosing to identify the
814          *            APK being written. You can open a file again for
815          *            additional writes (such as after a reboot) by using the
816          *            same name. This name is only meaningful within the context
817          *            of a single install session.
818          * @param offsetBytes offset into the file to begin writing at, or 0 to
819          *            start at the beginning of the file.
820          * @param lengthBytes total size of the file being written, used to
821          *            preallocate the underlying disk space, or -1 if unknown.
822          *            The system may clear various caches as needed to allocate
823          *            this space.
824          * @throws IOException if trouble opening the file for writing, such as
825          *             lack of disk space or unavailable media.
826          * @throws SecurityException if called after the session has been
827          *             sealed or abandoned
828          */
openWrite(@onNull String name, long offsetBytes, long lengthBytes)829         public @NonNull OutputStream openWrite(@NonNull String name, long offsetBytes,
830                 long lengthBytes) throws IOException {
831             try {
832                 if (ENABLE_REVOCABLE_FD) {
833                     return new ParcelFileDescriptor.AutoCloseOutputStream(
834                             mSession.openWrite(name, offsetBytes, lengthBytes));
835                 } else {
836                     final ParcelFileDescriptor clientSocket = mSession.openWrite(name,
837                             offsetBytes, lengthBytes);
838                     return new FileBridge.FileBridgeOutputStream(clientSocket);
839                 }
840             } catch (RuntimeException e) {
841                 ExceptionUtils.maybeUnwrapIOException(e);
842                 throw e;
843             } catch (RemoteException e) {
844                 throw e.rethrowFromSystemServer();
845             }
846         }
847 
848         /** {@hide} */
write(@onNull String name, long offsetBytes, long lengthBytes, @NonNull ParcelFileDescriptor fd)849         public void write(@NonNull String name, long offsetBytes, long lengthBytes,
850                 @NonNull ParcelFileDescriptor fd) throws IOException {
851             try {
852                 mSession.write(name, offsetBytes, lengthBytes, fd);
853             } catch (RuntimeException e) {
854                 ExceptionUtils.maybeUnwrapIOException(e);
855                 throw e;
856             } catch (RemoteException e) {
857                 throw e.rethrowFromSystemServer();
858             }
859         }
860 
861         /**
862          * Ensure that any outstanding data for given stream has been committed
863          * to disk. This is only valid for streams returned from
864          * {@link #openWrite(String, long, long)}.
865          */
fsync(@onNull OutputStream out)866         public void fsync(@NonNull OutputStream out) throws IOException {
867             if (ENABLE_REVOCABLE_FD) {
868                 if (out instanceof ParcelFileDescriptor.AutoCloseOutputStream) {
869                     try {
870                         Os.fsync(((ParcelFileDescriptor.AutoCloseOutputStream) out).getFD());
871                     } catch (ErrnoException e) {
872                         throw e.rethrowAsIOException();
873                     }
874                 } else {
875                     throw new IllegalArgumentException("Unrecognized stream");
876                 }
877             } else {
878                 if (out instanceof FileBridge.FileBridgeOutputStream) {
879                     ((FileBridge.FileBridgeOutputStream) out).fsync();
880                 } else {
881                     throw new IllegalArgumentException("Unrecognized stream");
882                 }
883             }
884         }
885 
886         /**
887          * Return all APK names contained in this session.
888          * <p>
889          * This returns all names which have been previously written through
890          * {@link #openWrite(String, long, long)} as part of this session.
891          *
892          * @throws SecurityException if called after the session has been
893          *             committed or abandoned.
894          */
getNames()895         public @NonNull String[] getNames() throws IOException {
896             try {
897                 return mSession.getNames();
898             } catch (RuntimeException e) {
899                 ExceptionUtils.maybeUnwrapIOException(e);
900                 throw e;
901             } catch (RemoteException e) {
902                 throw e.rethrowFromSystemServer();
903             }
904         }
905 
906         /**
907          * Open a stream to read an APK file from the session.
908          * <p>
909          * This is only valid for names which have been previously written
910          * through {@link #openWrite(String, long, long)} as part of this
911          * session. For example, this stream may be used to calculate a
912          * {@link MessageDigest} of a written APK before committing.
913          *
914          * @throws SecurityException if called after the session has been
915          *             committed or abandoned.
916          */
openRead(@onNull String name)917         public @NonNull InputStream openRead(@NonNull String name) throws IOException {
918             try {
919                 final ParcelFileDescriptor pfd = mSession.openRead(name);
920                 return new ParcelFileDescriptor.AutoCloseInputStream(pfd);
921             } catch (RuntimeException e) {
922                 ExceptionUtils.maybeUnwrapIOException(e);
923                 throw e;
924             } catch (RemoteException e) {
925                 throw e.rethrowFromSystemServer();
926             }
927         }
928 
929         /**
930          * Removes a split.
931          * <p>
932          * Split removals occur prior to adding new APKs. If upgrading a feature
933          * split, it is not expected nor desirable to remove the split prior to
934          * upgrading.
935          * <p>
936          * When split removal is bundled with new APKs, the packageName must be
937          * identical.
938          */
removeSplit(@onNull String splitName)939         public void removeSplit(@NonNull String splitName) throws IOException {
940             try {
941                 mSession.removeSplit(splitName);
942             } catch (RuntimeException e) {
943                 ExceptionUtils.maybeUnwrapIOException(e);
944                 throw e;
945             } catch (RemoteException e) {
946                 throw e.rethrowFromSystemServer();
947             }
948         }
949 
950         /**
951          * Attempt to commit everything staged in this session. This may require
952          * user intervention, and so it may not happen immediately. The final
953          * result of the commit will be reported through the given callback.
954          * <p>
955          * Once this method is called, the session is sealed and no additional
956          * mutations may be performed on the session. If the device reboots
957          * before the session has been finalized, you may commit the session again.
958          * <p>
959          * If the installer is the device owner or the affiliated profile owner, there will be no
960          * user intervention.
961          *
962          * @throws SecurityException if streams opened through
963          *             {@link #openWrite(String, long, long)} are still open.
964          *
965          * @see android.app.admin.DevicePolicyManager
966          */
commit(@onNull IntentSender statusReceiver)967         public void commit(@NonNull IntentSender statusReceiver) {
968             try {
969                 mSession.commit(statusReceiver, false);
970             } catch (RemoteException e) {
971                 throw e.rethrowFromSystemServer();
972             }
973         }
974 
975         /**
976          * Attempt to commit a session that has been {@link #transfer(String) transferred}.
977          *
978          * <p>If the device reboots before the session has been finalized, you may commit the
979          * session again.
980          *
981          * <p>The caller of this method is responsible to ensure the safety of the session. As the
982          * session was created by another - usually less trusted - app, it is paramount that before
983          * committing <u>all</u> public and system {@link SessionInfo properties of the session}
984          * and <u>all</u> {@link #openRead(String) APKs} are verified by the caller. It might happen
985          * that new properties are added to the session with a new API revision. In this case the
986          * callers need to be updated.
987          *
988          * @param statusReceiver Callbacks called when the state of the session changes.
989          *
990          * @hide
991          */
992         @SystemApi
993         @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES)
commitTransferred(@onNull IntentSender statusReceiver)994         public void commitTransferred(@NonNull IntentSender statusReceiver) {
995             try {
996                 mSession.commit(statusReceiver, true);
997             } catch (RemoteException e) {
998                 throw e.rethrowFromSystemServer();
999             }
1000         }
1001 
1002         /**
1003          * Transfer the session to a new owner.
1004          * <p>
1005          * Only sessions that update the installing app can be transferred.
1006          * <p>
1007          * After the transfer to a package with a different uid all method calls on the session
1008          * will cause {@link SecurityException}s.
1009          * <p>
1010          * Once this method is called, the session is sealed and no additional mutations beside
1011          * committing it may be performed on the session.
1012          *
1013          * @param packageName The package of the new owner. Needs to hold the INSTALL_PACKAGES
1014          *                    permission.
1015          *
1016          * @throws PackageManager.NameNotFoundException if the new owner could not be found.
1017          * @throws SecurityException if called after the session has been committed or abandoned.
1018          * @throws SecurityException if the session does not update the original installer
1019          * @throws SecurityException if streams opened through
1020          *                           {@link #openWrite(String, long, long) are still open.
1021          */
transfer(@onNull String packageName)1022         public void transfer(@NonNull String packageName)
1023                 throws PackageManager.NameNotFoundException {
1024             Preconditions.checkNotNull(packageName);
1025 
1026             try {
1027                 mSession.transfer(packageName);
1028             } catch (ParcelableException e) {
1029                 e.maybeRethrow(PackageManager.NameNotFoundException.class);
1030                 throw new RuntimeException(e);
1031             } catch (RemoteException e) {
1032                 throw e.rethrowFromSystemServer();
1033             }
1034         }
1035 
1036         /**
1037          * Release this session object. You can open the session again if it
1038          * hasn't been finalized.
1039          */
1040         @Override
close()1041         public void close() {
1042             try {
1043                 mSession.close();
1044             } catch (RemoteException e) {
1045                 throw e.rethrowFromSystemServer();
1046             }
1047         }
1048 
1049         /**
1050          * Completely abandon this session, destroying all staged data and
1051          * rendering it invalid. Abandoned sessions will be reported to
1052          * {@link SessionCallback} listeners as failures. This is equivalent to
1053          * opening the session and calling {@link Session#abandon()}.
1054          */
abandon()1055         public void abandon() {
1056             try {
1057                 mSession.abandon();
1058             } catch (RemoteException e) {
1059                 throw e.rethrowFromSystemServer();
1060             }
1061         }
1062     }
1063 
1064     /**
1065      * Parameters for creating a new {@link PackageInstaller.Session}.
1066      */
1067     public static class SessionParams implements Parcelable {
1068 
1069         /** {@hide} */
1070         public static final int MODE_INVALID = -1;
1071 
1072         /**
1073          * Mode for an install session whose staged APKs should fully replace any
1074          * existing APKs for the target app.
1075          */
1076         public static final int MODE_FULL_INSTALL = 1;
1077 
1078         /**
1079          * Mode for an install session that should inherit any existing APKs for the
1080          * target app, unless they have been explicitly overridden (based on split
1081          * name) by the session. For example, this can be used to add one or more
1082          * split APKs to an existing installation.
1083          * <p>
1084          * If there are no existing APKs for the target app, this behaves like
1085          * {@link #MODE_FULL_INSTALL}.
1086          */
1087         public static final int MODE_INHERIT_EXISTING = 2;
1088 
1089         /** {@hide} */
1090         public static final int UID_UNKNOWN = -1;
1091 
1092         /** {@hide} */
1093         public int mode = MODE_INVALID;
1094         /** {@hide} */
1095         public int installFlags;
1096         /** {@hide} */
1097         public int installLocation = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY;
1098         /** {@hide} */
1099         public @InstallReason int installReason = PackageManager.INSTALL_REASON_UNKNOWN;
1100         /** {@hide} */
1101         public long sizeBytes = -1;
1102         /** {@hide} */
1103         public String appPackageName;
1104         /** {@hide} */
1105         public Bitmap appIcon;
1106         /** {@hide} */
1107         public String appLabel;
1108         /** {@hide} */
1109         public long appIconLastModified = -1;
1110         /** {@hide} */
1111         public Uri originatingUri;
1112         /** {@hide} */
1113         public int originatingUid = UID_UNKNOWN;
1114         /** {@hide} */
1115         public Uri referrerUri;
1116         /** {@hide} */
1117         public String abiOverride;
1118         /** {@hide} */
1119         public String volumeUuid;
1120         /** {@hide} */
1121         public String[] grantedRuntimePermissions;
1122         /** {@hide} */
1123         public String installerPackageName;
1124 
1125         /**
1126          * Construct parameters for a new package install session.
1127          *
1128          * @param mode one of {@link #MODE_FULL_INSTALL} or
1129          *            {@link #MODE_INHERIT_EXISTING} describing how the session
1130          *            should interact with an existing app.
1131          */
SessionParams(int mode)1132         public SessionParams(int mode) {
1133             this.mode = mode;
1134         }
1135 
1136         /** {@hide} */
SessionParams(Parcel source)1137         public SessionParams(Parcel source) {
1138             mode = source.readInt();
1139             installFlags = source.readInt();
1140             installLocation = source.readInt();
1141             installReason = source.readInt();
1142             sizeBytes = source.readLong();
1143             appPackageName = source.readString();
1144             appIcon = source.readParcelable(null);
1145             appLabel = source.readString();
1146             originatingUri = source.readParcelable(null);
1147             originatingUid = source.readInt();
1148             referrerUri = source.readParcelable(null);
1149             abiOverride = source.readString();
1150             volumeUuid = source.readString();
1151             grantedRuntimePermissions = source.readStringArray();
1152             installerPackageName = source.readString();
1153         }
1154 
1155         /**
1156          * Check if there are hidden options set.
1157          *
1158          * <p>Hidden options are those options that cannot be verified via public or system-api
1159          * methods on {@link SessionInfo}.
1160          *
1161          * @return {@code true} if any hidden option is set.
1162          *
1163          * @hide
1164          */
areHiddenOptionsSet()1165         public boolean areHiddenOptionsSet() {
1166             return (installFlags & (PackageManager.INSTALL_ALLOW_DOWNGRADE
1167                     | PackageManager.INSTALL_DONT_KILL_APP
1168                     | PackageManager.INSTALL_INSTANT_APP
1169                     | PackageManager.INSTALL_FULL_APP
1170                     | PackageManager.INSTALL_VIRTUAL_PRELOAD
1171                     | PackageManager.INSTALL_ALLOCATE_AGGRESSIVE)) != installFlags
1172                     || abiOverride != null || volumeUuid != null;
1173         }
1174 
1175         /**
1176          * Provide value of {@link PackageInfo#installLocation}, which may be used
1177          * to determine where the app will be staged. Defaults to
1178          * {@link PackageInfo#INSTALL_LOCATION_INTERNAL_ONLY}.
1179          */
setInstallLocation(int installLocation)1180         public void setInstallLocation(int installLocation) {
1181             this.installLocation = installLocation;
1182         }
1183 
1184         /**
1185          * Optionally indicate the total size (in bytes) of all APKs that will be
1186          * delivered in this session. The system may use this to ensure enough disk
1187          * space exists before proceeding, or to estimate container size for
1188          * installations living on external storage.
1189          *
1190          * @see PackageInfo#INSTALL_LOCATION_AUTO
1191          * @see PackageInfo#INSTALL_LOCATION_PREFER_EXTERNAL
1192          */
setSize(long sizeBytes)1193         public void setSize(long sizeBytes) {
1194             this.sizeBytes = sizeBytes;
1195         }
1196 
1197         /**
1198          * Optionally set the package name of the app being installed. It's strongly
1199          * recommended that you provide this value when known, so that observers can
1200          * communicate installing apps to users.
1201          * <p>
1202          * If the APKs staged in the session aren't consistent with this package
1203          * name, the install will fail. Regardless of this value, all APKs in the
1204          * app must have the same package name.
1205          */
setAppPackageName(@ullable String appPackageName)1206         public void setAppPackageName(@Nullable String appPackageName) {
1207             this.appPackageName = appPackageName;
1208         }
1209 
1210         /**
1211          * Optionally set an icon representing the app being installed. This should
1212          * be roughly {@link ActivityManager#getLauncherLargeIconSize()} in both
1213          * dimensions.
1214          */
setAppIcon(@ullable Bitmap appIcon)1215         public void setAppIcon(@Nullable Bitmap appIcon) {
1216             this.appIcon = appIcon;
1217         }
1218 
1219         /**
1220          * Optionally set a label representing the app being installed.
1221          */
setAppLabel(@ullable CharSequence appLabel)1222         public void setAppLabel(@Nullable CharSequence appLabel) {
1223             this.appLabel = (appLabel != null) ? appLabel.toString() : null;
1224         }
1225 
1226         /**
1227          * Optionally set the URI where this package was downloaded from. This is
1228          * informational and may be used as a signal for anti-malware purposes.
1229          *
1230          * @see Intent#EXTRA_ORIGINATING_URI
1231          */
setOriginatingUri(@ullable Uri originatingUri)1232         public void setOriginatingUri(@Nullable Uri originatingUri) {
1233             this.originatingUri = originatingUri;
1234         }
1235 
1236         /**
1237          * Sets the UID that initiated the package installation. This is informational
1238          * and may be used as a signal for anti-malware purposes.
1239          *
1240          * @see Intent#EXTRA_ORIGINATING_UID
1241          */
setOriginatingUid(int originatingUid)1242         public void setOriginatingUid(int originatingUid) {
1243             this.originatingUid = originatingUid;
1244         }
1245 
1246         /**
1247          * Optionally set the URI that referred you to install this package. This is
1248          * informational and may be used as a signal for anti-malware purposes.
1249          *
1250          * @see Intent#EXTRA_REFERRER
1251          */
setReferrerUri(@ullable Uri referrerUri)1252         public void setReferrerUri(@Nullable Uri referrerUri) {
1253             this.referrerUri = referrerUri;
1254         }
1255 
1256         /**
1257          * Sets which runtime permissions to be granted to the package at installation.
1258          *
1259          * @param permissions The permissions to grant or null to grant all runtime
1260          *     permissions.
1261          *
1262          * @hide
1263          */
1264         @SystemApi
1265         @RequiresPermission(android.Manifest.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS)
setGrantedRuntimePermissions(String[] permissions)1266         public void setGrantedRuntimePermissions(String[] permissions) {
1267             installFlags |= PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS;
1268             this.grantedRuntimePermissions = permissions;
1269         }
1270 
1271         /** {@hide} */
setInstallFlagsInternal()1272         public void setInstallFlagsInternal() {
1273             installFlags |= PackageManager.INSTALL_INTERNAL;
1274             installFlags &= ~PackageManager.INSTALL_EXTERNAL;
1275         }
1276 
1277         /** {@hide} */
1278         @SystemApi
setAllowDowngrade(boolean allowDowngrade)1279         public void setAllowDowngrade(boolean allowDowngrade) {
1280             if (allowDowngrade) {
1281                 installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE;
1282             } else {
1283                 installFlags &= ~PackageManager.INSTALL_ALLOW_DOWNGRADE;
1284             }
1285         }
1286 
1287         /** {@hide} */
setInstallFlagsExternal()1288         public void setInstallFlagsExternal() {
1289             installFlags |= PackageManager.INSTALL_EXTERNAL;
1290             installFlags &= ~PackageManager.INSTALL_INTERNAL;
1291         }
1292 
1293         /** {@hide} */
setInstallFlagsForcePermissionPrompt()1294         public void setInstallFlagsForcePermissionPrompt() {
1295             installFlags |= PackageManager.INSTALL_FORCE_PERMISSION_PROMPT;
1296         }
1297 
1298         /** {@hide} */
1299         @SystemApi
setDontKillApp(boolean dontKillApp)1300         public void setDontKillApp(boolean dontKillApp) {
1301             if (dontKillApp) {
1302                 installFlags |= PackageManager.INSTALL_DONT_KILL_APP;
1303             } else {
1304                 installFlags &= ~PackageManager.INSTALL_DONT_KILL_APP;
1305             }
1306         }
1307 
1308         /** {@hide} */
1309         @SystemApi
setInstallAsInstantApp(boolean isInstantApp)1310         public void setInstallAsInstantApp(boolean isInstantApp) {
1311             if (isInstantApp) {
1312                 installFlags |= PackageManager.INSTALL_INSTANT_APP;
1313                 installFlags &= ~PackageManager.INSTALL_FULL_APP;
1314             } else {
1315                 installFlags &= ~PackageManager.INSTALL_INSTANT_APP;
1316                 installFlags |= PackageManager.INSTALL_FULL_APP;
1317             }
1318         }
1319 
1320         /**
1321          * Sets the install as a virtual preload. Will only have effect when called
1322          * by the verifier.
1323          * {@hide}
1324          */
1325         @SystemApi
setInstallAsVirtualPreload()1326         public void setInstallAsVirtualPreload() {
1327             installFlags |= PackageManager.INSTALL_VIRTUAL_PRELOAD;
1328         }
1329 
1330         /**
1331          * Set the reason for installing this package.
1332          */
setInstallReason(@nstallReason int installReason)1333         public void setInstallReason(@InstallReason int installReason) {
1334             this.installReason = installReason;
1335         }
1336 
1337         /** {@hide} */
1338         @SystemApi
1339         @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE)
setAllocateAggressive(boolean allocateAggressive)1340         public void setAllocateAggressive(boolean allocateAggressive) {
1341             if (allocateAggressive) {
1342                 installFlags |= PackageManager.INSTALL_ALLOCATE_AGGRESSIVE;
1343             } else {
1344                 installFlags &= ~PackageManager.INSTALL_ALLOCATE_AGGRESSIVE;
1345             }
1346         }
1347 
1348         /**
1349          * Set the installer package for the app.
1350          *
1351          * By default this is the app that created the {@link PackageInstaller} object.
1352          *
1353          * @param installerPackageName name of the installer package
1354          * {@hide}
1355          */
setInstallerPackageName(String installerPackageName)1356         public void setInstallerPackageName(String installerPackageName) {
1357             this.installerPackageName = installerPackageName;
1358         }
1359 
1360         /** {@hide} */
dump(IndentingPrintWriter pw)1361         public void dump(IndentingPrintWriter pw) {
1362             pw.printPair("mode", mode);
1363             pw.printHexPair("installFlags", installFlags);
1364             pw.printPair("installLocation", installLocation);
1365             pw.printPair("sizeBytes", sizeBytes);
1366             pw.printPair("appPackageName", appPackageName);
1367             pw.printPair("appIcon", (appIcon != null));
1368             pw.printPair("appLabel", appLabel);
1369             pw.printPair("originatingUri", originatingUri);
1370             pw.printPair("originatingUid", originatingUid);
1371             pw.printPair("referrerUri", referrerUri);
1372             pw.printPair("abiOverride", abiOverride);
1373             pw.printPair("volumeUuid", volumeUuid);
1374             pw.printPair("grantedRuntimePermissions", grantedRuntimePermissions);
1375             pw.printPair("installerPackageName", installerPackageName);
1376             pw.println();
1377         }
1378 
1379         @Override
describeContents()1380         public int describeContents() {
1381             return 0;
1382         }
1383 
1384         @Override
writeToParcel(Parcel dest, int flags)1385         public void writeToParcel(Parcel dest, int flags) {
1386             dest.writeInt(mode);
1387             dest.writeInt(installFlags);
1388             dest.writeInt(installLocation);
1389             dest.writeInt(installReason);
1390             dest.writeLong(sizeBytes);
1391             dest.writeString(appPackageName);
1392             dest.writeParcelable(appIcon, flags);
1393             dest.writeString(appLabel);
1394             dest.writeParcelable(originatingUri, flags);
1395             dest.writeInt(originatingUid);
1396             dest.writeParcelable(referrerUri, flags);
1397             dest.writeString(abiOverride);
1398             dest.writeString(volumeUuid);
1399             dest.writeStringArray(grantedRuntimePermissions);
1400             dest.writeString(installerPackageName);
1401         }
1402 
1403         public static final Parcelable.Creator<SessionParams>
1404                 CREATOR = new Parcelable.Creator<SessionParams>() {
1405                     @Override
1406                     public SessionParams createFromParcel(Parcel p) {
1407                         return new SessionParams(p);
1408                     }
1409 
1410                     @Override
1411                     public SessionParams[] newArray(int size) {
1412                         return new SessionParams[size];
1413                     }
1414                 };
1415     }
1416 
1417     /**
1418      * Details for an active install session.
1419      */
1420     public static class SessionInfo implements Parcelable {
1421 
1422         /** {@hide} */
1423         public int sessionId;
1424         /** {@hide} */
1425         public String installerPackageName;
1426         /** {@hide} */
1427         public String resolvedBaseCodePath;
1428         /** {@hide} */
1429         public float progress;
1430         /** {@hide} */
1431         public boolean sealed;
1432         /** {@hide} */
1433         public boolean active;
1434 
1435         /** {@hide} */
1436         public int mode;
1437         /** {@hide} */
1438         public @InstallReason int installReason;
1439         /** {@hide} */
1440         public long sizeBytes;
1441         /** {@hide} */
1442         public String appPackageName;
1443         /** {@hide} */
1444         public Bitmap appIcon;
1445         /** {@hide} */
1446         public CharSequence appLabel;
1447 
1448         /** {@hide} */
1449         public int installLocation;
1450         /** {@hide} */
1451         public Uri originatingUri;
1452         /** {@hide} */
1453         public int originatingUid;
1454         /** {@hide} */
1455         public Uri referrerUri;
1456         /** {@hide} */
1457         public String[] grantedRuntimePermissions;
1458         /** {@hide} */
1459         public int installFlags;
1460 
1461         /** {@hide} */
SessionInfo()1462         public SessionInfo() {
1463         }
1464 
1465         /** {@hide} */
SessionInfo(Parcel source)1466         public SessionInfo(Parcel source) {
1467             sessionId = source.readInt();
1468             installerPackageName = source.readString();
1469             resolvedBaseCodePath = source.readString();
1470             progress = source.readFloat();
1471             sealed = source.readInt() != 0;
1472             active = source.readInt() != 0;
1473 
1474             mode = source.readInt();
1475             installReason = source.readInt();
1476             sizeBytes = source.readLong();
1477             appPackageName = source.readString();
1478             appIcon = source.readParcelable(null);
1479             appLabel = source.readString();
1480 
1481             installLocation = source.readInt();
1482             originatingUri = source.readParcelable(null);
1483             originatingUid = source.readInt();
1484             referrerUri = source.readParcelable(null);
1485             grantedRuntimePermissions = source.readStringArray();
1486             installFlags = source.readInt();
1487         }
1488 
1489         /**
1490          * Return the ID for this session.
1491          */
getSessionId()1492         public int getSessionId() {
1493             return sessionId;
1494         }
1495 
1496         /**
1497          * Return the package name of the app that owns this session.
1498          */
getInstallerPackageName()1499         public @Nullable String getInstallerPackageName() {
1500             return installerPackageName;
1501         }
1502 
1503         /**
1504          * Return current overall progress of this session, between 0 and 1.
1505          * <p>
1506          * Note that this progress may not directly correspond to the value
1507          * reported by
1508          * {@link PackageInstaller.Session#setStagingProgress(float)}, as the
1509          * system may carve out a portion of the overall progress to represent
1510          * its own internal installation work.
1511          */
getProgress()1512         public float getProgress() {
1513             return progress;
1514         }
1515 
1516         /**
1517          * Return if this session is currently active.
1518          * <p>
1519          * A session is considered active whenever there is ongoing forward
1520          * progress being made, such as the installer holding an open
1521          * {@link Session} instance while streaming data into place, or the
1522          * system optimizing code as the result of
1523          * {@link Session#commit(IntentSender)}.
1524          * <p>
1525          * If the installer closes the {@link Session} without committing, the
1526          * session is considered inactive until the installer opens the session
1527          * again.
1528          */
isActive()1529         public boolean isActive() {
1530             return active;
1531         }
1532 
1533         /**
1534          * Return if this session is sealed.
1535          * <p>
1536          * Once sealed, no further changes may be made to the session. A session
1537          * is sealed the moment {@link Session#commit(IntentSender)} is called.
1538          */
isSealed()1539         public boolean isSealed() {
1540             return sealed;
1541         }
1542 
1543         /**
1544          * Return the reason for installing this package.
1545          *
1546          * @return The install reason.
1547          */
getInstallReason()1548         public @InstallReason int getInstallReason() {
1549             return installReason;
1550         }
1551 
1552         /** {@hide} */
1553         @Deprecated
isOpen()1554         public boolean isOpen() {
1555             return isActive();
1556         }
1557 
1558         /**
1559          * Return the package name this session is working with. May be {@code null}
1560          * if unknown.
1561          */
getAppPackageName()1562         public @Nullable String getAppPackageName() {
1563             return appPackageName;
1564         }
1565 
1566         /**
1567          * Return an icon representing the app being installed. May be {@code null}
1568          * if unavailable.
1569          */
getAppIcon()1570         public @Nullable Bitmap getAppIcon() {
1571             if (appIcon == null) {
1572                 // Icon may have been omitted for calls that return bulk session
1573                 // lists, so try fetching the specific icon.
1574                 try {
1575                     final SessionInfo info = AppGlobals.getPackageManager().getPackageInstaller()
1576                             .getSessionInfo(sessionId);
1577                     appIcon = (info != null) ? info.appIcon : null;
1578                 } catch (RemoteException e) {
1579                     throw e.rethrowFromSystemServer();
1580                 }
1581             }
1582             return appIcon;
1583         }
1584 
1585         /**
1586          * Return a label representing the app being installed. May be {@code null}
1587          * if unavailable.
1588          */
getAppLabel()1589         public @Nullable CharSequence getAppLabel() {
1590             return appLabel;
1591         }
1592 
1593         /**
1594          * Return an Intent that can be started to view details about this install
1595          * session. This may surface actions such as pause, resume, or cancel.
1596          * <p>
1597          * In some cases, a matching Activity may not exist, so ensure you safeguard
1598          * against this.
1599          *
1600          * @see PackageInstaller#ACTION_SESSION_DETAILS
1601          */
createDetailsIntent()1602         public @Nullable Intent createDetailsIntent() {
1603             final Intent intent = new Intent(PackageInstaller.ACTION_SESSION_DETAILS);
1604             intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
1605             intent.setPackage(installerPackageName);
1606             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1607             return intent;
1608         }
1609 
1610         /**
1611          * Get the mode of the session as set in the constructor of the {@link SessionParams}.
1612          *
1613          * @return One of {@link SessionParams#MODE_FULL_INSTALL}
1614          *         or {@link SessionParams#MODE_INHERIT_EXISTING}
1615          */
getMode()1616         public int getMode() {
1617             return mode;
1618         }
1619 
1620         /**
1621          * Get the value set in {@link SessionParams#setInstallLocation(int)}.
1622          */
getInstallLocation()1623         public int getInstallLocation() {
1624             return installLocation;
1625         }
1626 
1627         /**
1628          * Get the value as set in {@link SessionParams#setSize(long)}.
1629          *
1630          * <p>The value is a hint and does not have to match the actual size.
1631          */
getSize()1632         public long getSize() {
1633             return sizeBytes;
1634         }
1635 
1636         /**
1637          * Get the value set in {@link SessionParams#setOriginatingUri(Uri)}.
1638          */
getOriginatingUri()1639         public @Nullable Uri getOriginatingUri() {
1640             return originatingUri;
1641         }
1642 
1643         /**
1644          * Get the value set in {@link SessionParams#setOriginatingUid(int)}.
1645          */
getOriginatingUid()1646         public int getOriginatingUid() {
1647             return originatingUid;
1648         }
1649 
1650         /**
1651          * Get the value set in {@link SessionParams#setReferrerUri(Uri)}
1652          */
getReferrerUri()1653         public @Nullable Uri getReferrerUri() {
1654             return referrerUri;
1655         }
1656 
1657         /**
1658          * Get the value set in {@link SessionParams#setGrantedRuntimePermissions(String[])}.
1659          *
1660          * @hide
1661          */
1662         @SystemApi
getGrantedRuntimePermissions()1663         public @Nullable String[] getGrantedRuntimePermissions() {
1664             return grantedRuntimePermissions;
1665         }
1666 
1667         /**
1668          * Get the value set in {@link SessionParams#setAllowDowngrade(boolean)}.
1669          *
1670          * @hide
1671          */
1672         @SystemApi
getAllowDowngrade()1673         public boolean getAllowDowngrade() {
1674             return (installFlags & PackageManager.INSTALL_ALLOW_DOWNGRADE) != 0;
1675         }
1676 
1677         /**
1678          * Get the value set in {@link SessionParams#setDontKillApp(boolean)}.
1679          *
1680          * @hide
1681          */
1682         @SystemApi
getDontKillApp()1683         public boolean getDontKillApp() {
1684             return (installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0;
1685         }
1686 
1687         /**
1688          * If {@link SessionParams#setInstallAsInstantApp(boolean)} was called with {@code true},
1689          * return true. If it was called with {@code false} or if it was not called return false.
1690          *
1691          * @hide
1692          *
1693          * @see #getInstallAsFullApp
1694          */
1695         @SystemApi
getInstallAsInstantApp(boolean isInstantApp)1696         public boolean getInstallAsInstantApp(boolean isInstantApp) {
1697             return (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
1698         }
1699 
1700         /**
1701          * If {@link SessionParams#setInstallAsInstantApp(boolean)} was called with {@code false},
1702          * return true. If it was called with {@code true} or if it was not called return false.
1703          *
1704          * @hide
1705          *
1706          * @see #getInstallAsInstantApp
1707          */
1708         @SystemApi
getInstallAsFullApp(boolean isInstantApp)1709         public boolean getInstallAsFullApp(boolean isInstantApp) {
1710             return (installFlags & PackageManager.INSTALL_FULL_APP) != 0;
1711         }
1712 
1713         /**
1714          * Get if {@link SessionParams#setInstallAsVirtualPreload()} was called.
1715          *
1716          * @hide
1717          */
1718         @SystemApi
getInstallAsVirtualPreload()1719         public boolean getInstallAsVirtualPreload() {
1720             return (installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0;
1721         }
1722 
1723         /**
1724          * Get the value set in {@link SessionParams#setAllocateAggressive(boolean)}.
1725          *
1726          * @hide
1727          */
1728         @SystemApi
getAllocateAggressive()1729         public boolean getAllocateAggressive() {
1730             return (installFlags & PackageManager.INSTALL_ALLOCATE_AGGRESSIVE) != 0;
1731         }
1732 
1733 
1734         /** {@hide} */
1735         @Deprecated
getDetailsIntent()1736         public @Nullable Intent getDetailsIntent() {
1737             return createDetailsIntent();
1738         }
1739 
1740         @Override
describeContents()1741         public int describeContents() {
1742             return 0;
1743         }
1744 
1745         @Override
writeToParcel(Parcel dest, int flags)1746         public void writeToParcel(Parcel dest, int flags) {
1747             dest.writeInt(sessionId);
1748             dest.writeString(installerPackageName);
1749             dest.writeString(resolvedBaseCodePath);
1750             dest.writeFloat(progress);
1751             dest.writeInt(sealed ? 1 : 0);
1752             dest.writeInt(active ? 1 : 0);
1753 
1754             dest.writeInt(mode);
1755             dest.writeInt(installReason);
1756             dest.writeLong(sizeBytes);
1757             dest.writeString(appPackageName);
1758             dest.writeParcelable(appIcon, flags);
1759             dest.writeString(appLabel != null ? appLabel.toString() : null);
1760 
1761             dest.writeInt(installLocation);
1762             dest.writeParcelable(originatingUri, flags);
1763             dest.writeInt(originatingUid);
1764             dest.writeParcelable(referrerUri, flags);
1765             dest.writeStringArray(grantedRuntimePermissions);
1766             dest.writeInt(installFlags);
1767         }
1768 
1769         public static final Parcelable.Creator<SessionInfo>
1770                 CREATOR = new Parcelable.Creator<SessionInfo>() {
1771                     @Override
1772                     public SessionInfo createFromParcel(Parcel p) {
1773                         return new SessionInfo(p);
1774                     }
1775 
1776                     @Override
1777                     public SessionInfo[] newArray(int size) {
1778                         return new SessionInfo[size];
1779                     }
1780                 };
1781     }
1782 }
1783