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