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.annotation.NonNull;
     20 import android.annotation.Nullable;
     21 import android.annotation.RequiresPermission;
     22 import android.annotation.SdkConstant;
     23 import android.annotation.SdkConstant.SdkConstantType;
     24 import android.annotation.SystemApi;
     25 import android.app.ActivityManager;
     26 import android.content.Context;
     27 import android.content.Intent;
     28 import android.content.IntentSender;
     29 import android.graphics.Bitmap;
     30 import android.net.Uri;
     31 import android.os.FileBridge;
     32 import android.os.Handler;
     33 import android.os.Looper;
     34 import android.os.Message;
     35 import android.os.Parcel;
     36 import android.os.ParcelFileDescriptor;
     37 import android.os.Parcelable;
     38 import android.os.RemoteException;
     39 import android.util.ExceptionUtils;
     40 
     41 import com.android.internal.util.IndentingPrintWriter;
     42 
     43 import java.io.Closeable;
     44 import java.io.IOException;
     45 import java.io.InputStream;
     46 import java.io.OutputStream;
     47 import java.security.MessageDigest;
     48 import java.util.ArrayList;
     49 import java.util.Iterator;
     50 import java.util.List;
     51 
     52 /**
     53  * Offers the ability to install, upgrade, and remove applications on the
     54  * device. This includes support for apps packaged either as a single
     55  * "monolithic" APK, or apps packaged as multiple "split" APKs.
     56  * <p>
     57  * An app is delivered for installation through a
     58  * {@link PackageInstaller.Session}, which any app can create. Once the session
     59  * is created, the installer can stream one or more APKs into place until it
     60  * decides to either commit or destroy the session. Committing may require user
     61  * intervention to complete the installation.
     62  * <p>
     63  * Sessions can install brand new apps, upgrade existing apps, or add new splits
     64  * into an existing app.
     65  * <p>
     66  * Apps packaged as multiple split APKs always consist of a single "base" APK
     67  * (with a {@code null} split name) and zero or more "split" APKs (with unique
     68  * split names). Any subset of these APKs can be installed together, as long as
     69  * the following constraints are met:
     70  * <ul>
     71  * <li>All APKs must have the exact same package name, version code, and signing
     72  * certificates.
     73  * <li>All APKs must have unique split names.
     74  * <li>All installations must contain a single base APK.
     75  * </ul>
     76  */
     77 public class PackageInstaller {
     78     private static final String TAG = "PackageInstaller";
     79 
     80     /**
     81      * Activity Action: Show details about a particular install session. This
     82      * may surface actions such as pause, resume, or cancel.
     83      * <p>
     84      * This should always be scoped to the installer package that owns the
     85      * session. Clients should use {@link SessionInfo#createDetailsIntent()} to
     86      * build this intent correctly.
     87      * <p>
     88      * In some cases, a matching Activity may not exist, so ensure you safeguard
     89      * against this.
     90      * <p>
     91      * The session to show details for is defined in {@link #EXTRA_SESSION_ID}.
     92      */
     93     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     94     public static final String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS";
     95 
     96     /** {@hide} */
     97     public static final String
     98             ACTION_CONFIRM_PERMISSIONS = "android.content.pm.action.CONFIRM_PERMISSIONS";
     99 
    100     /**
    101      * An integer session ID that an operation is working with.
    102      *
    103      * @see Intent#getIntExtra(String, int)
    104      */
    105     public static final String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID";
    106 
    107     /**
    108      * Package name that an operation is working with.
    109      *
    110      * @see Intent#getStringExtra(String)
    111      */
    112     public static final String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME";
    113 
    114     /**
    115      * Current status of an operation. Will be one of
    116      * {@link #STATUS_PENDING_USER_ACTION}, {@link #STATUS_SUCCESS},
    117      * {@link #STATUS_FAILURE}, {@link #STATUS_FAILURE_ABORTED},
    118      * {@link #STATUS_FAILURE_BLOCKED}, {@link #STATUS_FAILURE_CONFLICT},
    119      * {@link #STATUS_FAILURE_INCOMPATIBLE}, {@link #STATUS_FAILURE_INVALID}, or
    120      * {@link #STATUS_FAILURE_STORAGE}.
    121      * <p>
    122      * More information about a status may be available through additional
    123      * extras; see the individual status documentation for details.
    124      *
    125      * @see Intent#getIntExtra(String, int)
    126      */
    127     public static final String EXTRA_STATUS = "android.content.pm.extra.STATUS";
    128 
    129     /**
    130      * Detailed string representation of the status, including raw details that
    131      * are useful for debugging.
    132      *
    133      * @see Intent#getStringExtra(String)
    134      */
    135     public static final String EXTRA_STATUS_MESSAGE = "android.content.pm.extra.STATUS_MESSAGE";
    136 
    137     /**
    138      * Another package name relevant to a status. This is typically the package
    139      * responsible for causing an operation failure.
    140      *
    141      * @see Intent#getStringExtra(String)
    142      */
    143     public static final String
    144             EXTRA_OTHER_PACKAGE_NAME = "android.content.pm.extra.OTHER_PACKAGE_NAME";
    145 
    146     /**
    147      * Storage path relevant to a status.
    148      *
    149      * @see Intent#getStringExtra(String)
    150      */
    151     public static final String EXTRA_STORAGE_PATH = "android.content.pm.extra.STORAGE_PATH";
    152 
    153     /** {@hide} */
    154     @Deprecated
    155     public static final String EXTRA_PACKAGE_NAMES = "android.content.pm.extra.PACKAGE_NAMES";
    156 
    157     /** {@hide} */
    158     public static final String EXTRA_LEGACY_STATUS = "android.content.pm.extra.LEGACY_STATUS";
    159     /** {@hide} */
    160     public static final String EXTRA_LEGACY_BUNDLE = "android.content.pm.extra.LEGACY_BUNDLE";
    161     /** {@hide} */
    162     public static final String EXTRA_CALLBACK = "android.content.pm.extra.CALLBACK";
    163 
    164     /**
    165      * User action is currently required to proceed. You can launch the intent
    166      * activity described by {@link Intent#EXTRA_INTENT} to involve the user and
    167      * continue.
    168      * <p>
    169      * You may choose to immediately launch the intent if the user is actively
    170      * using your app. Otherwise, you should use a notification to guide the
    171      * user back into your app before launching.
    172      *
    173      * @see Intent#getParcelableExtra(String)
    174      */
    175     public static final int STATUS_PENDING_USER_ACTION = -1;
    176 
    177     /**
    178      * The operation succeeded.
    179      */
    180     public static final int STATUS_SUCCESS = 0;
    181 
    182     /**
    183      * The operation failed in a generic way. The system will always try to
    184      * provide a more specific failure reason, but in some rare cases this may
    185      * be delivered.
    186      *
    187      * @see #EXTRA_STATUS_MESSAGE
    188      */
    189     public static final int STATUS_FAILURE = 1;
    190 
    191     /**
    192      * The operation failed because it was blocked. For example, a device policy
    193      * may be blocking the operation, a package verifier may have blocked the
    194      * operation, or the app may be required for core system operation.
    195      * <p>
    196      * The result may also contain {@link #EXTRA_OTHER_PACKAGE_NAME} with the
    197      * specific package blocking the install.
    198      *
    199      * @see #EXTRA_STATUS_MESSAGE
    200      * @see #EXTRA_OTHER_PACKAGE_NAME
    201      */
    202     public static final int STATUS_FAILURE_BLOCKED = 2;
    203 
    204     /**
    205      * The operation failed because it was actively aborted. For example, the
    206      * user actively declined requested permissions, or the session was
    207      * abandoned.
    208      *
    209      * @see #EXTRA_STATUS_MESSAGE
    210      */
    211     public static final int STATUS_FAILURE_ABORTED = 3;
    212 
    213     /**
    214      * The operation failed because one or more of the APKs was invalid. For
    215      * example, they might be malformed, corrupt, incorrectly signed,
    216      * mismatched, etc.
    217      *
    218      * @see #EXTRA_STATUS_MESSAGE
    219      */
    220     public static final int STATUS_FAILURE_INVALID = 4;
    221 
    222     /**
    223      * The operation failed because it conflicts (or is inconsistent with) with
    224      * another package already installed on the device. For example, an existing
    225      * permission, incompatible certificates, etc. The user may be able to
    226      * uninstall another app to fix the issue.
    227      * <p>
    228      * The result may also contain {@link #EXTRA_OTHER_PACKAGE_NAME} with the
    229      * specific package identified as the cause of the conflict.
    230      *
    231      * @see #EXTRA_STATUS_MESSAGE
    232      * @see #EXTRA_OTHER_PACKAGE_NAME
    233      */
    234     public static final int STATUS_FAILURE_CONFLICT = 5;
    235 
    236     /**
    237      * The operation failed because of storage issues. For example, the device
    238      * may be running low on space, or external media may be unavailable. The
    239      * user may be able to help free space or insert different external media.
    240      * <p>
    241      * The result may also contain {@link #EXTRA_STORAGE_PATH} with the path to
    242      * the storage device that caused the failure.
    243      *
    244      * @see #EXTRA_STATUS_MESSAGE
    245      * @see #EXTRA_STORAGE_PATH
    246      */
    247     public static final int STATUS_FAILURE_STORAGE = 6;
    248 
    249     /**
    250      * The operation failed because it is fundamentally incompatible with this
    251      * device. For example, the app may require a hardware feature that doesn't
    252      * exist, it may be missing native code for the ABIs supported by the
    253      * device, or it requires a newer SDK version, etc.
    254      *
    255      * @see #EXTRA_STATUS_MESSAGE
    256      */
    257     public static final int STATUS_FAILURE_INCOMPATIBLE = 7;
    258 
    259     private final Context mContext;
    260     private final PackageManager mPm;
    261     private final IPackageInstaller mInstaller;
    262     private final int mUserId;
    263     private final String mInstallerPackageName;
    264 
    265     private final ArrayList<SessionCallbackDelegate> mDelegates = new ArrayList<>();
    266 
    267     /** {@hide} */
    268     public PackageInstaller(Context context, PackageManager pm, IPackageInstaller installer,
    269             String installerPackageName, int userId) {
    270         mContext = context;
    271         mPm = pm;
    272         mInstaller = installer;
    273         mInstallerPackageName = installerPackageName;
    274         mUserId = userId;
    275     }
    276 
    277     /**
    278      * Create a new session using the given parameters, returning a unique ID
    279      * that represents the session. Once created, the session can be opened
    280      * multiple times across multiple device boots.
    281      * <p>
    282      * The system may automatically destroy sessions that have not been
    283      * finalized (either committed or abandoned) within a reasonable period of
    284      * time, typically on the order of a day.
    285      *
    286      * @throws IOException if parameters were unsatisfiable, such as lack of
    287      *             disk space or unavailable media.
    288      * @throws SecurityException when installation services are unavailable,
    289      *             such as when called from a restricted user.
    290      * @throws IllegalArgumentException when {@link SessionParams} is invalid.
    291      * @return positive, non-zero unique ID that represents the created session.
    292      *         This ID remains consistent across device reboots until the
    293      *         session is finalized. IDs are not reused during a given boot.
    294      */
    295     public int createSession(@NonNull SessionParams params) throws IOException {
    296         try {
    297             return mInstaller.createSession(params, mInstallerPackageName, mUserId);
    298         } catch (RuntimeException e) {
    299             ExceptionUtils.maybeUnwrapIOException(e);
    300             throw e;
    301         } catch (RemoteException e) {
    302             throw e.rethrowFromSystemServer();
    303         }
    304     }
    305 
    306     /**
    307      * Open an existing session to actively perform work. To succeed, the caller
    308      * must be the owner of the install session.
    309      *
    310      * @throws IOException if parameters were unsatisfiable, such as lack of
    311      *             disk space or unavailable media.
    312      * @throws SecurityException when the caller does not own the session, or
    313      *             the session is invalid.
    314      */
    315     public @NonNull Session openSession(int sessionId) throws IOException {
    316         try {
    317             return new Session(mInstaller.openSession(sessionId));
    318         } catch (RuntimeException e) {
    319             ExceptionUtils.maybeUnwrapIOException(e);
    320             throw e;
    321         } catch (RemoteException e) {
    322             throw e.rethrowFromSystemServer();
    323         }
    324     }
    325 
    326     /**
    327      * Update the icon representing the app being installed in a specific
    328      * session. This should be roughly
    329      * {@link ActivityManager#getLauncherLargeIconSize()} in both dimensions.
    330      *
    331      * @throws SecurityException when the caller does not own the session, or
    332      *             the session is invalid.
    333      */
    334     public void updateSessionAppIcon(int sessionId, @Nullable Bitmap appIcon) {
    335         try {
    336             mInstaller.updateSessionAppIcon(sessionId, appIcon);
    337         } catch (RemoteException e) {
    338             throw e.rethrowFromSystemServer();
    339         }
    340     }
    341 
    342     /**
    343      * Update the label representing the app being installed in a specific
    344      * session.
    345      *
    346      * @throws SecurityException when the caller does not own the session, or
    347      *             the session is invalid.
    348      */
    349     public void updateSessionAppLabel(int sessionId, @Nullable CharSequence appLabel) {
    350         try {
    351             final String val = (appLabel != null) ? appLabel.toString() : null;
    352             mInstaller.updateSessionAppLabel(sessionId, val);
    353         } catch (RemoteException e) {
    354             throw e.rethrowFromSystemServer();
    355         }
    356     }
    357 
    358     /**
    359      * Completely abandon the given session, destroying all staged data and
    360      * rendering it invalid. Abandoned sessions will be reported to
    361      * {@link SessionCallback} listeners as failures. This is equivalent to
    362      * opening the session and calling {@link Session#abandon()}.
    363      *
    364      * @throws SecurityException when the caller does not own the session, or
    365      *             the session is invalid.
    366      */
    367     public void abandonSession(int sessionId) {
    368         try {
    369             mInstaller.abandonSession(sessionId);
    370         } catch (RemoteException e) {
    371             throw e.rethrowFromSystemServer();
    372         }
    373     }
    374 
    375     /**
    376      * Return details for a specific session. No special permissions are
    377      * required to retrieve these details.
    378      *
    379      * @return details for the requested session, or {@code null} if the session
    380      *         does not exist.
    381      */
    382     public @Nullable SessionInfo getSessionInfo(int sessionId) {
    383         try {
    384             return mInstaller.getSessionInfo(sessionId);
    385         } catch (RemoteException e) {
    386             throw e.rethrowFromSystemServer();
    387         }
    388     }
    389 
    390     /**
    391      * Return list of all known install sessions, regardless of the installer.
    392      */
    393     public @NonNull List<SessionInfo> getAllSessions() {
    394         try {
    395             return mInstaller.getAllSessions(mUserId).getList();
    396         } catch (RemoteException e) {
    397             throw e.rethrowFromSystemServer();
    398         }
    399     }
    400 
    401     /**
    402      * Return list of all known install sessions owned by the calling app.
    403      */
    404     public @NonNull List<SessionInfo> getMySessions() {
    405         try {
    406             return mInstaller.getMySessions(mInstallerPackageName, mUserId).getList();
    407         } catch (RemoteException e) {
    408             throw e.rethrowFromSystemServer();
    409         }
    410     }
    411 
    412     /**
    413      * Uninstall the given package, removing it completely from the device. This
    414      * method is only available to the current "installer of record" for the
    415      * package.
    416      */
    417     public void uninstall(@NonNull String packageName, @NonNull IntentSender statusReceiver) {
    418         try {
    419             mInstaller.uninstall(packageName, mInstallerPackageName, 0, statusReceiver, mUserId);
    420         } catch (RemoteException e) {
    421             throw e.rethrowFromSystemServer();
    422         }
    423     }
    424 
    425     /** {@hide} */
    426     public void setPermissionsResult(int sessionId, boolean accepted) {
    427         try {
    428             mInstaller.setPermissionsResult(sessionId, accepted);
    429         } catch (RemoteException e) {
    430             throw e.rethrowFromSystemServer();
    431         }
    432     }
    433 
    434     /**
    435      * Events for observing session lifecycle.
    436      * <p>
    437      * A typical session lifecycle looks like this:
    438      * <ul>
    439      * <li>An installer creates a session to indicate pending app delivery. All
    440      * install details are available at this point.
    441      * <li>The installer opens the session to deliver APK data. Note that a
    442      * session may be opened and closed multiple times as network connectivity
    443      * changes. The installer may deliver periodic progress updates.
    444      * <li>The installer commits or abandons the session, resulting in the
    445      * session being finished.
    446      * </ul>
    447      */
    448     public static abstract class SessionCallback {
    449         /**
    450          * New session has been created. Details about the session can be
    451          * obtained from {@link PackageInstaller#getSessionInfo(int)}.
    452          */
    453         public abstract void onCreated(int sessionId);
    454 
    455         /**
    456          * Badging details for an existing session has changed. For example, the
    457          * app icon or label has been updated.
    458          */
    459         public abstract void onBadgingChanged(int sessionId);
    460 
    461         /**
    462          * Active state for session has been changed.
    463          * <p>
    464          * A session is considered active whenever there is ongoing forward
    465          * progress being made, such as the installer holding an open
    466          * {@link Session} instance while streaming data into place, or the
    467          * system optimizing code as the result of
    468          * {@link Session#commit(IntentSender)}.
    469          * <p>
    470          * If the installer closes the {@link Session} without committing, the
    471          * session is considered inactive until the installer opens the session
    472          * again.
    473          */
    474         public abstract void onActiveChanged(int sessionId, boolean active);
    475 
    476         /**
    477          * Progress for given session has been updated.
    478          * <p>
    479          * Note that this progress may not directly correspond to the value
    480          * reported by
    481          * {@link PackageInstaller.Session#setStagingProgress(float)}, as the
    482          * system may carve out a portion of the overall progress to represent
    483          * its own internal installation work.
    484          */
    485         public abstract void onProgressChanged(int sessionId, float progress);
    486 
    487         /**
    488          * Session has completely finished, either with success or failure.
    489          */
    490         public abstract void onFinished(int sessionId, boolean success);
    491     }
    492 
    493     /** {@hide} */
    494     private static class SessionCallbackDelegate extends IPackageInstallerCallback.Stub implements
    495             Handler.Callback {
    496         private static final int MSG_SESSION_CREATED = 1;
    497         private static final int MSG_SESSION_BADGING_CHANGED = 2;
    498         private static final int MSG_SESSION_ACTIVE_CHANGED = 3;
    499         private static final int MSG_SESSION_PROGRESS_CHANGED = 4;
    500         private static final int MSG_SESSION_FINISHED = 5;
    501 
    502         final SessionCallback mCallback;
    503         final Handler mHandler;
    504 
    505         public SessionCallbackDelegate(SessionCallback callback, Looper looper) {
    506             mCallback = callback;
    507             mHandler = new Handler(looper, this);
    508         }
    509 
    510         @Override
    511         public boolean handleMessage(Message msg) {
    512             final int sessionId = msg.arg1;
    513             switch (msg.what) {
    514                 case MSG_SESSION_CREATED:
    515                     mCallback.onCreated(sessionId);
    516                     return true;
    517                 case MSG_SESSION_BADGING_CHANGED:
    518                     mCallback.onBadgingChanged(sessionId);
    519                     return true;
    520                 case MSG_SESSION_ACTIVE_CHANGED:
    521                     final boolean active = msg.arg2 != 0;
    522                     mCallback.onActiveChanged(sessionId, active);
    523                     return true;
    524                 case MSG_SESSION_PROGRESS_CHANGED:
    525                     mCallback.onProgressChanged(sessionId, (float) msg.obj);
    526                     return true;
    527                 case MSG_SESSION_FINISHED:
    528                     mCallback.onFinished(sessionId, msg.arg2 != 0);
    529                     return true;
    530             }
    531             return false;
    532         }
    533 
    534         @Override
    535         public void onSessionCreated(int sessionId) {
    536             mHandler.obtainMessage(MSG_SESSION_CREATED, sessionId, 0).sendToTarget();
    537         }
    538 
    539         @Override
    540         public void onSessionBadgingChanged(int sessionId) {
    541             mHandler.obtainMessage(MSG_SESSION_BADGING_CHANGED, sessionId, 0).sendToTarget();
    542         }
    543 
    544         @Override
    545         public void onSessionActiveChanged(int sessionId, boolean active) {
    546             mHandler.obtainMessage(MSG_SESSION_ACTIVE_CHANGED, sessionId, active ? 1 : 0)
    547                     .sendToTarget();
    548         }
    549 
    550         @Override
    551         public void onSessionProgressChanged(int sessionId, float progress) {
    552             mHandler.obtainMessage(MSG_SESSION_PROGRESS_CHANGED, sessionId, 0, progress)
    553                     .sendToTarget();
    554         }
    555 
    556         @Override
    557         public void onSessionFinished(int sessionId, boolean success) {
    558             mHandler.obtainMessage(MSG_SESSION_FINISHED, sessionId, success ? 1 : 0)
    559                     .sendToTarget();
    560         }
    561     }
    562 
    563     /** {@hide} */
    564     @Deprecated
    565     public void addSessionCallback(@NonNull SessionCallback callback) {
    566         registerSessionCallback(callback);
    567     }
    568 
    569     /**
    570      * Register to watch for session lifecycle events. No special permissions
    571      * are required to watch for these events.
    572      */
    573     public void registerSessionCallback(@NonNull SessionCallback callback) {
    574         registerSessionCallback(callback, new Handler());
    575     }
    576 
    577     /** {@hide} */
    578     @Deprecated
    579     public void addSessionCallback(@NonNull SessionCallback callback, @NonNull Handler handler) {
    580         registerSessionCallback(callback, handler);
    581     }
    582 
    583     /**
    584      * Register to watch for session lifecycle events. No special permissions
    585      * are required to watch for these events.
    586      *
    587      * @param handler to dispatch callback events through, otherwise uses
    588      *            calling thread.
    589      */
    590     public void registerSessionCallback(@NonNull SessionCallback callback, @NonNull Handler handler) {
    591         synchronized (mDelegates) {
    592             final SessionCallbackDelegate delegate = new SessionCallbackDelegate(callback,
    593                     handler.getLooper());
    594             try {
    595                 mInstaller.registerCallback(delegate, mUserId);
    596             } catch (RemoteException e) {
    597                 throw e.rethrowFromSystemServer();
    598             }
    599             mDelegates.add(delegate);
    600         }
    601     }
    602 
    603     /** {@hide} */
    604     @Deprecated
    605     public void removeSessionCallback(@NonNull SessionCallback callback) {
    606         unregisterSessionCallback(callback);
    607     }
    608 
    609     /**
    610      * Unregister a previously registered callback.
    611      */
    612     public void unregisterSessionCallback(@NonNull SessionCallback callback) {
    613         synchronized (mDelegates) {
    614             for (Iterator<SessionCallbackDelegate> i = mDelegates.iterator(); i.hasNext();) {
    615                 final SessionCallbackDelegate delegate = i.next();
    616                 if (delegate.mCallback == callback) {
    617                     try {
    618                         mInstaller.unregisterCallback(delegate);
    619                     } catch (RemoteException e) {
    620                         throw e.rethrowFromSystemServer();
    621                     }
    622                     i.remove();
    623                 }
    624             }
    625         }
    626     }
    627 
    628     /**
    629      * An installation that is being actively staged. For an install to succeed,
    630      * all existing and new packages must have identical package names, version
    631      * codes, and signing certificates.
    632      * <p>
    633      * A session may contain any number of split packages. If the application
    634      * does not yet exist, this session must include a base package.
    635      * <p>
    636      * If an APK included in this session is already defined by the existing
    637      * installation (for example, the same split name), the APK in this session
    638      * will replace the existing APK.
    639      */
    640     public static class Session implements Closeable {
    641         private IPackageInstallerSession mSession;
    642 
    643         /** {@hide} */
    644         public Session(IPackageInstallerSession session) {
    645             mSession = session;
    646         }
    647 
    648         /** {@hide} */
    649         @Deprecated
    650         public void setProgress(float progress) {
    651             setStagingProgress(progress);
    652         }
    653 
    654         /**
    655          * Set current progress of staging this session. Valid values are
    656          * anywhere between 0 and 1.
    657          * <p>
    658          * Note that this progress may not directly correspond to the value
    659          * reported by {@link SessionCallback#onProgressChanged(int, float)}, as
    660          * the system may carve out a portion of the overall progress to
    661          * represent its own internal installation work.
    662          */
    663         public void setStagingProgress(float progress) {
    664             try {
    665                 mSession.setClientProgress(progress);
    666             } catch (RemoteException e) {
    667                 throw e.rethrowFromSystemServer();
    668             }
    669         }
    670 
    671         /** {@hide} */
    672         public void addProgress(float progress) {
    673             try {
    674                 mSession.addClientProgress(progress);
    675             } catch (RemoteException e) {
    676                 throw e.rethrowFromSystemServer();
    677             }
    678         }
    679 
    680         /**
    681          * Open a stream to write an APK file into the session.
    682          * <p>
    683          * The returned stream will start writing data at the requested offset
    684          * in the underlying file, which can be used to resume a partially
    685          * written file. If a valid file length is specified, the system will
    686          * preallocate the underlying disk space to optimize placement on disk.
    687          * It's strongly recommended to provide a valid file length when known.
    688          * <p>
    689          * You can write data into the returned stream, optionally call
    690          * {@link #fsync(OutputStream)} as needed to ensure bytes have been
    691          * persisted to disk, and then close when finished. All streams must be
    692          * closed before calling {@link #commit(IntentSender)}.
    693          *
    694          * @param name arbitrary, unique name of your choosing to identify the
    695          *            APK being written. You can open a file again for
    696          *            additional writes (such as after a reboot) by using the
    697          *            same name. This name is only meaningful within the context
    698          *            of a single install session.
    699          * @param offsetBytes offset into the file to begin writing at, or 0 to
    700          *            start at the beginning of the file.
    701          * @param lengthBytes total size of the file being written, used to
    702          *            preallocate the underlying disk space, or -1 if unknown.
    703          *            The system may clear various caches as needed to allocate
    704          *            this space.
    705          * @throws IOException if trouble opening the file for writing, such as
    706          *             lack of disk space or unavailable media.
    707          * @throws SecurityException if called after the session has been
    708          *             committed or abandoned.
    709          */
    710         public @NonNull OutputStream openWrite(@NonNull String name, long offsetBytes,
    711                 long lengthBytes) throws IOException {
    712             try {
    713                 final ParcelFileDescriptor clientSocket = mSession.openWrite(name,
    714                         offsetBytes, lengthBytes);
    715                 return new FileBridge.FileBridgeOutputStream(clientSocket);
    716             } catch (RuntimeException e) {
    717                 ExceptionUtils.maybeUnwrapIOException(e);
    718                 throw e;
    719             } catch (RemoteException e) {
    720                 throw e.rethrowFromSystemServer();
    721             }
    722         }
    723 
    724         /**
    725          * Ensure that any outstanding data for given stream has been committed
    726          * to disk. This is only valid for streams returned from
    727          * {@link #openWrite(String, long, long)}.
    728          */
    729         public void fsync(@NonNull OutputStream out) throws IOException {
    730             if (out instanceof FileBridge.FileBridgeOutputStream) {
    731                 ((FileBridge.FileBridgeOutputStream) out).fsync();
    732             } else {
    733                 throw new IllegalArgumentException("Unrecognized stream");
    734             }
    735         }
    736 
    737         /**
    738          * Return all APK names contained in this session.
    739          * <p>
    740          * This returns all names which have been previously written through
    741          * {@link #openWrite(String, long, long)} as part of this session.
    742          *
    743          * @throws SecurityException if called after the session has been
    744          *             committed or abandoned.
    745          */
    746         public @NonNull String[] getNames() throws IOException {
    747             try {
    748                 return mSession.getNames();
    749             } catch (RuntimeException e) {
    750                 ExceptionUtils.maybeUnwrapIOException(e);
    751                 throw e;
    752             } catch (RemoteException e) {
    753                 throw e.rethrowFromSystemServer();
    754             }
    755         }
    756 
    757         /**
    758          * Open a stream to read an APK file from the session.
    759          * <p>
    760          * This is only valid for names which have been previously written
    761          * through {@link #openWrite(String, long, long)} as part of this
    762          * session. For example, this stream may be used to calculate a
    763          * {@link MessageDigest} of a written APK before committing.
    764          *
    765          * @throws SecurityException if called after the session has been
    766          *             committed or abandoned.
    767          */
    768         public @NonNull InputStream openRead(@NonNull String name) throws IOException {
    769             try {
    770                 final ParcelFileDescriptor pfd = mSession.openRead(name);
    771                 return new ParcelFileDescriptor.AutoCloseInputStream(pfd);
    772             } catch (RuntimeException e) {
    773                 ExceptionUtils.maybeUnwrapIOException(e);
    774                 throw e;
    775             } catch (RemoteException e) {
    776                 throw e.rethrowFromSystemServer();
    777             }
    778         }
    779 
    780         /**
    781          * Removes a split.
    782          * <p>
    783          * Split removals occur prior to adding new APKs. If upgrading a feature
    784          * split, it is not expected nor desirable to remove the split prior to
    785          * upgrading.
    786          * <p>
    787          * When split removal is bundled with new APKs, the packageName must be
    788          * identical.
    789          */
    790         public void removeSplit(@NonNull String splitName) throws IOException {
    791             try {
    792                 mSession.removeSplit(splitName);
    793             } catch (RuntimeException e) {
    794                 ExceptionUtils.maybeUnwrapIOException(e);
    795                 throw e;
    796             } catch (RemoteException e) {
    797                 throw e.rethrowFromSystemServer();
    798             }
    799         }
    800 
    801         /**
    802          * Attempt to commit everything staged in this session. This may require
    803          * user intervention, and so it may not happen immediately. The final
    804          * result of the commit will be reported through the given callback.
    805          * <p>
    806          * Once this method is called, no additional mutations may be performed
    807          * on the session. If the device reboots before the session has been
    808          * finalized, you may commit the session again.
    809          *
    810          * @throws SecurityException if streams opened through
    811          *             {@link #openWrite(String, long, long)} are still open.
    812          */
    813         public void commit(@NonNull IntentSender statusReceiver) {
    814             try {
    815                 mSession.commit(statusReceiver);
    816             } catch (RemoteException e) {
    817                 throw e.rethrowFromSystemServer();
    818             }
    819         }
    820 
    821         /**
    822          * Release this session object. You can open the session again if it
    823          * hasn't been finalized.
    824          */
    825         @Override
    826         public void close() {
    827             try {
    828                 mSession.close();
    829             } catch (RemoteException e) {
    830                 throw e.rethrowFromSystemServer();
    831             }
    832         }
    833 
    834         /**
    835          * Completely abandon this session, destroying all staged data and
    836          * rendering it invalid. Abandoned sessions will be reported to
    837          * {@link SessionCallback} listeners as failures. This is equivalent to
    838          * opening the session and calling {@link Session#abandon()}.
    839          */
    840         public void abandon() {
    841             try {
    842                 mSession.abandon();
    843             } catch (RemoteException e) {
    844                 throw e.rethrowFromSystemServer();
    845             }
    846         }
    847     }
    848 
    849     /**
    850      * Parameters for creating a new {@link PackageInstaller.Session}.
    851      */
    852     public static class SessionParams implements Parcelable {
    853 
    854         /** {@hide} */
    855         public static final int MODE_INVALID = -1;
    856 
    857         /**
    858          * Mode for an install session whose staged APKs should fully replace any
    859          * existing APKs for the target app.
    860          */
    861         public static final int MODE_FULL_INSTALL = 1;
    862 
    863         /**
    864          * Mode for an install session that should inherit any existing APKs for the
    865          * target app, unless they have been explicitly overridden (based on split
    866          * name) by the session. For example, this can be used to add one or more
    867          * split APKs to an existing installation.
    868          * <p>
    869          * If there are no existing APKs for the target app, this behaves like
    870          * {@link #MODE_FULL_INSTALL}.
    871          */
    872         public static final int MODE_INHERIT_EXISTING = 2;
    873 
    874         /** {@hide} */
    875         public static final int UID_UNKNOWN = -1;
    876 
    877         /** {@hide} */
    878         public int mode = MODE_INVALID;
    879         /** {@hide} */
    880         public int installFlags;
    881         /** {@hide} */
    882         public int installLocation = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY;
    883         /** {@hide} */
    884         public long sizeBytes = -1;
    885         /** {@hide} */
    886         public String appPackageName;
    887         /** {@hide} */
    888         public Bitmap appIcon;
    889         /** {@hide} */
    890         public String appLabel;
    891         /** {@hide} */
    892         public long appIconLastModified = -1;
    893         /** {@hide} */
    894         public Uri originatingUri;
    895         /** {@hide} */
    896         public int originatingUid = UID_UNKNOWN;
    897         /** {@hide} */
    898         public Uri referrerUri;
    899         /** {@hide} */
    900         public String abiOverride;
    901         /** {@hide} */
    902         public String volumeUuid;
    903         /** {@hide} */
    904         public String[] grantedRuntimePermissions;
    905 
    906         /**
    907          * Construct parameters for a new package install session.
    908          *
    909          * @param mode one of {@link #MODE_FULL_INSTALL} or
    910          *            {@link #MODE_INHERIT_EXISTING} describing how the session
    911          *            should interact with an existing app.
    912          */
    913         public SessionParams(int mode) {
    914             this.mode = mode;
    915         }
    916 
    917         /** {@hide} */
    918         public SessionParams(Parcel source) {
    919             mode = source.readInt();
    920             installFlags = source.readInt();
    921             installLocation = source.readInt();
    922             sizeBytes = source.readLong();
    923             appPackageName = source.readString();
    924             appIcon = source.readParcelable(null);
    925             appLabel = source.readString();
    926             originatingUri = source.readParcelable(null);
    927             originatingUid = source.readInt();
    928             referrerUri = source.readParcelable(null);
    929             abiOverride = source.readString();
    930             volumeUuid = source.readString();
    931             grantedRuntimePermissions = source.readStringArray();
    932         }
    933 
    934         /**
    935          * Provide value of {@link PackageInfo#installLocation}, which may be used
    936          * to determine where the app will be staged. Defaults to
    937          * {@link PackageInfo#INSTALL_LOCATION_INTERNAL_ONLY}.
    938          */
    939         public void setInstallLocation(int installLocation) {
    940             this.installLocation = installLocation;
    941         }
    942 
    943         /**
    944          * Optionally indicate the total size (in bytes) of all APKs that will be
    945          * delivered in this session. The system may use this to ensure enough disk
    946          * space exists before proceeding, or to estimate container size for
    947          * installations living on external storage.
    948          *
    949          * @see PackageInfo#INSTALL_LOCATION_AUTO
    950          * @see PackageInfo#INSTALL_LOCATION_PREFER_EXTERNAL
    951          */
    952         public void setSize(long sizeBytes) {
    953             this.sizeBytes = sizeBytes;
    954         }
    955 
    956         /**
    957          * Optionally set the package name of the app being installed. It's strongly
    958          * recommended that you provide this value when known, so that observers can
    959          * communicate installing apps to users.
    960          * <p>
    961          * If the APKs staged in the session aren't consistent with this package
    962          * name, the install will fail. Regardless of this value, all APKs in the
    963          * app must have the same package name.
    964          */
    965         public void setAppPackageName(@Nullable String appPackageName) {
    966             this.appPackageName = appPackageName;
    967         }
    968 
    969         /**
    970          * Optionally set an icon representing the app being installed. This should
    971          * be roughly {@link ActivityManager#getLauncherLargeIconSize()} in both
    972          * dimensions.
    973          */
    974         public void setAppIcon(@Nullable Bitmap appIcon) {
    975             this.appIcon = appIcon;
    976         }
    977 
    978         /**
    979          * Optionally set a label representing the app being installed.
    980          */
    981         public void setAppLabel(@Nullable CharSequence appLabel) {
    982             this.appLabel = (appLabel != null) ? appLabel.toString() : null;
    983         }
    984 
    985         /**
    986          * Optionally set the URI where this package was downloaded from. This is
    987          * informational and may be used as a signal for anti-malware purposes.
    988          *
    989          * @see Intent#EXTRA_ORIGINATING_URI
    990          */
    991         public void setOriginatingUri(@Nullable Uri originatingUri) {
    992             this.originatingUri = originatingUri;
    993         }
    994 
    995         /**
    996          * Sets the UID that initiated package installation. This is informational
    997          * and may be used as a signal for anti-malware purposes.
    998          *
    999          * @see PackageManager#EXTRA_VERIFICATION_INSTALLER_UID
   1000          */
   1001         public void setOriginatingUid(int originatingUid) {
   1002             this.originatingUid = originatingUid;
   1003         }
   1004 
   1005         /**
   1006          * Optionally set the URI that referred you to install this package. This is
   1007          * informational and may be used as a signal for anti-malware purposes.
   1008          *
   1009          * @see Intent#EXTRA_REFERRER
   1010          */
   1011         public void setReferrerUri(@Nullable Uri referrerUri) {
   1012             this.referrerUri = referrerUri;
   1013         }
   1014 
   1015         /**
   1016          * Sets which runtime permissions to be granted to the package at installation.
   1017          * Using this API requires holding {@link android.Manifest.permission
   1018          * #INSTALL_GRANT_RUNTIME_PERMISSIONS}
   1019          *
   1020          * @param permissions The permissions to grant or null to grant all runtime
   1021          *     permissions.
   1022          *
   1023          * @hide
   1024          */
   1025         @SystemApi
   1026         @RequiresPermission(android.Manifest.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS)
   1027         public void setGrantedRuntimePermissions(String[] permissions) {
   1028             installFlags |= PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS;
   1029             this.grantedRuntimePermissions = permissions;
   1030         }
   1031 
   1032         /** {@hide} */
   1033         public void setInstallFlagsInternal() {
   1034             installFlags |= PackageManager.INSTALL_INTERNAL;
   1035             installFlags &= ~PackageManager.INSTALL_EXTERNAL;
   1036         }
   1037 
   1038         /** {@hide} */
   1039         @SystemApi
   1040         public void setAllowDowngrade(boolean allowDowngrade) {
   1041             if (allowDowngrade) {
   1042                 installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE;
   1043             } else {
   1044                 installFlags &= ~PackageManager.INSTALL_ALLOW_DOWNGRADE;
   1045             }
   1046         }
   1047 
   1048         /** {@hide} */
   1049         public void setInstallFlagsExternal() {
   1050             installFlags |= PackageManager.INSTALL_EXTERNAL;
   1051             installFlags &= ~PackageManager.INSTALL_INTERNAL;
   1052         }
   1053 
   1054         /** {@hide} */
   1055         public void setInstallFlagsForcePermissionPrompt() {
   1056             installFlags |= PackageManager.INSTALL_FORCE_PERMISSION_PROMPT;
   1057         }
   1058 
   1059         /** {@hide} */
   1060         @SystemApi
   1061         public void setDontKillApp(boolean dontKillApp) {
   1062             if (dontKillApp) {
   1063                 installFlags |= PackageManager.INSTALL_DONT_KILL_APP;
   1064             } else {
   1065                 installFlags &= ~PackageManager.INSTALL_DONT_KILL_APP;
   1066             }
   1067         }
   1068 
   1069         /** {@hide} */
   1070         public void dump(IndentingPrintWriter pw) {
   1071             pw.printPair("mode", mode);
   1072             pw.printHexPair("installFlags", installFlags);
   1073             pw.printPair("installLocation", installLocation);
   1074             pw.printPair("sizeBytes", sizeBytes);
   1075             pw.printPair("appPackageName", appPackageName);
   1076             pw.printPair("appIcon", (appIcon != null));
   1077             pw.printPair("appLabel", appLabel);
   1078             pw.printPair("originatingUri", originatingUri);
   1079             pw.printPair("originatingUid", originatingUid);
   1080             pw.printPair("referrerUri", referrerUri);
   1081             pw.printPair("abiOverride", abiOverride);
   1082             pw.printPair("volumeUuid", volumeUuid);
   1083             pw.printPair("grantedRuntimePermissions", grantedRuntimePermissions);
   1084             pw.println();
   1085         }
   1086 
   1087         @Override
   1088         public int describeContents() {
   1089             return 0;
   1090         }
   1091 
   1092         @Override
   1093         public void writeToParcel(Parcel dest, int flags) {
   1094             dest.writeInt(mode);
   1095             dest.writeInt(installFlags);
   1096             dest.writeInt(installLocation);
   1097             dest.writeLong(sizeBytes);
   1098             dest.writeString(appPackageName);
   1099             dest.writeParcelable(appIcon, flags);
   1100             dest.writeString(appLabel);
   1101             dest.writeParcelable(originatingUri, flags);
   1102             dest.writeInt(originatingUid);
   1103             dest.writeParcelable(referrerUri, flags);
   1104             dest.writeString(abiOverride);
   1105             dest.writeString(volumeUuid);
   1106             dest.writeStringArray(grantedRuntimePermissions);
   1107         }
   1108 
   1109         public static final Parcelable.Creator<SessionParams>
   1110                 CREATOR = new Parcelable.Creator<SessionParams>() {
   1111                     @Override
   1112                     public SessionParams createFromParcel(Parcel p) {
   1113                         return new SessionParams(p);
   1114                     }
   1115 
   1116                     @Override
   1117                     public SessionParams[] newArray(int size) {
   1118                         return new SessionParams[size];
   1119                     }
   1120                 };
   1121     }
   1122 
   1123     /**
   1124      * Details for an active install session.
   1125      */
   1126     public static class SessionInfo implements Parcelable {
   1127 
   1128         /** {@hide} */
   1129         public int sessionId;
   1130         /** {@hide} */
   1131         public String installerPackageName;
   1132         /** {@hide} */
   1133         public String resolvedBaseCodePath;
   1134         /** {@hide} */
   1135         public float progress;
   1136         /** {@hide} */
   1137         public boolean sealed;
   1138         /** {@hide} */
   1139         public boolean active;
   1140 
   1141         /** {@hide} */
   1142         public int mode;
   1143         /** {@hide} */
   1144         public long sizeBytes;
   1145         /** {@hide} */
   1146         public String appPackageName;
   1147         /** {@hide} */
   1148         public Bitmap appIcon;
   1149         /** {@hide} */
   1150         public CharSequence appLabel;
   1151 
   1152         /** {@hide} */
   1153         public SessionInfo() {
   1154         }
   1155 
   1156         /** {@hide} */
   1157         public SessionInfo(Parcel source) {
   1158             sessionId = source.readInt();
   1159             installerPackageName = source.readString();
   1160             resolvedBaseCodePath = source.readString();
   1161             progress = source.readFloat();
   1162             sealed = source.readInt() != 0;
   1163             active = source.readInt() != 0;
   1164 
   1165             mode = source.readInt();
   1166             sizeBytes = source.readLong();
   1167             appPackageName = source.readString();
   1168             appIcon = source.readParcelable(null);
   1169             appLabel = source.readString();
   1170         }
   1171 
   1172         /**
   1173          * Return the ID for this session.
   1174          */
   1175         public int getSessionId() {
   1176             return sessionId;
   1177         }
   1178 
   1179         /**
   1180          * Return the package name of the app that owns this session.
   1181          */
   1182         public @Nullable String getInstallerPackageName() {
   1183             return installerPackageName;
   1184         }
   1185 
   1186         /**
   1187          * Return current overall progress of this session, between 0 and 1.
   1188          * <p>
   1189          * Note that this progress may not directly correspond to the value
   1190          * reported by
   1191          * {@link PackageInstaller.Session#setStagingProgress(float)}, as the
   1192          * system may carve out a portion of the overall progress to represent
   1193          * its own internal installation work.
   1194          */
   1195         public float getProgress() {
   1196             return progress;
   1197         }
   1198 
   1199         /**
   1200          * Return if this session is currently active.
   1201          * <p>
   1202          * A session is considered active whenever there is ongoing forward
   1203          * progress being made, such as the installer holding an open
   1204          * {@link Session} instance while streaming data into place, or the
   1205          * system optimizing code as the result of
   1206          * {@link Session#commit(IntentSender)}.
   1207          * <p>
   1208          * If the installer closes the {@link Session} without committing, the
   1209          * session is considered inactive until the installer opens the session
   1210          * again.
   1211          */
   1212         public boolean isActive() {
   1213             return active;
   1214         }
   1215 
   1216         /** {@hide} */
   1217         @Deprecated
   1218         public boolean isOpen() {
   1219             return isActive();
   1220         }
   1221 
   1222         /**
   1223          * Return the package name this session is working with. May be {@code null}
   1224          * if unknown.
   1225          */
   1226         public @Nullable String getAppPackageName() {
   1227             return appPackageName;
   1228         }
   1229 
   1230         /**
   1231          * Return an icon representing the app being installed. May be {@code null}
   1232          * if unavailable.
   1233          */
   1234         public @Nullable Bitmap getAppIcon() {
   1235             return appIcon;
   1236         }
   1237 
   1238         /**
   1239          * Return a label representing the app being installed. May be {@code null}
   1240          * if unavailable.
   1241          */
   1242         public @Nullable CharSequence getAppLabel() {
   1243             return appLabel;
   1244         }
   1245 
   1246         /**
   1247          * Return an Intent that can be started to view details about this install
   1248          * session. This may surface actions such as pause, resume, or cancel.
   1249          * <p>
   1250          * In some cases, a matching Activity may not exist, so ensure you safeguard
   1251          * against this.
   1252          *
   1253          * @see PackageInstaller#ACTION_SESSION_DETAILS
   1254          */
   1255         public @Nullable Intent createDetailsIntent() {
   1256             final Intent intent = new Intent(PackageInstaller.ACTION_SESSION_DETAILS);
   1257             intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
   1258             intent.setPackage(installerPackageName);
   1259             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
   1260             return intent;
   1261         }
   1262 
   1263         /** {@hide} */
   1264         @Deprecated
   1265         public @Nullable Intent getDetailsIntent() {
   1266             return createDetailsIntent();
   1267         }
   1268 
   1269         @Override
   1270         public int describeContents() {
   1271             return 0;
   1272         }
   1273 
   1274         @Override
   1275         public void writeToParcel(Parcel dest, int flags) {
   1276             dest.writeInt(sessionId);
   1277             dest.writeString(installerPackageName);
   1278             dest.writeString(resolvedBaseCodePath);
   1279             dest.writeFloat(progress);
   1280             dest.writeInt(sealed ? 1 : 0);
   1281             dest.writeInt(active ? 1 : 0);
   1282 
   1283             dest.writeInt(mode);
   1284             dest.writeLong(sizeBytes);
   1285             dest.writeString(appPackageName);
   1286             dest.writeParcelable(appIcon, flags);
   1287             dest.writeString(appLabel != null ? appLabel.toString() : null);
   1288         }
   1289 
   1290         public static final Parcelable.Creator<SessionInfo>
   1291                 CREATOR = new Parcelable.Creator<SessionInfo>() {
   1292                     @Override
   1293                     public SessionInfo createFromParcel(Parcel p) {
   1294                         return new SessionInfo(p);
   1295                     }
   1296 
   1297                     @Override
   1298                     public SessionInfo[] newArray(int size) {
   1299                         return new SessionInfo[size];
   1300                     }
   1301                 };
   1302     }
   1303 }
   1304