PackageInstaller.java revision 5d74493f64493cd506d7458b810095259287f623
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
17package android.content.pm;
18
19import android.Manifest;
20import android.annotation.NonNull;
21import android.annotation.Nullable;
22import android.annotation.RequiresPermission;
23import android.annotation.SdkConstant;
24import android.annotation.SdkConstant.SdkConstantType;
25import android.annotation.SystemApi;
26import android.app.ActivityManager;
27import android.app.AppGlobals;
28import android.content.Intent;
29import android.content.IntentSender;
30import android.content.pm.PackageManager.DeleteFlags;
31import android.content.pm.PackageManager.InstallReason;
32import android.graphics.Bitmap;
33import android.net.Uri;
34import android.os.FileBridge;
35import android.os.Handler;
36import android.os.Looper;
37import android.os.Message;
38import android.os.Parcel;
39import android.os.ParcelFileDescriptor;
40import android.os.Parcelable;
41import android.os.ParcelableException;
42import android.os.RemoteException;
43import android.os.SystemProperties;
44import android.system.ErrnoException;
45import android.system.Os;
46import android.util.ExceptionUtils;
47
48import com.android.internal.util.IndentingPrintWriter;
49import com.android.internal.util.Preconditions;
50
51import java.io.Closeable;
52import java.io.IOException;
53import java.io.InputStream;
54import java.io.OutputStream;
55import java.security.MessageDigest;
56import java.util.ArrayList;
57import java.util.Iterator;
58import 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 */
85public 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