blob: 0304f19cc5b465ba826d2075369057f388bb6a00 [file] [log] [blame]
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001/*
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
Svet Ganov67882122016-12-11 16:36:34 -080019import android.Manifest;
Dario Freni71eee5e2018-12-06 15:47:16 +000020import android.annotation.IntDef;
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -070021import android.annotation.NonNull;
22import android.annotation.Nullable;
Svet Ganov7121e182015-07-13 22:38:12 -070023import android.annotation.RequiresPermission;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070024import android.annotation.SdkConstant;
25import android.annotation.SdkConstant.SdkConstantType;
Svet Ganov7121e182015-07-13 22:38:12 -070026import android.annotation.SystemApi;
Mathew Inwood5c0d3542018-08-14 13:54:31 +010027import android.annotation.UnsupportedAppUsage;
Jeff Sharkeya0907432014-08-15 10:23:11 -070028import android.app.ActivityManager;
Jeff Sharkeyda1247a2017-06-08 14:13:29 -060029import android.app.AppGlobals;
Jeff Sharkeyfbd0e9f2014-08-06 16:34:34 -070030import android.content.Intent;
Jeff Sharkeya0907432014-08-15 10:23:11 -070031import android.content.IntentSender;
Todd Kennedycda831f2017-05-16 10:54:33 -070032import android.content.pm.PackageManager.DeleteFlags;
Bartosz Fabianowski40a00622017-04-18 14:39:23 +020033import android.content.pm.PackageManager.InstallReason;
Jeff Sharkeya0907432014-08-15 10:23:11 -070034import android.graphics.Bitmap;
35import android.net.Uri;
Mathew Inwood8c854f82018-09-14 12:35:36 +010036import android.os.Build;
Jeff Sharkey78cc3402014-05-22 10:52:49 -070037import android.os.FileBridge;
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -070038import android.os.Handler;
Jon Miranda2b340a22019-01-25 14:03:49 -080039import android.os.HandlerExecutor;
Jeff Sharkeya0907432014-08-15 10:23:11 -070040import android.os.Parcel;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070041import android.os.ParcelFileDescriptor;
Jeff Sharkeya0907432014-08-15 10:23:11 -070042import android.os.Parcelable;
Philip P. Moltmann7460c592017-08-08 20:07:11 +000043import android.os.ParcelableException;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070044import android.os.RemoteException;
Jeff Sharkey02d4e342017-03-10 21:53:48 -070045import android.os.SystemProperties;
Jon Miranda2b340a22019-01-25 14:03:49 -080046import android.os.UserHandle;
Jeff Sharkey02d4e342017-03-10 21:53:48 -070047import android.system.ErrnoException;
48import android.system.Os;
Jeff Sharkeya1031142014-07-12 18:09:46 -070049import android.util.ExceptionUtils;
Jeff Sharkeya0907432014-08-15 10:23:11 -070050
51import com.android.internal.util.IndentingPrintWriter;
Svet Ganov67882122016-12-11 16:36:34 -080052import com.android.internal.util.Preconditions;
Jon Miranda2b340a22019-01-25 14:03:49 -080053import com.android.internal.util.function.pooled.PooledLambda;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070054
Jeff Sharkeyec55ef02014-07-08 11:28:00 -070055import java.io.Closeable;
Jeff Sharkeya1031142014-07-12 18:09:46 -070056import java.io.IOException;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070057import java.io.InputStream;
Jeff Sharkey78cc3402014-05-22 10:52:49 -070058import java.io.OutputStream;
Dario Freni71eee5e2018-12-06 15:47:16 +000059import java.lang.annotation.Retention;
60import java.lang.annotation.RetentionPolicy;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070061import java.security.MessageDigest;
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -070062import java.util.ArrayList;
63import java.util.Iterator;
Jeff Sharkeybb580672014-07-10 12:10:25 -070064import java.util.List;
Jon Miranda2b340a22019-01-25 14:03:49 -080065import java.util.concurrent.Executor;
Jeff Sharkey78cc3402014-05-22 10:52:49 -070066
Jeff Sharkey6c833e02014-07-14 22:44:30 -070067/**
68 * Offers the ability to install, upgrade, and remove applications on the
69 * device. This includes support for apps packaged either as a single
70 * "monolithic" APK, or apps packaged as multiple "split" APKs.
71 * <p>
72 * An app is delivered for installation through a
73 * {@link PackageInstaller.Session}, which any app can create. Once the session
74 * is created, the installer can stream one or more APKs into place until it
75 * decides to either commit or destroy the session. Committing may require user
Rubin Xufd4a3b42018-12-05 16:03:27 +000076 * intervention to complete the installation, unless the caller falls into one of the
77 * following categories, in which case the installation will complete automatically.
78 * <ul>
79 * <li>the device owner
80 * <li>the affiliated profile owner
81 * <li>the device owner delegated app with
82 * {@link android.app.admin.DevicePolicyManager#DELEGATION_PACKAGE_INSTALLATION}
83 * </ul>
Jeff Sharkey6c833e02014-07-14 22:44:30 -070084 * <p>
85 * Sessions can install brand new apps, upgrade existing apps, or add new splits
Jeff Sharkeyda96e132014-07-15 14:54:09 -070086 * into an existing app.
Jeff Sharkey6c833e02014-07-14 22:44:30 -070087 * <p>
Jeff Sharkeyda96e132014-07-15 14:54:09 -070088 * Apps packaged as multiple split APKs always consist of a single "base" APK
Jeff Sharkey6c833e02014-07-14 22:44:30 -070089 * (with a {@code null} split name) and zero or more "split" APKs (with unique
90 * split names). Any subset of these APKs can be installed together, as long as
91 * the following constraints are met:
92 * <ul>
93 * <li>All APKs must have the exact same package name, version code, and signing
94 * certificates.
Jeff Sharkey6c833e02014-07-14 22:44:30 -070095 * <li>All APKs must have unique split names.
Jeff Sharkeyda96e132014-07-15 14:54:09 -070096 * <li>All installations must contain a single base APK.
Jeff Sharkey6c833e02014-07-14 22:44:30 -070097 * </ul>
Peter Visontayf702fd42017-11-17 14:00:47 +000098 * <p>
99 * The ApiDemos project contains examples of using this API:
100 * <code>ApiDemos/src/com/example/android/apis/content/InstallApk*.java</code>.
Ricky Waic5ea08b2018-09-05 20:55:11 +0100101 * <p>
102 * On Android Q or above, an app installed notification will be posted
103 * by system after a new app is installed.
104 * To customize installer's notification icon, you should declare the following in the manifest
105 * &lt;application> as follows: </p>
106 * <pre>
107 * &lt;meta-data android:name="com.android.packageinstaller.notification.smallIcon"
108 * android:resource="@drawable/installer_notification_icon"/>
109 * </pre>
110 * <pre>
111 * &lt;meta-data android:name="com.android.packageinstaller.notification.color"
112 * android:resource="@color/installer_notification_color"/>
113 * </pre>
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700114 */
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700115public class PackageInstaller {
Jeff Sharkeya0907432014-08-15 10:23:11 -0700116 private static final String TAG = "PackageInstaller";
117
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700118 /** {@hide} */
119 public static final boolean ENABLE_REVOCABLE_FD =
120 SystemProperties.getBoolean("fw.revocable_fd", false);
121
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700122 /**
123 * Activity Action: Show details about a particular install session. This
124 * may surface actions such as pause, resume, or cancel.
125 * <p>
126 * This should always be scoped to the installer package that owns the
Jeff Sharkeyde742312014-09-15 14:04:56 -0700127 * session. Clients should use {@link SessionInfo#createDetailsIntent()} to
Jeff Sharkeya0907432014-08-15 10:23:11 -0700128 * build this intent correctly.
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700129 * <p>
130 * In some cases, a matching Activity may not exist, so ensure you safeguard
131 * against this.
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700132 * <p>
133 * The session to show details for is defined in {@link #EXTRA_SESSION_ID}.
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700134 */
135 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
136 public static final String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS";
137
Sunny Goyal6d7cb232017-01-30 10:43:18 -0800138 /**
139 * Broadcast Action: Explicit broadcast sent to the last known default launcher when a session
140 * for a new install is committed. For managed profile, this is sent to the default launcher
141 * of the primary profile.
142 * <p>
143 * The associated session is defined in {@link #EXTRA_SESSION} and the user for which this
144 * session was created in {@link Intent#EXTRA_USER}.
145 */
146 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
147 public static final String ACTION_SESSION_COMMITTED =
148 "android.content.pm.action.SESSION_COMMITTED";
149
Dario Frenie487ea22018-12-12 15:41:59 +0000150 /**
151 * Broadcast Action: Send information about a staged install session when its state is updated.
152 * <p>
153 * The associated session information is defined in {@link #EXTRA_SESSION}.
154 */
155 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
156 public static final String ACTION_SESSION_UPDATED =
157 "android.content.pm.action.SESSION_UPDATED";
158
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700159 /** {@hide} */
Philip P. Moltmanne8fe3cb2018-07-23 14:27:11 -0700160 public static final String ACTION_CONFIRM_INSTALL = "android.content.pm.action.CONFIRM_INSTALL";
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700161
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700162 /**
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700163 * An integer session ID that an operation is working with.
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700164 *
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700165 * @see Intent#getIntExtra(String, int)
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700166 */
167 public static final String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID";
168
Jeff Sharkeya0907432014-08-15 10:23:11 -0700169 /**
Sunny Goyal6d7cb232017-01-30 10:43:18 -0800170 * {@link SessionInfo} that an operation is working with.
171 *
172 * @see Intent#getParcelableExtra(String)
173 */
174 public static final String EXTRA_SESSION = "android.content.pm.extra.SESSION";
175
176 /**
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700177 * Package name that an operation is working with.
Jeff Sharkeya0907432014-08-15 10:23:11 -0700178 *
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700179 * @see Intent#getStringExtra(String)
Jeff Sharkeya0907432014-08-15 10:23:11 -0700180 */
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700181 public static final String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME";
182
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700183 /**
184 * Current status of an operation. Will be one of
185 * {@link #STATUS_PENDING_USER_ACTION}, {@link #STATUS_SUCCESS},
186 * {@link #STATUS_FAILURE}, {@link #STATUS_FAILURE_ABORTED},
187 * {@link #STATUS_FAILURE_BLOCKED}, {@link #STATUS_FAILURE_CONFLICT},
188 * {@link #STATUS_FAILURE_INCOMPATIBLE}, {@link #STATUS_FAILURE_INVALID}, or
189 * {@link #STATUS_FAILURE_STORAGE}.
190 * <p>
191 * More information about a status may be available through additional
192 * extras; see the individual status documentation for details.
193 *
194 * @see Intent#getIntExtra(String, int)
195 */
196 public static final String EXTRA_STATUS = "android.content.pm.extra.STATUS";
197
198 /**
199 * Detailed string representation of the status, including raw details that
200 * are useful for debugging.
201 *
202 * @see Intent#getStringExtra(String)
203 */
204 public static final String EXTRA_STATUS_MESSAGE = "android.content.pm.extra.STATUS_MESSAGE";
205
206 /**
207 * Another package name relevant to a status. This is typically the package
208 * responsible for causing an operation failure.
209 *
210 * @see Intent#getStringExtra(String)
211 */
212 public static final String
213 EXTRA_OTHER_PACKAGE_NAME = "android.content.pm.extra.OTHER_PACKAGE_NAME";
214
215 /**
216 * Storage path relevant to a status.
217 *
218 * @see Intent#getStringExtra(String)
219 */
220 public static final String EXTRA_STORAGE_PATH = "android.content.pm.extra.STORAGE_PATH";
221
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700222 /** {@hide} */
223 @Deprecated
Jeff Sharkeya0907432014-08-15 10:23:11 -0700224 public static final String EXTRA_PACKAGE_NAMES = "android.content.pm.extra.PACKAGE_NAMES";
225
226 /** {@hide} */
227 public static final String EXTRA_LEGACY_STATUS = "android.content.pm.extra.LEGACY_STATUS";
228 /** {@hide} */
229 public static final String EXTRA_LEGACY_BUNDLE = "android.content.pm.extra.LEGACY_BUNDLE";
Jeff Sharkeyf0600952014-08-07 17:31:53 -0700230 /** {@hide} */
231 public static final String EXTRA_CALLBACK = "android.content.pm.extra.CALLBACK";
232
Jeff Sharkeya0907432014-08-15 10:23:11 -0700233 /**
234 * User action is currently required to proceed. You can launch the intent
235 * activity described by {@link Intent#EXTRA_INTENT} to involve the user and
236 * continue.
237 * <p>
238 * You may choose to immediately launch the intent if the user is actively
239 * using your app. Otherwise, you should use a notification to guide the
240 * user back into your app before launching.
241 *
242 * @see Intent#getParcelableExtra(String)
243 */
Jeff Sharkey742e7902014-08-16 19:09:13 -0700244 public static final int STATUS_PENDING_USER_ACTION = -1;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700245
246 /**
247 * The operation succeeded.
248 */
249 public static final int STATUS_SUCCESS = 0;
250
251 /**
252 * The operation failed in a generic way. The system will always try to
253 * provide a more specific failure reason, but in some rare cases this may
254 * be delivered.
255 *
256 * @see #EXTRA_STATUS_MESSAGE
257 */
258 public static final int STATUS_FAILURE = 1;
259
260 /**
261 * The operation failed because it was blocked. For example, a device policy
262 * may be blocking the operation, a package verifier may have blocked the
263 * operation, or the app may be required for core system operation.
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700264 * <p>
265 * The result may also contain {@link #EXTRA_OTHER_PACKAGE_NAME} with the
266 * specific package blocking the install.
Jeff Sharkeya0907432014-08-15 10:23:11 -0700267 *
268 * @see #EXTRA_STATUS_MESSAGE
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700269 * @see #EXTRA_OTHER_PACKAGE_NAME
Jeff Sharkeya0907432014-08-15 10:23:11 -0700270 */
Jeff Sharkey742e7902014-08-16 19:09:13 -0700271 public static final int STATUS_FAILURE_BLOCKED = 2;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700272
273 /**
274 * The operation failed because it was actively aborted. For example, the
275 * user actively declined requested permissions, or the session was
276 * abandoned.
277 *
278 * @see #EXTRA_STATUS_MESSAGE
279 */
Jeff Sharkey742e7902014-08-16 19:09:13 -0700280 public static final int STATUS_FAILURE_ABORTED = 3;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700281
282 /**
283 * The operation failed because one or more of the APKs was invalid. For
284 * example, they might be malformed, corrupt, incorrectly signed,
285 * mismatched, etc.
286 *
287 * @see #EXTRA_STATUS_MESSAGE
288 */
Jeff Sharkey742e7902014-08-16 19:09:13 -0700289 public static final int STATUS_FAILURE_INVALID = 4;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700290
291 /**
292 * The operation failed because it conflicts (or is inconsistent with) with
293 * another package already installed on the device. For example, an existing
294 * permission, incompatible certificates, etc. The user may be able to
295 * uninstall another app to fix the issue.
296 * <p>
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700297 * The result may also contain {@link #EXTRA_OTHER_PACKAGE_NAME} with the
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700298 * specific package identified as the cause of the conflict.
Jeff Sharkeya0907432014-08-15 10:23:11 -0700299 *
300 * @see #EXTRA_STATUS_MESSAGE
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700301 * @see #EXTRA_OTHER_PACKAGE_NAME
Jeff Sharkeya0907432014-08-15 10:23:11 -0700302 */
Jeff Sharkey742e7902014-08-16 19:09:13 -0700303 public static final int STATUS_FAILURE_CONFLICT = 5;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700304
305 /**
306 * The operation failed because of storage issues. For example, the device
307 * may be running low on space, or external media may be unavailable. The
308 * user may be able to help free space or insert different external media.
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700309 * <p>
310 * The result may also contain {@link #EXTRA_STORAGE_PATH} with the path to
311 * the storage device that caused the failure.
Jeff Sharkeya0907432014-08-15 10:23:11 -0700312 *
313 * @see #EXTRA_STATUS_MESSAGE
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700314 * @see #EXTRA_STORAGE_PATH
Jeff Sharkeya0907432014-08-15 10:23:11 -0700315 */
Jeff Sharkey742e7902014-08-16 19:09:13 -0700316 public static final int STATUS_FAILURE_STORAGE = 6;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700317
318 /**
319 * The operation failed because it is fundamentally incompatible with this
320 * device. For example, the app may require a hardware feature that doesn't
321 * exist, it may be missing native code for the ABIs supported by the
322 * device, or it requires a newer SDK version, etc.
323 *
324 * @see #EXTRA_STATUS_MESSAGE
325 */
Jeff Sharkey742e7902014-08-16 19:09:13 -0700326 public static final int STATUS_FAILURE_INCOMPATIBLE = 7;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700327
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700328 private final IPackageInstaller mInstaller;
329 private final int mUserId;
330 private final String mInstallerPackageName;
331
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700332 private final ArrayList<SessionCallbackDelegate> mDelegates = new ArrayList<>();
333
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700334 /** {@hide} */
Svet Ganov67882122016-12-11 16:36:34 -0800335 public PackageInstaller(IPackageInstaller installer,
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700336 String installerPackageName, int userId) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700337 mInstaller = installer;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700338 mInstallerPackageName = installerPackageName;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700339 mUserId = userId;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700340 }
341
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700342 /**
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700343 * Create a new session using the given parameters, returning a unique ID
344 * that represents the session. Once created, the session can be opened
345 * multiple times across multiple device boots.
346 * <p>
347 * The system may automatically destroy sessions that have not been
348 * finalized (either committed or abandoned) within a reasonable period of
349 * time, typically on the order of a day.
350 *
351 * @throws IOException if parameters were unsatisfiable, such as lack of
352 * disk space or unavailable media.
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700353 * @throws SecurityException when installation services are unavailable,
354 * such as when called from a restricted user.
355 * @throws IllegalArgumentException when {@link SessionParams} is invalid.
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700356 * @return positive, non-zero unique ID that represents the created session.
357 * This ID remains consistent across device reboots until the
358 * session is finalized. IDs are not reused during a given boot.
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700359 */
Jeff Sharkeya0907432014-08-15 10:23:11 -0700360 public int createSession(@NonNull SessionParams params) throws IOException {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700361 try {
Philip P. Moltmann79c238a2017-12-13 15:59:07 -0800362 final String installerPackage;
363 if (params.installerPackageName == null) {
364 installerPackage = mInstallerPackageName;
365 } else {
366 installerPackage = params.installerPackageName;
367 }
368
369 return mInstaller.createSession(params, installerPackage, mUserId);
Jeff Sharkeya1031142014-07-12 18:09:46 -0700370 } catch (RuntimeException e) {
371 ExceptionUtils.maybeUnwrapIOException(e);
372 throw e;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700373 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700374 throw e.rethrowFromSystemServer();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700375 }
376 }
377
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700378 /**
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700379 * Open an existing session to actively perform work. To succeed, the caller
380 * must be the owner of the install session.
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700381 *
382 * @throws IOException if parameters were unsatisfiable, such as lack of
383 * disk space or unavailable media.
384 * @throws SecurityException when the caller does not own the session, or
385 * the session is invalid.
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700386 */
Jeff Sharkeybc7bce32014-09-05 15:53:05 -0700387 public @NonNull Session openSession(int sessionId) throws IOException {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700388 try {
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000389 try {
390 return new Session(mInstaller.openSession(sessionId));
391 } catch (RemoteException e) {
392 throw e.rethrowFromSystemServer();
393 }
Jeff Sharkeybc7bce32014-09-05 15:53:05 -0700394 } catch (RuntimeException e) {
395 ExceptionUtils.maybeUnwrapIOException(e);
396 throw e;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700397 }
398 }
399
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700400 /**
401 * Update the icon representing the app being installed in a specific
402 * session. This should be roughly
403 * {@link ActivityManager#getLauncherLargeIconSize()} in both dimensions.
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700404 *
405 * @throws SecurityException when the caller does not own the session, or
406 * the session is invalid.
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700407 */
408 public void updateSessionAppIcon(int sessionId, @Nullable Bitmap appIcon) {
409 try {
410 mInstaller.updateSessionAppIcon(sessionId, appIcon);
411 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700412 throw e.rethrowFromSystemServer();
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700413 }
414 }
415
416 /**
417 * Update the label representing the app being installed in a specific
418 * session.
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700419 *
420 * @throws SecurityException when the caller does not own the session, or
421 * the session is invalid.
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700422 */
423 public void updateSessionAppLabel(int sessionId, @Nullable CharSequence appLabel) {
424 try {
425 final String val = (appLabel != null) ? appLabel.toString() : null;
426 mInstaller.updateSessionAppLabel(sessionId, val);
427 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700428 throw e.rethrowFromSystemServer();
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700429 }
430 }
431
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700432 /**
433 * Completely abandon the given session, destroying all staged data and
434 * rendering it invalid. Abandoned sessions will be reported to
435 * {@link SessionCallback} listeners as failures. This is equivalent to
436 * opening the session and calling {@link Session#abandon()}.
437 *
438 * @throws SecurityException when the caller does not own the session, or
439 * the session is invalid.
440 */
Jeff Sharkey381d94b2014-08-24 14:45:56 -0700441 public void abandonSession(int sessionId) {
442 try {
443 mInstaller.abandonSession(sessionId);
444 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700445 throw e.rethrowFromSystemServer();
Jeff Sharkey381d94b2014-08-24 14:45:56 -0700446 }
447 }
448
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700449 /**
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700450 * Return details for a specific session. No special permissions are
451 * required to retrieve these details.
452 *
453 * @return details for the requested session, or {@code null} if the session
454 * does not exist.
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700455 */
Jeff Sharkeya0907432014-08-15 10:23:11 -0700456 public @Nullable SessionInfo getSessionInfo(int sessionId) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700457 try {
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700458 return mInstaller.getSessionInfo(sessionId);
459 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700460 throw e.rethrowFromSystemServer();
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700461 }
462 }
463
464 /**
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700465 * Return list of all known install sessions, regardless of the installer.
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700466 */
Jeff Sharkeya0907432014-08-15 10:23:11 -0700467 public @NonNull List<SessionInfo> getAllSessions() {
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700468 try {
Jeff Sharkey97d47ed2014-10-15 09:19:47 -0700469 return mInstaller.getAllSessions(mUserId).getList();
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700470 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700471 throw e.rethrowFromSystemServer();
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700472 }
473 }
474
475 /**
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700476 * Return list of all known install sessions owned by the calling app.
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700477 */
Jeff Sharkeya0907432014-08-15 10:23:11 -0700478 public @NonNull List<SessionInfo> getMySessions() {
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700479 try {
Jeff Sharkey97d47ed2014-10-15 09:19:47 -0700480 return mInstaller.getMySessions(mInstallerPackageName, mUserId).getList();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700481 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700482 throw e.rethrowFromSystemServer();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700483 }
484 }
485
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700486 /**
Dario Freniaac4ba42018-12-06 15:47:16 +0000487 * Return list of all staged install sessions.
488 */
489 public @NonNull List<SessionInfo> getStagedSessions() {
490 try {
491 // TODO: limit this to the mUserId?
492 return mInstaller.getStagedSessions().getList();
493 } catch (RemoteException e) {
494 throw e.rethrowFromSystemServer();
495 }
496 }
497
498 /**
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700499 * Uninstall the given package, removing it completely from the device. This
Tony Mak366ee622018-02-12 17:52:34 +0000500 * method is available to:
501 * <ul>
502 * <li>the current "installer of record" for the package
503 * <li>the device owner
504 * <li>the affiliated profile owner
Rubin Xufd4a3b42018-12-05 16:03:27 +0000505 * <li>the device owner delegated app with
506 * {@link android.app.admin.DevicePolicyManager#DELEGATION_PACKAGE_INSTALLATION}
Tony Mak366ee622018-02-12 17:52:34 +0000507 * </ul>
Svet Ganov67882122016-12-11 16:36:34 -0800508 *
509 * @param packageName The package to uninstall.
510 * @param statusReceiver Where to deliver the result.
Tony Mak366ee622018-02-12 17:52:34 +0000511 *
512 * @see android.app.admin.DevicePolicyManager
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700513 */
Philip P. Moltmannd9bb39a2017-09-05 12:41:15 -0700514 @RequiresPermission(anyOf = {
515 Manifest.permission.DELETE_PACKAGES,
516 Manifest.permission.REQUEST_DELETE_PACKAGES})
Jeff Sharkeya0907432014-08-15 10:23:11 -0700517 public void uninstall(@NonNull String packageName, @NonNull IntentSender statusReceiver) {
Todd Kennedycda831f2017-05-16 10:54:33 -0700518 uninstall(packageName, 0 /*flags*/, statusReceiver);
519 }
520
521 /**
522 * Uninstall the given package, removing it completely from the device. This
523 * method is only available to the current "installer of record" for the
524 * package.
525 *
526 * @param packageName The package to uninstall.
527 * @param flags Flags for uninstall.
528 * @param statusReceiver Where to deliver the result.
529 *
530 * @hide
531 */
532 public void uninstall(@NonNull String packageName, @DeleteFlags int flags,
533 @NonNull IntentSender statusReceiver) {
534 uninstall(new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST),
535 flags, statusReceiver);
Svet Ganov67882122016-12-11 16:36:34 -0800536 }
537
538 /**
539 * Uninstall the given package with a specific version code, removing it
Tony Mak366ee622018-02-12 17:52:34 +0000540 * completely from the device. If the version code of the package
Svet Ganov67882122016-12-11 16:36:34 -0800541 * does not match the one passed in the versioned package argument this
542 * method is a no-op. Use {@link PackageManager#VERSION_CODE_HIGHEST} to
543 * uninstall the latest version of the package.
Tony Mak366ee622018-02-12 17:52:34 +0000544 * <p>
545 * This method is available to:
546 * <ul>
547 * <li>the current "installer of record" for the package
548 * <li>the device owner
549 * <li>the affiliated profile owner
550 * </ul>
Svet Ganov67882122016-12-11 16:36:34 -0800551 *
552 * @param versionedPackage The versioned package to uninstall.
553 * @param statusReceiver Where to deliver the result.
Tony Mak366ee622018-02-12 17:52:34 +0000554 *
555 * @see android.app.admin.DevicePolicyManager
Svet Ganov67882122016-12-11 16:36:34 -0800556 */
Philip P. Moltmannd9bb39a2017-09-05 12:41:15 -0700557 @RequiresPermission(anyOf = {
558 Manifest.permission.DELETE_PACKAGES,
559 Manifest.permission.REQUEST_DELETE_PACKAGES})
Todd Kennedycda831f2017-05-16 10:54:33 -0700560 public void uninstall(@NonNull VersionedPackage versionedPackage,
561 @NonNull IntentSender statusReceiver) {
562 uninstall(versionedPackage, 0 /*flags*/, statusReceiver);
563 }
564
565 /**
566 * Uninstall the given package with a specific version code, removing it
567 * completely from the device. This method is only available to the current
568 * "installer of record" for the package. If the version code of the package
569 * does not match the one passed in the versioned package argument this
570 * method is a no-op. Use {@link PackageManager#VERSION_CODE_HIGHEST} to
571 * uninstall the latest version of the package.
572 *
573 * @param versionedPackage The versioned package to uninstall.
574 * @param flags Flags for uninstall.
575 * @param statusReceiver Where to deliver the result.
576 *
577 * @hide
578 */
Svet Ganov67882122016-12-11 16:36:34 -0800579 @RequiresPermission(anyOf = {
580 Manifest.permission.DELETE_PACKAGES,
581 Manifest.permission.REQUEST_DELETE_PACKAGES})
Todd Kennedycda831f2017-05-16 10:54:33 -0700582 public void uninstall(@NonNull VersionedPackage versionedPackage, @DeleteFlags int flags,
Svet Ganov67882122016-12-11 16:36:34 -0800583 @NonNull IntentSender statusReceiver) {
584 Preconditions.checkNotNull(versionedPackage, "versionedPackage cannot be null");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700585 try {
Svet Ganov67882122016-12-11 16:36:34 -0800586 mInstaller.uninstall(versionedPackage, mInstallerPackageName,
Todd Kennedycda831f2017-05-16 10:54:33 -0700587 flags, statusReceiver, mUserId);
Jeff Sharkeybb580672014-07-10 12:10:25 -0700588 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700589 throw e.rethrowFromSystemServer();
Jeff Sharkeybb580672014-07-10 12:10:25 -0700590 }
591 }
592
Chandan Nathe8e463b2019-01-28 15:23:38 +0000593 /**
594 * Install the given package, which already exists on the device, for the user for which this
595 * installer was created.
596 *
597 * @param packageName The package to install.
598 * @param installReason Reason for install.
599 * @param statusReceiver Where to deliver the result.
600 */
601 @RequiresPermission(allOf = {
602 Manifest.permission.INSTALL_PACKAGES,
603 Manifest.permission.INSTALL_EXISTING_PACKAGES})
604 public void installExistingPackage(@NonNull String packageName,
605 @InstallReason int installReason,
606 @Nullable IntentSender statusReceiver) {
607 Preconditions.checkNotNull(packageName, "packageName cannot be null");
608 try {
609 mInstaller.installExistingPackage(packageName, 0, installReason, statusReceiver,
610 mUserId);
611 } catch (RemoteException e) {
612 throw e.rethrowFromSystemServer();
613 }
614 }
615
616
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700617 /** {@hide} */
Todd Kennedy04cc1912017-03-03 13:05:12 -0800618 @SystemApi
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -0600619 @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES)
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700620 public void setPermissionsResult(int sessionId, boolean accepted) {
621 try {
622 mInstaller.setPermissionsResult(sessionId, accepted);
623 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700624 throw e.rethrowFromSystemServer();
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700625 }
626 }
627
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700628 /**
629 * Events for observing session lifecycle.
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700630 * <p>
631 * A typical session lifecycle looks like this:
632 * <ul>
633 * <li>An installer creates a session to indicate pending app delivery. All
634 * install details are available at this point.
635 * <li>The installer opens the session to deliver APK data. Note that a
636 * session may be opened and closed multiple times as network connectivity
637 * changes. The installer may deliver periodic progress updates.
638 * <li>The installer commits or abandons the session, resulting in the
639 * session being finished.
640 * </ul>
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700641 */
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700642 public static abstract class SessionCallback {
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700643 /**
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700644 * New session has been created. Details about the session can be
645 * obtained from {@link PackageInstaller#getSessionInfo(int)}.
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700646 */
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700647 public abstract void onCreated(int sessionId);
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700648
649 /**
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700650 * Badging details for an existing session has changed. For example, the
651 * app icon or label has been updated.
652 */
653 public abstract void onBadgingChanged(int sessionId);
654
655 /**
Jeff Sharkeybc7bce32014-09-05 15:53:05 -0700656 * Active state for session has been changed.
657 * <p>
658 * A session is considered active whenever there is ongoing forward
659 * progress being made, such as the installer holding an open
660 * {@link Session} instance while streaming data into place, or the
661 * system optimizing code as the result of
662 * {@link Session#commit(IntentSender)}.
663 * <p>
664 * If the installer closes the {@link Session} without committing, the
665 * session is considered inactive until the installer opens the session
666 * again.
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700667 */
Jeff Sharkeybc7bce32014-09-05 15:53:05 -0700668 public abstract void onActiveChanged(int sessionId, boolean active);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700669
670 /**
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700671 * Progress for given session has been updated.
672 * <p>
673 * Note that this progress may not directly correspond to the value
Jeff Sharkeybc7bce32014-09-05 15:53:05 -0700674 * reported by
675 * {@link PackageInstaller.Session#setStagingProgress(float)}, as the
676 * system may carve out a portion of the overall progress to represent
677 * its own internal installation work.
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700678 */
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700679 public abstract void onProgressChanged(int sessionId, float progress);
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700680
681 /**
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700682 * Session has completely finished, either with success or failure.
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700683 */
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700684 public abstract void onFinished(int sessionId, boolean success);
Jeff Sharkeybb580672014-07-10 12:10:25 -0700685 }
686
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700687 /** {@hide} */
Jon Miranda2b340a22019-01-25 14:03:49 -0800688 static class SessionCallbackDelegate extends IPackageInstallerCallback.Stub {
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700689 private static final int MSG_SESSION_CREATED = 1;
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700690 private static final int MSG_SESSION_BADGING_CHANGED = 2;
Jeff Sharkeybc7bce32014-09-05 15:53:05 -0700691 private static final int MSG_SESSION_ACTIVE_CHANGED = 3;
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700692 private static final int MSG_SESSION_PROGRESS_CHANGED = 4;
Jeff Sharkeybc7bce32014-09-05 15:53:05 -0700693 private static final int MSG_SESSION_FINISHED = 5;
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700694
695 final SessionCallback mCallback;
Jon Miranda2b340a22019-01-25 14:03:49 -0800696 final Executor mExecutor;
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700697
Jon Miranda2b340a22019-01-25 14:03:49 -0800698 SessionCallbackDelegate(SessionCallback callback, Executor executor) {
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700699 mCallback = callback;
Jon Miranda2b340a22019-01-25 14:03:49 -0800700 mExecutor = executor;
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700701 }
702
703 @Override
704 public void onSessionCreated(int sessionId) {
Jon Miranda2b340a22019-01-25 14:03:49 -0800705 mExecutor.execute(PooledLambda.obtainRunnable(SessionCallback::onCreated, mCallback,
706 sessionId).recycleOnUse());
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700707 }
708
709 @Override
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700710 public void onSessionBadgingChanged(int sessionId) {
Jon Miranda2b340a22019-01-25 14:03:49 -0800711 mExecutor.execute(PooledLambda.obtainRunnable(SessionCallback::onBadgingChanged,
712 mCallback, sessionId).recycleOnUse());
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700713 }
714
715 @Override
Jeff Sharkeybc7bce32014-09-05 15:53:05 -0700716 public void onSessionActiveChanged(int sessionId, boolean active) {
Jon Miranda2b340a22019-01-25 14:03:49 -0800717 mExecutor.execute(PooledLambda.obtainRunnable(SessionCallback::onActiveChanged,
718 mCallback, sessionId, active).recycleOnUse());
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700719 }
720
721 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700722 public void onSessionProgressChanged(int sessionId, float progress) {
Jon Miranda2b340a22019-01-25 14:03:49 -0800723 mExecutor.execute(PooledLambda.obtainRunnable(SessionCallback::onProgressChanged,
724 mCallback, sessionId, progress).recycleOnUse());
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700725 }
726
727 @Override
728 public void onSessionFinished(int sessionId, boolean success) {
Jon Miranda2b340a22019-01-25 14:03:49 -0800729 mExecutor.execute(PooledLambda.obtainRunnable(SessionCallback::onFinished,
730 mCallback, sessionId, success).recycleOnUse());
Jeff Sharkeybb580672014-07-10 12:10:25 -0700731 }
732 }
733
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700734 /** {@hide} */
735 @Deprecated
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700736 public void addSessionCallback(@NonNull SessionCallback callback) {
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700737 registerSessionCallback(callback);
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700738 }
739
740 /**
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700741 * Register to watch for session lifecycle events. No special permissions
742 * are required to watch for these events.
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700743 */
744 public void registerSessionCallback(@NonNull SessionCallback callback) {
745 registerSessionCallback(callback, new Handler());
746 }
747
748 /** {@hide} */
749 @Deprecated
750 public void addSessionCallback(@NonNull SessionCallback callback, @NonNull Handler handler) {
751 registerSessionCallback(callback, handler);
752 }
753
754 /**
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700755 * Register to watch for session lifecycle events. No special permissions
756 * are required to watch for these events.
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700757 *
758 * @param handler to dispatch callback events through, otherwise uses
759 * calling thread.
760 */
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700761 public void registerSessionCallback(@NonNull SessionCallback callback, @NonNull Handler handler) {
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700762 synchronized (mDelegates) {
763 final SessionCallbackDelegate delegate = new SessionCallbackDelegate(callback,
Jon Miranda2b340a22019-01-25 14:03:49 -0800764 new HandlerExecutor(handler));
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700765 try {
766 mInstaller.registerCallback(delegate, mUserId);
767 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700768 throw e.rethrowFromSystemServer();
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700769 }
770 mDelegates.add(delegate);
771 }
772 }
773
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700774 /** {@hide} */
775 @Deprecated
776 public void removeSessionCallback(@NonNull SessionCallback callback) {
777 unregisterSessionCallback(callback);
778 }
779
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700780 /**
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700781 * Unregister a previously registered callback.
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700782 */
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700783 public void unregisterSessionCallback(@NonNull SessionCallback callback) {
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700784 synchronized (mDelegates) {
785 for (Iterator<SessionCallbackDelegate> i = mDelegates.iterator(); i.hasNext();) {
786 final SessionCallbackDelegate delegate = i.next();
787 if (delegate.mCallback == callback) {
788 try {
789 mInstaller.unregisterCallback(delegate);
790 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700791 throw e.rethrowFromSystemServer();
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700792 }
793 i.remove();
794 }
795 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700796 }
797 }
798
799 /**
800 * An installation that is being actively staged. For an install to succeed,
801 * all existing and new packages must have identical package names, version
802 * codes, and signing certificates.
803 * <p>
804 * A session may contain any number of split packages. If the application
805 * does not yet exist, this session must include a base package.
806 * <p>
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700807 * If an APK included in this session is already defined by the existing
808 * installation (for example, the same split name), the APK in this session
809 * will replace the existing APK.
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000810 * <p>
811 * In such a case that multiple packages need to be commited simultaneously,
812 * multiple sessions can be referenced by a single multi-package session.
813 * This session is created with no package name and calling
814 * {@link SessionParams#setMultiPackage()} with {@code true}. The
815 * individual session IDs can be added with {@link #addChildSessionId(int)}
816 * and commit of the multi-package session will result in all child sessions
817 * being committed atomically.
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700818 */
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700819 public static class Session implements Closeable {
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000820 /** {@hide} */
821 protected final IPackageInstallerSession mSession;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700822
823 /** {@hide} */
824 public Session(IPackageInstallerSession session) {
825 mSession = session;
826 }
827
Jeff Sharkeybc7bce32014-09-05 15:53:05 -0700828 /** {@hide} */
829 @Deprecated
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700830 public void setProgress(float progress) {
Jeff Sharkeybc7bce32014-09-05 15:53:05 -0700831 setStagingProgress(progress);
832 }
833
834 /**
835 * Set current progress of staging this session. Valid values are
836 * anywhere between 0 and 1.
837 * <p>
838 * Note that this progress may not directly correspond to the value
839 * reported by {@link SessionCallback#onProgressChanged(int, float)}, as
840 * the system may carve out a portion of the overall progress to
841 * represent its own internal installation work.
842 */
843 public void setStagingProgress(float progress) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700844 try {
Jeff Sharkeya1031142014-07-12 18:09:46 -0700845 mSession.setClientProgress(progress);
846 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700847 throw e.rethrowFromSystemServer();
Jeff Sharkeya1031142014-07-12 18:09:46 -0700848 }
849 }
850
851 /** {@hide} */
Mathew Inwood5c0d3542018-08-14 13:54:31 +0100852 @UnsupportedAppUsage
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700853 public void addProgress(float progress) {
Jeff Sharkeya1031142014-07-12 18:09:46 -0700854 try {
855 mSession.addClientProgress(progress);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700856 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700857 throw e.rethrowFromSystemServer();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700858 }
859 }
860
Jeff Sharkey78cc3402014-05-22 10:52:49 -0700861 /**
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700862 * Open a stream to write an APK file into the session.
863 * <p>
864 * The returned stream will start writing data at the requested offset
865 * in the underlying file, which can be used to resume a partially
866 * written file. If a valid file length is specified, the system will
867 * preallocate the underlying disk space to optimize placement on disk.
868 * It's strongly recommended to provide a valid file length when known.
869 * <p>
870 * You can write data into the returned stream, optionally call
871 * {@link #fsync(OutputStream)} as needed to ensure bytes have been
872 * persisted to disk, and then close when finished. All streams must be
Jeff Sharkeya0907432014-08-15 10:23:11 -0700873 * closed before calling {@link #commit(IntentSender)}.
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700874 *
875 * @param name arbitrary, unique name of your choosing to identify the
876 * APK being written. You can open a file again for
877 * additional writes (such as after a reboot) by using the
878 * same name. This name is only meaningful within the context
879 * of a single install session.
880 * @param offsetBytes offset into the file to begin writing at, or 0 to
881 * start at the beginning of the file.
882 * @param lengthBytes total size of the file being written, used to
883 * preallocate the underlying disk space, or -1 if unknown.
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700884 * The system may clear various caches as needed to allocate
885 * this space.
886 * @throws IOException if trouble opening the file for writing, such as
887 * lack of disk space or unavailable media.
888 * @throws SecurityException if called after the session has been
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000889 * sealed or abandoned
Jeff Sharkey78cc3402014-05-22 10:52:49 -0700890 */
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700891 public @NonNull OutputStream openWrite(@NonNull String name, long offsetBytes,
892 long lengthBytes) throws IOException {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700893 try {
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700894 if (ENABLE_REVOCABLE_FD) {
895 return new ParcelFileDescriptor.AutoCloseOutputStream(
896 mSession.openWrite(name, offsetBytes, lengthBytes));
897 } else {
898 final ParcelFileDescriptor clientSocket = mSession.openWrite(name,
899 offsetBytes, lengthBytes);
900 return new FileBridge.FileBridgeOutputStream(clientSocket);
901 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700902 } catch (RuntimeException e) {
903 ExceptionUtils.maybeUnwrapIOException(e);
904 throw e;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700905 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700906 throw e.rethrowFromSystemServer();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700907 }
Jeff Sharkey0451de62018-02-02 11:27:21 -0700908 }
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700909
Jeff Sharkey0451de62018-02-02 11:27:21 -0700910 /** {@hide} */
911 public void write(@NonNull String name, long offsetBytes, long lengthBytes,
912 @NonNull ParcelFileDescriptor fd) throws IOException {
913 try {
914 mSession.write(name, offsetBytes, lengthBytes, fd);
915 } catch (RuntimeException e) {
916 ExceptionUtils.maybeUnwrapIOException(e);
917 throw e;
918 } catch (RemoteException e) {
919 throw e.rethrowFromSystemServer();
920 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700921 }
922
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700923 /**
924 * Ensure that any outstanding data for given stream has been committed
925 * to disk. This is only valid for streams returned from
926 * {@link #openWrite(String, long, long)}.
927 */
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700928 public void fsync(@NonNull OutputStream out) throws IOException {
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700929 if (ENABLE_REVOCABLE_FD) {
930 if (out instanceof ParcelFileDescriptor.AutoCloseOutputStream) {
931 try {
932 Os.fsync(((ParcelFileDescriptor.AutoCloseOutputStream) out).getFD());
933 } catch (ErrnoException e) {
934 throw e.rethrowAsIOException();
935 }
936 } else {
937 throw new IllegalArgumentException("Unrecognized stream");
938 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700939 } else {
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700940 if (out instanceof FileBridge.FileBridgeOutputStream) {
941 ((FileBridge.FileBridgeOutputStream) out).fsync();
942 } else {
943 throw new IllegalArgumentException("Unrecognized stream");
944 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700945 }
946 }
947
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700948 /**
Jeff Sharkeya0907432014-08-15 10:23:11 -0700949 * Return all APK names contained in this session.
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700950 * <p>
951 * This returns all names which have been previously written through
952 * {@link #openWrite(String, long, long)} as part of this session.
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700953 *
954 * @throws SecurityException if called after the session has been
955 * committed or abandoned.
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700956 */
Jeff Sharkey742e7902014-08-16 19:09:13 -0700957 public @NonNull String[] getNames() throws IOException {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700958 try {
Jeff Sharkeya0907432014-08-15 10:23:11 -0700959 return mSession.getNames();
Jeff Sharkey742e7902014-08-16 19:09:13 -0700960 } catch (RuntimeException e) {
961 ExceptionUtils.maybeUnwrapIOException(e);
962 throw e;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700963 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700964 throw e.rethrowFromSystemServer();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700965 }
966 }
967
968 /**
969 * Open a stream to read an APK file from the session.
970 * <p>
971 * This is only valid for names which have been previously written
972 * through {@link #openWrite(String, long, long)} as part of this
973 * session. For example, this stream may be used to calculate a
974 * {@link MessageDigest} of a written APK before committing.
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700975 *
976 * @throws SecurityException if called after the session has been
977 * committed or abandoned.
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700978 */
979 public @NonNull InputStream openRead(@NonNull String name) throws IOException {
980 try {
981 final ParcelFileDescriptor pfd = mSession.openRead(name);
982 return new ParcelFileDescriptor.AutoCloseInputStream(pfd);
983 } catch (RuntimeException e) {
984 ExceptionUtils.maybeUnwrapIOException(e);
985 throw e;
986 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700987 throw e.rethrowFromSystemServer();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700988 }
989 }
990
991 /**
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800992 * Removes a split.
993 * <p>
994 * Split removals occur prior to adding new APKs. If upgrading a feature
995 * split, it is not expected nor desirable to remove the split prior to
996 * upgrading.
997 * <p>
998 * When split removal is bundled with new APKs, the packageName must be
999 * identical.
1000 */
1001 public void removeSplit(@NonNull String splitName) throws IOException {
1002 try {
1003 mSession.removeSplit(splitName);
1004 } catch (RuntimeException e) {
1005 ExceptionUtils.maybeUnwrapIOException(e);
1006 throw e;
1007 } catch (RemoteException e) {
1008 throw e.rethrowFromSystemServer();
1009 }
1010 }
1011
1012 /**
Jeff Sharkey6c833e02014-07-14 22:44:30 -07001013 * Attempt to commit everything staged in this session. This may require
1014 * user intervention, and so it may not happen immediately. The final
1015 * result of the commit will be reported through the given callback.
1016 * <p>
Todd Kennedy04cc1912017-03-03 13:05:12 -08001017 * Once this method is called, the session is sealed and no additional
1018 * mutations may be performed on the session. If the device reboots
1019 * before the session has been finalized, you may commit the session again.
Tony Mak366ee622018-02-12 17:52:34 +00001020 * <p>
1021 * If the installer is the device owner or the affiliated profile owner, there will be no
1022 * user intervention.
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001023 *
Philip P. Moltmann2fe7dee2018-09-14 08:45:42 -07001024 * @param statusReceiver Called when the state of the session changes. Intents
1025 * sent to this receiver contain {@link #EXTRA_STATUS}. Refer to the
1026 * individual status codes on how to handle them.
1027 *
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001028 * @throws SecurityException if streams opened through
1029 * {@link #openWrite(String, long, long)} are still open.
Tony Mak366ee622018-02-12 17:52:34 +00001030 *
1031 * @see android.app.admin.DevicePolicyManager
Jeff Sharkey6c833e02014-07-14 22:44:30 -07001032 */
Jeff Sharkeya0907432014-08-15 10:23:11 -07001033 public void commit(@NonNull IntentSender statusReceiver) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001034 try {
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001035 mSession.commit(statusReceiver, false);
1036 } catch (RemoteException e) {
1037 throw e.rethrowFromSystemServer();
1038 }
1039 }
1040
1041 /**
1042 * Attempt to commit a session that has been {@link #transfer(String) transferred}.
1043 *
1044 * <p>If the device reboots before the session has been finalized, you may commit the
1045 * session again.
1046 *
1047 * <p>The caller of this method is responsible to ensure the safety of the session. As the
1048 * session was created by another - usually less trusted - app, it is paramount that before
1049 * committing <u>all</u> public and system {@link SessionInfo properties of the session}
1050 * and <u>all</u> {@link #openRead(String) APKs} are verified by the caller. It might happen
1051 * that new properties are added to the session with a new API revision. In this case the
1052 * callers need to be updated.
1053 *
Philip P. Moltmann2fe7dee2018-09-14 08:45:42 -07001054 * @param statusReceiver Called when the state of the session changes. Intents
1055 * sent to this receiver contain {@link #EXTRA_STATUS}. Refer to the
1056 * individual status codes on how to handle them.
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001057 *
1058 * @hide
1059 */
1060 @SystemApi
1061 @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES)
1062 public void commitTransferred(@NonNull IntentSender statusReceiver) {
1063 try {
1064 mSession.commit(statusReceiver, true);
1065 } catch (RemoteException e) {
1066 throw e.rethrowFromSystemServer();
1067 }
1068 }
1069
1070 /**
1071 * Transfer the session to a new owner.
1072 * <p>
1073 * Only sessions that update the installing app can be transferred.
1074 * <p>
1075 * After the transfer to a package with a different uid all method calls on the session
1076 * will cause {@link SecurityException}s.
1077 * <p>
1078 * Once this method is called, the session is sealed and no additional mutations beside
1079 * committing it may be performed on the session.
1080 *
1081 * @param packageName The package of the new owner. Needs to hold the INSTALL_PACKAGES
1082 * permission.
1083 *
1084 * @throws PackageManager.NameNotFoundException if the new owner could not be found.
1085 * @throws SecurityException if called after the session has been committed or abandoned.
1086 * @throws SecurityException if the session does not update the original installer
1087 * @throws SecurityException if streams opened through
1088 * {@link #openWrite(String, long, long) are still open.
1089 */
1090 public void transfer(@NonNull String packageName)
1091 throws PackageManager.NameNotFoundException {
1092 Preconditions.checkNotNull(packageName);
1093
1094 try {
1095 mSession.transfer(packageName);
1096 } catch (ParcelableException e) {
1097 e.maybeRethrow(PackageManager.NameNotFoundException.class);
1098 throw new RuntimeException(e);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001099 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001100 throw e.rethrowFromSystemServer();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001101 }
1102 }
1103
Jeff Sharkey6c833e02014-07-14 22:44:30 -07001104 /**
1105 * Release this session object. You can open the session again if it
1106 * hasn't been finalized.
1107 */
Jeff Sharkeyec55ef02014-07-08 11:28:00 -07001108 @Override
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001109 public void close() {
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07001110 try {
1111 mSession.close();
1112 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001113 throw e.rethrowFromSystemServer();
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07001114 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001115 }
1116
Jeff Sharkey6c833e02014-07-14 22:44:30 -07001117 /**
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07001118 * Completely abandon this session, destroying all staged data and
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001119 * rendering it invalid. Abandoned sessions will be reported to
1120 * {@link SessionCallback} listeners as failures. This is equivalent to
1121 * opening the session and calling {@link Session#abandon()}.
Jeff Sharkey6c833e02014-07-14 22:44:30 -07001122 */
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07001123 public void abandon() {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001124 try {
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07001125 mSession.abandon();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001126 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001127 throw e.rethrowFromSystemServer();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001128 }
1129 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001130
1131 /**
1132 * @return {@code true} if this session will commit more than one package when it is
1133 * committed.
1134 */
1135 public boolean isMultiPackage() {
1136 try {
1137 return mSession.isMultiPackage();
1138 } catch (RemoteException e) {
1139 throw e.rethrowFromSystemServer();
1140 }
1141 }
1142
1143 /**
Dario Freniaac4ba42018-12-06 15:47:16 +00001144 * @return {@code true} if this session will be staged and applied at next reboot.
1145 */
1146 public boolean isStaged() {
1147 try {
1148 return mSession.isStaged();
1149 } catch (RemoteException e) {
1150 throw e.rethrowFromSystemServer();
1151 }
1152 }
1153
1154 /**
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001155 * @return the session ID of the multi-package session that this belongs to or
1156 * {@link SessionInfo#INVALID_ID} if it does not belong to a multi-package session.
1157 */
1158 public int getParentSessionId() {
1159 try {
1160 return mSession.getParentSessionId();
1161 } catch (RemoteException e) {
1162 throw e.rethrowFromSystemServer();
1163 }
1164 }
1165
1166 /**
1167 * @return the set of session IDs that will be committed atomically when this session is
1168 * committed if this is a multi-package session or null if none exist.
1169 */
1170 @NonNull
1171 public int[] getChildSessionIds() {
1172 try {
1173 return mSession.getChildSessionIds();
1174 } catch (RemoteException e) {
1175 throw e.rethrowFromSystemServer();
1176 }
1177 }
1178
1179 /**
1180 * Adds a session ID to the set of sessions that will be committed atomically
1181 * when this session is committed.
1182 *
1183 * @param sessionId the session ID to add to this multi-package session.
1184 */
1185 public void addChildSessionId(int sessionId) {
1186 try {
1187 mSession.addChildSessionId(sessionId);
1188 } catch (RemoteException e) {
1189 throw e.rethrowFromSystemServer();
1190 }
1191 }
1192
1193 /**
1194 * Removes a session ID from the set of sessions that will be committed
1195 * atomically when this session is committed.
1196 *
1197 * @param sessionId the session ID to remove from this multi-package session.
1198 */
1199 public void removeChildSessionId(int sessionId) {
1200 try {
1201 mSession.removeChildSessionId(sessionId);
1202 } catch (RemoteException e) {
1203 throw e.rethrowFromSystemServer();
1204 }
1205 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001206 }
Jeff Sharkeybb580672014-07-10 12:10:25 -07001207
Jeff Sharkey6c833e02014-07-14 22:44:30 -07001208 /**
Jeff Sharkeya0907432014-08-15 10:23:11 -07001209 * Parameters for creating a new {@link PackageInstaller.Session}.
Jeff Sharkey6c833e02014-07-14 22:44:30 -07001210 */
Jeff Sharkeya0907432014-08-15 10:23:11 -07001211 public static class SessionParams implements Parcelable {
1212
1213 /** {@hide} */
1214 public static final int MODE_INVALID = -1;
Jeff Sharkeyf0600952014-08-07 17:31:53 -07001215
1216 /**
Jeff Sharkeya0907432014-08-15 10:23:11 -07001217 * Mode for an install session whose staged APKs should fully replace any
1218 * existing APKs for the target app.
Jeff Sharkeyf0600952014-08-07 17:31:53 -07001219 */
Jeff Sharkeya0907432014-08-15 10:23:11 -07001220 public static final int MODE_FULL_INSTALL = 1;
Jeff Sharkeyf0600952014-08-07 17:31:53 -07001221
1222 /**
Jeff Sharkeya0907432014-08-15 10:23:11 -07001223 * Mode for an install session that should inherit any existing APKs for the
1224 * target app, unless they have been explicitly overridden (based on split
1225 * name) by the session. For example, this can be used to add one or more
1226 * split APKs to an existing installation.
Jeff Sharkeyfbd0e9f2014-08-06 16:34:34 -07001227 * <p>
Jeff Sharkeya0907432014-08-15 10:23:11 -07001228 * If there are no existing APKs for the target app, this behaves like
1229 * {@link #MODE_FULL_INSTALL}.
Jeff Sharkeyfbd0e9f2014-08-06 16:34:34 -07001230 */
Jeff Sharkeya0907432014-08-15 10:23:11 -07001231 public static final int MODE_INHERIT_EXISTING = 2;
Jeff Sharkeyfbd0e9f2014-08-06 16:34:34 -07001232
Jeff Sharkeya0907432014-08-15 10:23:11 -07001233 /** {@hide} */
Todd Kennedya1d12cf2015-09-29 15:43:00 -07001234 public static final int UID_UNKNOWN = -1;
1235
1236 /** {@hide} */
Mathew Inwood8c854f82018-09-14 12:35:36 +01001237 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Jeff Sharkeya0907432014-08-15 10:23:11 -07001238 public int mode = MODE_INVALID;
1239 /** {@hide} */
Mathew Inwood5c0d3542018-08-14 13:54:31 +01001240 @UnsupportedAppUsage
Jeff Sharkeya0907432014-08-15 10:23:11 -07001241 public int installFlags;
1242 /** {@hide} */
1243 public int installLocation = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY;
1244 /** {@hide} */
Bartosz Fabianowski40a00622017-04-18 14:39:23 +02001245 public @InstallReason int installReason = PackageManager.INSTALL_REASON_UNKNOWN;
Bartosz Fabianowskia34f53f2017-01-11 18:08:47 +01001246 /** {@hide} */
Mathew Inwood5c0d3542018-08-14 13:54:31 +01001247 @UnsupportedAppUsage
Jeff Sharkeya0907432014-08-15 10:23:11 -07001248 public long sizeBytes = -1;
1249 /** {@hide} */
Mathew Inwood8c854f82018-09-14 12:35:36 +01001250 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Jeff Sharkeya0907432014-08-15 10:23:11 -07001251 public String appPackageName;
1252 /** {@hide} */
Mathew Inwood5c0d3542018-08-14 13:54:31 +01001253 @UnsupportedAppUsage
Jeff Sharkeya0907432014-08-15 10:23:11 -07001254 public Bitmap appIcon;
1255 /** {@hide} */
Mathew Inwood8c854f82018-09-14 12:35:36 +01001256 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Jeff Sharkeya0907432014-08-15 10:23:11 -07001257 public String appLabel;
1258 /** {@hide} */
Jeff Sharkey02bd7842014-10-06 15:14:27 -07001259 public long appIconLastModified = -1;
1260 /** {@hide} */
Jeff Sharkeya0907432014-08-15 10:23:11 -07001261 public Uri originatingUri;
1262 /** {@hide} */
Mathew Inwood5c0d3542018-08-14 13:54:31 +01001263 @UnsupportedAppUsage
Todd Kennedya1d12cf2015-09-29 15:43:00 -07001264 public int originatingUid = UID_UNKNOWN;
1265 /** {@hide} */
Jeff Sharkeya0907432014-08-15 10:23:11 -07001266 public Uri referrerUri;
1267 /** {@hide} */
1268 public String abiOverride;
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -07001269 /** {@hide} */
1270 public String volumeUuid;
Svet Ganov7121e182015-07-13 22:38:12 -07001271 /** {@hide} */
1272 public String[] grantedRuntimePermissions;
Philip P. Moltmann79c238a2017-12-13 15:59:07 -08001273 /** {@hide} */
1274 public String installerPackageName;
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001275 /** {@hide} */
1276 public boolean isMultiPackage;
Dario Freniaac4ba42018-12-06 15:47:16 +00001277 /** {@hide} */
1278 public boolean isStaged;
Jeff Sharkeybb580672014-07-10 12:10:25 -07001279
Jeff Sharkeya0907432014-08-15 10:23:11 -07001280 /**
1281 * Construct parameters for a new package install session.
1282 *
1283 * @param mode one of {@link #MODE_FULL_INSTALL} or
1284 * {@link #MODE_INHERIT_EXISTING} describing how the session
1285 * should interact with an existing app.
1286 */
1287 public SessionParams(int mode) {
1288 this.mode = mode;
1289 }
Jeff Sharkeybb580672014-07-10 12:10:25 -07001290
Jeff Sharkeya0907432014-08-15 10:23:11 -07001291 /** {@hide} */
1292 public SessionParams(Parcel source) {
1293 mode = source.readInt();
1294 installFlags = source.readInt();
1295 installLocation = source.readInt();
Bartosz Fabianowskia34f53f2017-01-11 18:08:47 +01001296 installReason = source.readInt();
Jeff Sharkeya0907432014-08-15 10:23:11 -07001297 sizeBytes = source.readLong();
1298 appPackageName = source.readString();
1299 appIcon = source.readParcelable(null);
1300 appLabel = source.readString();
1301 originatingUri = source.readParcelable(null);
Todd Kennedya1d12cf2015-09-29 15:43:00 -07001302 originatingUid = source.readInt();
Jeff Sharkeya0907432014-08-15 10:23:11 -07001303 referrerUri = source.readParcelable(null);
1304 abiOverride = source.readString();
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -07001305 volumeUuid = source.readString();
Svet Ganov7121e182015-07-13 22:38:12 -07001306 grantedRuntimePermissions = source.readStringArray();
Philip P. Moltmann79c238a2017-12-13 15:59:07 -08001307 installerPackageName = source.readString();
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001308 isMultiPackage = source.readBoolean();
Dario Freniaac4ba42018-12-06 15:47:16 +00001309 isStaged = source.readBoolean();
Jeff Sharkeya0907432014-08-15 10:23:11 -07001310 }
1311
Dario Freni4b572c02019-01-29 09:40:31 +00001312 /** {@hide} */
1313 public SessionParams copy() {
1314 SessionParams ret = new SessionParams(mode);
1315 ret.installFlags = installFlags;
1316 ret.installLocation = installLocation;
1317 ret.installReason = installReason;
1318 ret.sizeBytes = sizeBytes;
1319 ret.appPackageName = appPackageName;
1320 ret.appIcon = appIcon; // not a copy.
1321 ret.appLabel = appLabel;
1322 ret.originatingUri = originatingUri; // not a copy, but immutable.
1323 ret.originatingUid = originatingUid;
1324 ret.referrerUri = referrerUri; // not a copy, but immutable.
1325 ret.abiOverride = abiOverride;
1326 ret.volumeUuid = volumeUuid;
1327 ret.grantedRuntimePermissions = grantedRuntimePermissions;
1328 ret.installerPackageName = installerPackageName;
1329 ret.isMultiPackage = isMultiPackage;
1330 ret.isStaged = isStaged;
1331 return ret;
1332 }
1333
Jeff Sharkeya0907432014-08-15 10:23:11 -07001334 /**
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001335 * Check if there are hidden options set.
1336 *
1337 * <p>Hidden options are those options that cannot be verified via public or system-api
1338 * methods on {@link SessionInfo}.
1339 *
1340 * @return {@code true} if any hidden option is set.
1341 *
1342 * @hide
1343 */
1344 public boolean areHiddenOptionsSet() {
1345 return (installFlags & (PackageManager.INSTALL_ALLOW_DOWNGRADE
1346 | PackageManager.INSTALL_DONT_KILL_APP
1347 | PackageManager.INSTALL_INSTANT_APP
1348 | PackageManager.INSTALL_FULL_APP
1349 | PackageManager.INSTALL_VIRTUAL_PRELOAD
1350 | PackageManager.INSTALL_ALLOCATE_AGGRESSIVE)) != installFlags
1351 || abiOverride != null || volumeUuid != null;
1352 }
1353
1354 /**
Jeff Sharkeya0907432014-08-15 10:23:11 -07001355 * Provide value of {@link PackageInfo#installLocation}, which may be used
1356 * to determine where the app will be staged. Defaults to
1357 * {@link PackageInfo#INSTALL_LOCATION_INTERNAL_ONLY}.
1358 */
1359 public void setInstallLocation(int installLocation) {
1360 this.installLocation = installLocation;
1361 }
1362
1363 /**
1364 * Optionally indicate the total size (in bytes) of all APKs that will be
1365 * delivered in this session. The system may use this to ensure enough disk
1366 * space exists before proceeding, or to estimate container size for
1367 * installations living on external storage.
1368 *
1369 * @see PackageInfo#INSTALL_LOCATION_AUTO
1370 * @see PackageInfo#INSTALL_LOCATION_PREFER_EXTERNAL
1371 */
1372 public void setSize(long sizeBytes) {
1373 this.sizeBytes = sizeBytes;
1374 }
1375
1376 /**
1377 * Optionally set the package name of the app being installed. It's strongly
1378 * recommended that you provide this value when known, so that observers can
1379 * communicate installing apps to users.
1380 * <p>
1381 * If the APKs staged in the session aren't consistent with this package
1382 * name, the install will fail. Regardless of this value, all APKs in the
1383 * app must have the same package name.
1384 */
1385 public void setAppPackageName(@Nullable String appPackageName) {
1386 this.appPackageName = appPackageName;
1387 }
1388
1389 /**
1390 * Optionally set an icon representing the app being installed. This should
1391 * be roughly {@link ActivityManager#getLauncherLargeIconSize()} in both
1392 * dimensions.
1393 */
1394 public void setAppIcon(@Nullable Bitmap appIcon) {
1395 this.appIcon = appIcon;
1396 }
1397
1398 /**
1399 * Optionally set a label representing the app being installed.
1400 */
1401 public void setAppLabel(@Nullable CharSequence appLabel) {
1402 this.appLabel = (appLabel != null) ? appLabel.toString() : null;
1403 }
1404
1405 /**
Todd Kennedy1ed6b872016-03-10 10:07:00 -08001406 * Optionally set the URI where this package was downloaded from. This is
1407 * informational and may be used as a signal for anti-malware purposes.
Jeff Sharkeya0907432014-08-15 10:23:11 -07001408 *
1409 * @see Intent#EXTRA_ORIGINATING_URI
1410 */
1411 public void setOriginatingUri(@Nullable Uri originatingUri) {
1412 this.originatingUri = originatingUri;
1413 }
1414
1415 /**
Nikolas Bravo62831002017-11-07 21:07:15 +00001416 * Sets the UID that initiated the package installation. This is informational
Todd Kennedy1ed6b872016-03-10 10:07:00 -08001417 * and may be used as a signal for anti-malware purposes.
Todd Kennedya1d12cf2015-09-29 15:43:00 -07001418 */
1419 public void setOriginatingUid(int originatingUid) {
1420 this.originatingUid = originatingUid;
1421 }
1422
1423 /**
Todd Kennedy1ed6b872016-03-10 10:07:00 -08001424 * Optionally set the URI that referred you to install this package. This is
1425 * informational and may be used as a signal for anti-malware purposes.
Jeff Sharkeya0907432014-08-15 10:23:11 -07001426 *
1427 * @see Intent#EXTRA_REFERRER
1428 */
1429 public void setReferrerUri(@Nullable Uri referrerUri) {
1430 this.referrerUri = referrerUri;
1431 }
1432
Svet Ganov7121e182015-07-13 22:38:12 -07001433 /**
1434 * Sets which runtime permissions to be granted to the package at installation.
Svet Ganov7121e182015-07-13 22:38:12 -07001435 *
1436 * @param permissions The permissions to grant or null to grant all runtime
1437 * permissions.
1438 *
1439 * @hide
1440 */
1441 @SystemApi
1442 @RequiresPermission(android.Manifest.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS)
1443 public void setGrantedRuntimePermissions(String[] permissions) {
1444 installFlags |= PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS;
1445 this.grantedRuntimePermissions = permissions;
1446 }
1447
Richard Uhlerb29f1452018-09-12 16:38:15 +01001448 /**
1449 * Request that rollbacks be enabled for the given upgrade.
Richard Uhlerc739c8c2018-12-12 11:03:34 +00001450 * @hide
Richard Uhlerb29f1452018-09-12 16:38:15 +01001451 */
Richard Uhlerc739c8c2018-12-12 11:03:34 +00001452 @SystemApi
Richard Uhlerb29f1452018-09-12 16:38:15 +01001453 public void setEnableRollback() {
1454 installFlags |= PackageManager.INSTALL_ENABLE_ROLLBACK;
1455 }
1456
Jeff Sharkeya0907432014-08-15 10:23:11 -07001457 /** {@hide} */
Todd Kennedyc84d1ab2016-03-11 11:37:17 -08001458 @SystemApi
Todd Kennedy948b7022016-03-14 14:29:52 -07001459 public void setAllowDowngrade(boolean allowDowngrade) {
1460 if (allowDowngrade) {
1461 installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE;
1462 } else {
1463 installFlags &= ~PackageManager.INSTALL_ALLOW_DOWNGRADE;
1464 }
Todd Kennedyc84d1ab2016-03-11 11:37:17 -08001465 }
1466
1467 /** {@hide} */
Todd Kennedya1d12cf2015-09-29 15:43:00 -07001468 public void setInstallFlagsForcePermissionPrompt() {
1469 installFlags |= PackageManager.INSTALL_FORCE_PERMISSION_PROMPT;
1470 }
1471
1472 /** {@hide} */
Todd Kennedy24ca5c62016-03-16 15:42:01 -07001473 @SystemApi
1474 public void setDontKillApp(boolean dontKillApp) {
1475 if (dontKillApp) {
1476 installFlags |= PackageManager.INSTALL_DONT_KILL_APP;
1477 } else {
1478 installFlags &= ~PackageManager.INSTALL_DONT_KILL_APP;
1479 }
Todd Kennedy39bfee52016-02-24 10:28:21 -08001480 }
1481
1482 /** {@hide} */
Todd Kennedyb7717682016-11-30 15:41:21 -08001483 @SystemApi
1484 public void setInstallAsInstantApp(boolean isInstantApp) {
1485 if (isInstantApp) {
Todd Kennedybe0b8892017-02-15 14:13:52 -08001486 installFlags |= PackageManager.INSTALL_INSTANT_APP;
1487 installFlags &= ~PackageManager.INSTALL_FULL_APP;
Todd Kennedyb7717682016-11-30 15:41:21 -08001488 } else {
Todd Kennedybe0b8892017-02-15 14:13:52 -08001489 installFlags &= ~PackageManager.INSTALL_INSTANT_APP;
1490 installFlags |= PackageManager.INSTALL_FULL_APP;
Todd Kennedyb7717682016-11-30 15:41:21 -08001491 }
1492 }
1493
Bartosz Fabianowski40a00622017-04-18 14:39:23 +02001494 /**
Todd Kennedy78a72502017-07-19 12:49:30 -07001495 * Sets the install as a virtual preload. Will only have effect when called
1496 * by the verifier.
1497 * {@hide}
1498 */
1499 @SystemApi
1500 public void setInstallAsVirtualPreload() {
1501 installFlags |= PackageManager.INSTALL_VIRTUAL_PRELOAD;
1502 }
1503
1504 /**
Bartosz Fabianowski40a00622017-04-18 14:39:23 +02001505 * Set the reason for installing this package.
Todd Kennedy5fdbabb2018-03-07 15:59:41 -08001506 * <p>
1507 * The install reason should be a pre-defined integer. The behavior is
1508 * undefined if other values are used.
1509 *
Aurimas Liutikas7f695332018-05-31 21:07:32 -07001510 * @see PackageManager#INSTALL_REASON_UNKNOWN
1511 * @see PackageManager#INSTALL_REASON_POLICY
1512 * @see PackageManager#INSTALL_REASON_DEVICE_RESTORE
1513 * @see PackageManager#INSTALL_REASON_DEVICE_SETUP
Todd Kennedy5fdbabb2018-03-07 15:59:41 -08001514 * @see PackageManager#INSTALL_REASON_USER
Bartosz Fabianowski40a00622017-04-18 14:39:23 +02001515 */
1516 public void setInstallReason(@InstallReason int installReason) {
Bartosz Fabianowskia34f53f2017-01-11 18:08:47 +01001517 this.installReason = installReason;
1518 }
1519
Todd Kennedyb7717682016-11-30 15:41:21 -08001520 /** {@hide} */
Jeff Sharkey683bcd32017-03-18 17:54:51 -06001521 @SystemApi
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -06001522 @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE)
Jeff Sharkey683bcd32017-03-18 17:54:51 -06001523 public void setAllocateAggressive(boolean allocateAggressive) {
1524 if (allocateAggressive) {
1525 installFlags |= PackageManager.INSTALL_ALLOCATE_AGGRESSIVE;
1526 } else {
1527 installFlags &= ~PackageManager.INSTALL_ALLOCATE_AGGRESSIVE;
1528 }
1529 }
1530
Philip P. Moltmann79c238a2017-12-13 15:59:07 -08001531 /**
1532 * Set the installer package for the app.
1533 *
1534 * By default this is the app that created the {@link PackageInstaller} object.
1535 *
1536 * @param installerPackageName name of the installer package
1537 * {@hide}
1538 */
1539 public void setInstallerPackageName(String installerPackageName) {
1540 this.installerPackageName = installerPackageName;
1541 }
1542
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001543 /**
1544 * Set this session to be the parent of a multi-package install.
1545 *
1546 * A multi-package install session contains no APKs and only references other install
1547 * sessions via ID. When a multi-package session is committed, all of its children
1548 * are committed to the system in an atomic manner. If any children fail to install,
1549 * all of them do, including the multi-package session.
1550 */
1551 public void setMultiPackage() {
1552 this.isMultiPackage = true;
1553 }
1554
Dario Freniaac4ba42018-12-06 15:47:16 +00001555 /**
1556 * Set this session to be staged to be installed at reboot.
1557 *
1558 * Staged sessions are scheduled to be installed at next reboot. Staged sessions can also be
1559 * multi-package. In that case, if any of the children sessions fail to install at reboot,
1560 * all the other children sessions are aborted as well.
Dario Freni77786d92019-02-08 17:26:05 +00001561 *
1562 * {@hide}
Dario Freniaac4ba42018-12-06 15:47:16 +00001563 */
Dario Freni77786d92019-02-08 17:26:05 +00001564 @SystemApi
1565 @RequiresPermission(Manifest.permission.INSTALL_PACKAGES)
Dario Freniaac4ba42018-12-06 15:47:16 +00001566 public void setStaged() {
1567 this.isStaged = true;
1568 }
1569
Dario Freni3fa46d82019-01-23 19:31:47 +00001570 /**
1571 * Set this session to be installing an APEX package.
Nikita Ioffe4501c112019-02-22 11:51:09 +00001572 *
1573 * {@hide}
Dario Freni3fa46d82019-01-23 19:31:47 +00001574 */
Nikita Ioffe4501c112019-02-22 11:51:09 +00001575 @SystemApi
1576 @RequiresPermission(Manifest.permission.INSTALL_PACKAGES)
Dario Freni3fa46d82019-01-23 19:31:47 +00001577 public void setInstallAsApex() {
1578 installFlags |= PackageManager.INSTALL_APEX;
1579 }
1580
Jeff Sharkey683bcd32017-03-18 17:54:51 -06001581 /** {@hide} */
Jeff Sharkeya0907432014-08-15 10:23:11 -07001582 public void dump(IndentingPrintWriter pw) {
1583 pw.printPair("mode", mode);
1584 pw.printHexPair("installFlags", installFlags);
1585 pw.printPair("installLocation", installLocation);
1586 pw.printPair("sizeBytes", sizeBytes);
1587 pw.printPair("appPackageName", appPackageName);
1588 pw.printPair("appIcon", (appIcon != null));
1589 pw.printPair("appLabel", appLabel);
1590 pw.printPair("originatingUri", originatingUri);
Todd Kennedya1d12cf2015-09-29 15:43:00 -07001591 pw.printPair("originatingUid", originatingUid);
Jeff Sharkeya0907432014-08-15 10:23:11 -07001592 pw.printPair("referrerUri", referrerUri);
1593 pw.printPair("abiOverride", abiOverride);
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -07001594 pw.printPair("volumeUuid", volumeUuid);
Svet Ganov7121e182015-07-13 22:38:12 -07001595 pw.printPair("grantedRuntimePermissions", grantedRuntimePermissions);
Philip P. Moltmann79c238a2017-12-13 15:59:07 -08001596 pw.printPair("installerPackageName", installerPackageName);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001597 pw.printPair("isMultiPackage", isMultiPackage);
Dario Freniaac4ba42018-12-06 15:47:16 +00001598 pw.printPair("isStaged", isStaged);
Jeff Sharkeya0907432014-08-15 10:23:11 -07001599 pw.println();
Jeff Sharkeybb580672014-07-10 12:10:25 -07001600 }
1601
1602 @Override
Jeff Sharkeya0907432014-08-15 10:23:11 -07001603 public int describeContents() {
1604 return 0;
Jeff Sharkeyfbd0e9f2014-08-06 16:34:34 -07001605 }
1606
1607 @Override
Jeff Sharkeya0907432014-08-15 10:23:11 -07001608 public void writeToParcel(Parcel dest, int flags) {
1609 dest.writeInt(mode);
1610 dest.writeInt(installFlags);
1611 dest.writeInt(installLocation);
Bartosz Fabianowskia34f53f2017-01-11 18:08:47 +01001612 dest.writeInt(installReason);
Jeff Sharkeya0907432014-08-15 10:23:11 -07001613 dest.writeLong(sizeBytes);
1614 dest.writeString(appPackageName);
1615 dest.writeParcelable(appIcon, flags);
1616 dest.writeString(appLabel);
1617 dest.writeParcelable(originatingUri, flags);
Todd Kennedya1d12cf2015-09-29 15:43:00 -07001618 dest.writeInt(originatingUid);
Jeff Sharkeya0907432014-08-15 10:23:11 -07001619 dest.writeParcelable(referrerUri, flags);
1620 dest.writeString(abiOverride);
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -07001621 dest.writeString(volumeUuid);
Svet Ganov7121e182015-07-13 22:38:12 -07001622 dest.writeStringArray(grantedRuntimePermissions);
Philip P. Moltmann79c238a2017-12-13 15:59:07 -08001623 dest.writeString(installerPackageName);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001624 dest.writeBoolean(isMultiPackage);
Dario Freniaac4ba42018-12-06 15:47:16 +00001625 dest.writeBoolean(isStaged);
Jeff Sharkeybb580672014-07-10 12:10:25 -07001626 }
Jeff Sharkeya0907432014-08-15 10:23:11 -07001627
1628 public static final Parcelable.Creator<SessionParams>
1629 CREATOR = new Parcelable.Creator<SessionParams>() {
1630 @Override
1631 public SessionParams createFromParcel(Parcel p) {
1632 return new SessionParams(p);
1633 }
1634
1635 @Override
1636 public SessionParams[] newArray(int size) {
1637 return new SessionParams[size];
1638 }
1639 };
Jeff Sharkeybb580672014-07-10 12:10:25 -07001640 }
1641
Jeff Sharkey6c833e02014-07-14 22:44:30 -07001642 /**
Jeff Sharkeya0907432014-08-15 10:23:11 -07001643 * Details for an active install session.
Jeff Sharkey6c833e02014-07-14 22:44:30 -07001644 */
Jeff Sharkeya0907432014-08-15 10:23:11 -07001645 public static class SessionInfo implements Parcelable {
1646
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001647 /**
1648 * A session ID that does not exist or is invalid.
1649 */
1650 public static final int INVALID_ID = -1;
1651 /** {@hide} */
1652 private static final int[] NO_SESSIONS = {};
Dario Freni71eee5e2018-12-06 15:47:16 +00001653
1654 /** @hide */
Dario Frenib6d28962019-01-31 15:52:24 +00001655 @IntDef(prefix = { "STAGED_SESSION_" }, value = {
1656 STAGED_SESSION_NO_ERROR,
1657 STAGED_SESSION_VERIFICATION_FAILED,
1658 STAGED_SESSION_ACTIVATION_FAILED,
1659 STAGED_SESSION_UNKNOWN})
Dario Freni71eee5e2018-12-06 15:47:16 +00001660 @Retention(RetentionPolicy.SOURCE)
1661 public @interface StagedSessionErrorCode{}
1662 /**
1663 * Constant indicating that no error occurred during the preparation or the activation of
1664 * this staged session.
1665 */
Dario Frenib6d28962019-01-31 15:52:24 +00001666 public static final int STAGED_SESSION_NO_ERROR = 0;
Dario Freni71eee5e2018-12-06 15:47:16 +00001667
1668 /**
1669 * Constant indicating that an error occurred during the verification phase (pre-reboot) of
1670 * this staged session.
1671 */
Dario Frenib6d28962019-01-31 15:52:24 +00001672 public static final int STAGED_SESSION_VERIFICATION_FAILED = 1;
Dario Freni71eee5e2018-12-06 15:47:16 +00001673
1674 /**
1675 * Constant indicating that an error occurred during the activation phase (post-reboot) of
1676 * this staged session.
1677 */
Dario Frenib6d28962019-01-31 15:52:24 +00001678 public static final int STAGED_SESSION_ACTIVATION_FAILED = 2;
1679
1680 /**
1681 * Constant indicating that an unknown error occurred while processing this staged session.
1682 */
1683 public static final int STAGED_SESSION_UNKNOWN = 3;
Dario Freni71eee5e2018-12-06 15:47:16 +00001684
Jeff Sharkeya0907432014-08-15 10:23:11 -07001685 /** {@hide} */
Mathew Inwood8c854f82018-09-14 12:35:36 +01001686 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Jeff Sharkeya0907432014-08-15 10:23:11 -07001687 public int sessionId;
1688 /** {@hide} */
Jon Miranda2b340a22019-01-25 14:03:49 -08001689 public int userId;
1690 /** {@hide} */
Mathew Inwood8c854f82018-09-14 12:35:36 +01001691 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Jeff Sharkeya0907432014-08-15 10:23:11 -07001692 public String installerPackageName;
1693 /** {@hide} */
Mathew Inwood5c0d3542018-08-14 13:54:31 +01001694 @UnsupportedAppUsage
Jeff Sharkeya0907432014-08-15 10:23:11 -07001695 public String resolvedBaseCodePath;
1696 /** {@hide} */
Mathew Inwood8c854f82018-09-14 12:35:36 +01001697 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Jeff Sharkeya0907432014-08-15 10:23:11 -07001698 public float progress;
1699 /** {@hide} */
Mathew Inwood5c0d3542018-08-14 13:54:31 +01001700 @UnsupportedAppUsage
Jeff Sharkeya0907432014-08-15 10:23:11 -07001701 public boolean sealed;
1702 /** {@hide} */
Mathew Inwood8c854f82018-09-14 12:35:36 +01001703 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001704 public boolean active;
Jeff Sharkeya0907432014-08-15 10:23:11 -07001705
1706 /** {@hide} */
Mathew Inwood8c854f82018-09-14 12:35:36 +01001707 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Jeff Sharkeya0907432014-08-15 10:23:11 -07001708 public int mode;
1709 /** {@hide} */
Bartosz Fabianowski40a00622017-04-18 14:39:23 +02001710 public @InstallReason int installReason;
Sunny Goyal6d7cb232017-01-30 10:43:18 -08001711 /** {@hide} */
Mathew Inwood8c854f82018-09-14 12:35:36 +01001712 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Jeff Sharkeya0907432014-08-15 10:23:11 -07001713 public long sizeBytes;
1714 /** {@hide} */
Mathew Inwood8c854f82018-09-14 12:35:36 +01001715 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Jeff Sharkeya0907432014-08-15 10:23:11 -07001716 public String appPackageName;
1717 /** {@hide} */
Mathew Inwood8c854f82018-09-14 12:35:36 +01001718 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Jeff Sharkeya0907432014-08-15 10:23:11 -07001719 public Bitmap appIcon;
1720 /** {@hide} */
Mathew Inwood8c854f82018-09-14 12:35:36 +01001721 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Jeff Sharkeya0907432014-08-15 10:23:11 -07001722 public CharSequence appLabel;
1723
1724 /** {@hide} */
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001725 public int installLocation;
1726 /** {@hide} */
1727 public Uri originatingUri;
1728 /** {@hide} */
1729 public int originatingUid;
1730 /** {@hide} */
1731 public Uri referrerUri;
1732 /** {@hide} */
1733 public String[] grantedRuntimePermissions;
1734 /** {@hide} */
1735 public int installFlags;
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001736 /** {@hide} */
1737 public boolean isMultiPackage;
1738 /** {@hide} */
Dario Freniaac4ba42018-12-06 15:47:16 +00001739 public boolean isStaged;
1740 /** {@hide} */
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001741 public int parentSessionId = INVALID_ID;
1742 /** {@hide} */
1743 public int[] childSessionIds = NO_SESSIONS;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001744
1745 /** {@hide} */
Dario Freni60a96c12019-02-24 21:01:29 +00001746 public boolean isStagedSessionApplied;
Dario Freni71eee5e2018-12-06 15:47:16 +00001747 /** {@hide} */
Dario Freni60a96c12019-02-24 21:01:29 +00001748 public boolean isStagedSessionReady;
Dario Freni71eee5e2018-12-06 15:47:16 +00001749 /** {@hide} */
Dario Freni60a96c12019-02-24 21:01:29 +00001750 public boolean isStagedSessionFailed;
Dario Freni71eee5e2018-12-06 15:47:16 +00001751 private int mStagedSessionErrorCode;
Dario Freni275b4ab2019-01-25 09:55:16 +00001752 private String mStagedSessionErrorMessage;
Dario Freni71eee5e2018-12-06 15:47:16 +00001753
1754 /** {@hide} */
Mathew Inwood5c0d3542018-08-14 13:54:31 +01001755 @UnsupportedAppUsage
Jeff Sharkeya0907432014-08-15 10:23:11 -07001756 public SessionInfo() {
1757 }
1758
1759 /** {@hide} */
1760 public SessionInfo(Parcel source) {
1761 sessionId = source.readInt();
Jon Miranda2b340a22019-01-25 14:03:49 -08001762 userId = source.readInt();
Jeff Sharkeya0907432014-08-15 10:23:11 -07001763 installerPackageName = source.readString();
1764 resolvedBaseCodePath = source.readString();
1765 progress = source.readFloat();
1766 sealed = source.readInt() != 0;
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001767 active = source.readInt() != 0;
Jeff Sharkeya0907432014-08-15 10:23:11 -07001768
1769 mode = source.readInt();
Sunny Goyal6d7cb232017-01-30 10:43:18 -08001770 installReason = source.readInt();
Jeff Sharkeya0907432014-08-15 10:23:11 -07001771 sizeBytes = source.readLong();
1772 appPackageName = source.readString();
1773 appIcon = source.readParcelable(null);
1774 appLabel = source.readString();
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001775
1776 installLocation = source.readInt();
1777 originatingUri = source.readParcelable(null);
1778 originatingUid = source.readInt();
1779 referrerUri = source.readParcelable(null);
1780 grantedRuntimePermissions = source.readStringArray();
1781 installFlags = source.readInt();
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001782 isMultiPackage = source.readBoolean();
Dario Freniaac4ba42018-12-06 15:47:16 +00001783 isStaged = source.readBoolean();
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001784 parentSessionId = source.readInt();
1785 childSessionIds = source.createIntArray();
1786 if (childSessionIds == null) {
1787 childSessionIds = NO_SESSIONS;
1788 }
Dario Freni60a96c12019-02-24 21:01:29 +00001789 isStagedSessionApplied = source.readBoolean();
1790 isStagedSessionReady = source.readBoolean();
1791 isStagedSessionFailed = source.readBoolean();
Dario Freni71eee5e2018-12-06 15:47:16 +00001792 mStagedSessionErrorCode = source.readInt();
Dario Freni275b4ab2019-01-25 09:55:16 +00001793 mStagedSessionErrorMessage = source.readString();
Jeff Sharkeya0907432014-08-15 10:23:11 -07001794 }
Jeff Sharkeybb580672014-07-10 12:10:25 -07001795
1796 /**
Jeff Sharkeya0907432014-08-15 10:23:11 -07001797 * Return the ID for this session.
Jeff Sharkeybb580672014-07-10 12:10:25 -07001798 */
Jeff Sharkeya0907432014-08-15 10:23:11 -07001799 public int getSessionId() {
1800 return sessionId;
1801 }
Jeff Sharkeybb580672014-07-10 12:10:25 -07001802
1803 /**
Jon Miranda2b340a22019-01-25 14:03:49 -08001804 * Return the user associated with this session.
1805 */
1806 public UserHandle getUser() {
1807 return new UserHandle(userId);
1808 }
1809
1810 /**
Jeff Sharkeya0907432014-08-15 10:23:11 -07001811 * Return the package name of the app that owns this session.
1812 */
1813 public @Nullable String getInstallerPackageName() {
1814 return installerPackageName;
1815 }
1816
1817 /**
1818 * Return current overall progress of this session, between 0 and 1.
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07001819 * <p>
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001820 * Note that this progress may not directly correspond to the value
1821 * reported by
1822 * {@link PackageInstaller.Session#setStagingProgress(float)}, as the
1823 * system may carve out a portion of the overall progress to represent
1824 * its own internal installation work.
Jeff Sharkeybb580672014-07-10 12:10:25 -07001825 */
Jeff Sharkeya0907432014-08-15 10:23:11 -07001826 public float getProgress() {
1827 return progress;
1828 }
Jeff Sharkeybb580672014-07-10 12:10:25 -07001829
1830 /**
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001831 * Return if this session is currently active.
1832 * <p>
1833 * A session is considered active whenever there is ongoing forward
1834 * progress being made, such as the installer holding an open
1835 * {@link Session} instance while streaming data into place, or the
1836 * system optimizing code as the result of
1837 * {@link Session#commit(IntentSender)}.
1838 * <p>
1839 * If the installer closes the {@link Session} without committing, the
1840 * session is considered inactive until the installer opens the session
1841 * again.
Jeff Sharkeybb580672014-07-10 12:10:25 -07001842 */
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001843 public boolean isActive() {
1844 return active;
1845 }
1846
Sunny Goyal6d7cb232017-01-30 10:43:18 -08001847 /**
Todd Kennedy04cc1912017-03-03 13:05:12 -08001848 * Return if this session is sealed.
1849 * <p>
1850 * Once sealed, no further changes may be made to the session. A session
1851 * is sealed the moment {@link Session#commit(IntentSender)} is called.
1852 */
1853 public boolean isSealed() {
1854 return sealed;
1855 }
1856
1857 /**
Sunny Goyal6d7cb232017-01-30 10:43:18 -08001858 * Return the reason for installing this package.
1859 *
Bartosz Fabianowski40a00622017-04-18 14:39:23 +02001860 * @return The install reason.
Sunny Goyal6d7cb232017-01-30 10:43:18 -08001861 */
Bartosz Fabianowski40a00622017-04-18 14:39:23 +02001862 public @InstallReason int getInstallReason() {
Sunny Goyal6d7cb232017-01-30 10:43:18 -08001863 return installReason;
1864 }
1865
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001866 /** {@hide} */
1867 @Deprecated
Jeff Sharkeya0907432014-08-15 10:23:11 -07001868 public boolean isOpen() {
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001869 return isActive();
Jeff Sharkeya0907432014-08-15 10:23:11 -07001870 }
Jeff Sharkeybb580672014-07-10 12:10:25 -07001871
1872 /**
Jeff Sharkeya0907432014-08-15 10:23:11 -07001873 * Return the package name this session is working with. May be {@code null}
1874 * if unknown.
Jeff Sharkeybb580672014-07-10 12:10:25 -07001875 */
Jeff Sharkeya0907432014-08-15 10:23:11 -07001876 public @Nullable String getAppPackageName() {
1877 return appPackageName;
1878 }
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07001879
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001880 /**
Jeff Sharkeya0907432014-08-15 10:23:11 -07001881 * Return an icon representing the app being installed. May be {@code null}
1882 * if unavailable.
1883 */
1884 public @Nullable Bitmap getAppIcon() {
Jeff Sharkeyda1247a2017-06-08 14:13:29 -06001885 if (appIcon == null) {
1886 // Icon may have been omitted for calls that return bulk session
1887 // lists, so try fetching the specific icon.
1888 try {
Jeff Sharkeyd1dd2c62017-08-02 09:28:53 -06001889 final SessionInfo info = AppGlobals.getPackageManager().getPackageInstaller()
1890 .getSessionInfo(sessionId);
1891 appIcon = (info != null) ? info.appIcon : null;
Jeff Sharkeyda1247a2017-06-08 14:13:29 -06001892 } catch (RemoteException e) {
1893 throw e.rethrowFromSystemServer();
1894 }
1895 }
Jeff Sharkeya0907432014-08-15 10:23:11 -07001896 return appIcon;
1897 }
1898
1899 /**
1900 * Return a label representing the app being installed. May be {@code null}
1901 * if unavailable.
1902 */
1903 public @Nullable CharSequence getAppLabel() {
1904 return appLabel;
1905 }
1906
1907 /**
1908 * Return an Intent that can be started to view details about this install
1909 * session. This may surface actions such as pause, resume, or cancel.
1910 * <p>
1911 * In some cases, a matching Activity may not exist, so ensure you safeguard
1912 * against this.
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001913 *
Jeff Sharkeya0907432014-08-15 10:23:11 -07001914 * @see PackageInstaller#ACTION_SESSION_DETAILS
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001915 */
Jeff Sharkeyde742312014-09-15 14:04:56 -07001916 public @Nullable Intent createDetailsIntent() {
Jeff Sharkeya0907432014-08-15 10:23:11 -07001917 final Intent intent = new Intent(PackageInstaller.ACTION_SESSION_DETAILS);
1918 intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
1919 intent.setPackage(installerPackageName);
1920 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1921 return intent;
Jeff Sharkeybb580672014-07-10 12:10:25 -07001922 }
1923
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001924 /**
1925 * Get the mode of the session as set in the constructor of the {@link SessionParams}.
1926 *
1927 * @return One of {@link SessionParams#MODE_FULL_INSTALL}
1928 * or {@link SessionParams#MODE_INHERIT_EXISTING}
1929 */
1930 public int getMode() {
1931 return mode;
1932 }
1933
1934 /**
1935 * Get the value set in {@link SessionParams#setInstallLocation(int)}.
1936 */
1937 public int getInstallLocation() {
1938 return installLocation;
1939 }
1940
1941 /**
1942 * Get the value as set in {@link SessionParams#setSize(long)}.
1943 *
1944 * <p>The value is a hint and does not have to match the actual size.
1945 */
1946 public long getSize() {
1947 return sizeBytes;
1948 }
1949
1950 /**
1951 * Get the value set in {@link SessionParams#setOriginatingUri(Uri)}.
1952 */
1953 public @Nullable Uri getOriginatingUri() {
1954 return originatingUri;
1955 }
1956
1957 /**
1958 * Get the value set in {@link SessionParams#setOriginatingUid(int)}.
1959 */
1960 public int getOriginatingUid() {
1961 return originatingUid;
1962 }
1963
1964 /**
1965 * Get the value set in {@link SessionParams#setReferrerUri(Uri)}
1966 */
1967 public @Nullable Uri getReferrerUri() {
1968 return referrerUri;
1969 }
1970
1971 /**
1972 * Get the value set in {@link SessionParams#setGrantedRuntimePermissions(String[])}.
1973 *
1974 * @hide
1975 */
1976 @SystemApi
1977 public @Nullable String[] getGrantedRuntimePermissions() {
1978 return grantedRuntimePermissions;
1979 }
1980
1981 /**
1982 * Get the value set in {@link SessionParams#setAllowDowngrade(boolean)}.
1983 *
1984 * @hide
1985 */
1986 @SystemApi
1987 public boolean getAllowDowngrade() {
1988 return (installFlags & PackageManager.INSTALL_ALLOW_DOWNGRADE) != 0;
1989 }
1990
1991 /**
1992 * Get the value set in {@link SessionParams#setDontKillApp(boolean)}.
1993 *
1994 * @hide
1995 */
1996 @SystemApi
1997 public boolean getDontKillApp() {
1998 return (installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0;
1999 }
2000
2001 /**
2002 * If {@link SessionParams#setInstallAsInstantApp(boolean)} was called with {@code true},
2003 * return true. If it was called with {@code false} or if it was not called return false.
2004 *
2005 * @hide
2006 *
2007 * @see #getInstallAsFullApp
2008 */
2009 @SystemApi
2010 public boolean getInstallAsInstantApp(boolean isInstantApp) {
2011 return (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
2012 }
2013
2014 /**
2015 * If {@link SessionParams#setInstallAsInstantApp(boolean)} was called with {@code false},
2016 * return true. If it was called with {@code true} or if it was not called return false.
2017 *
2018 * @hide
2019 *
2020 * @see #getInstallAsInstantApp
2021 */
2022 @SystemApi
2023 public boolean getInstallAsFullApp(boolean isInstantApp) {
2024 return (installFlags & PackageManager.INSTALL_FULL_APP) != 0;
2025 }
2026
2027 /**
2028 * Get if {@link SessionParams#setInstallAsVirtualPreload()} was called.
2029 *
2030 * @hide
2031 */
2032 @SystemApi
2033 public boolean getInstallAsVirtualPreload() {
2034 return (installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0;
2035 }
2036
2037 /**
2038 * Get the value set in {@link SessionParams#setAllocateAggressive(boolean)}.
2039 *
2040 * @hide
2041 */
2042 @SystemApi
2043 public boolean getAllocateAggressive() {
2044 return (installFlags & PackageManager.INSTALL_ALLOCATE_AGGRESSIVE) != 0;
2045 }
2046
2047
Jeff Sharkeyde742312014-09-15 14:04:56 -07002048 /** {@hide} */
2049 @Deprecated
2050 public @Nullable Intent getDetailsIntent() {
2051 return createDetailsIntent();
2052 }
2053
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002054 /**
2055 * Returns true if this session is a multi-package session containing references to other
2056 * sessions.
2057 */
2058 public boolean isMultiPackage() {
2059 return isMultiPackage;
2060 }
2061
2062 /**
Dario Freniaac4ba42018-12-06 15:47:16 +00002063 * Returns true if this session is a staged session which will be applied at next reboot.
2064 */
2065 public boolean isStaged() {
2066 return isStaged;
2067 }
2068
2069 /**
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002070 * Returns the parent multi-package session ID if this session belongs to one,
2071 * {@link #INVALID_ID} otherwise.
2072 */
2073 public int getParentSessionId() {
2074 return parentSessionId;
2075 }
2076
2077 /**
2078 * Returns the set of session IDs that will be committed when this session is commited if
2079 * this session is a multi-package session.
2080 */
2081 public int[] getChildSessionIds() {
2082 return childSessionIds;
2083 }
2084
Dario Freni60a96c12019-02-24 21:01:29 +00002085 private void checkSessionIsStaged() {
2086 if (!isStaged) {
2087 throw new IllegalStateException("Session is not marked as staged.");
2088 }
2089 }
2090
Dario Freni71eee5e2018-12-06 15:47:16 +00002091 /**
2092 * Whether the staged session has been applied successfully, meaning that all of its
2093 * packages have been activated and no further action is required.
2094 * Only meaningful if {@code isStaged} is true.
2095 */
Dario Freni60a96c12019-02-24 21:01:29 +00002096 public boolean isStagedSessionApplied() {
2097 checkSessionIsStaged();
2098 return isStagedSessionApplied;
Dario Freni71eee5e2018-12-06 15:47:16 +00002099 }
2100
2101 /**
2102 * Whether the staged session is ready to be applied at next reboot. Only meaningful if
2103 * {@code isStaged} is true.
2104 */
Dario Freni60a96c12019-02-24 21:01:29 +00002105 public boolean isStagedSessionReady() {
2106 checkSessionIsStaged();
2107 return isStagedSessionReady;
Dario Freni71eee5e2018-12-06 15:47:16 +00002108 }
2109
2110 /**
2111 * Whether something went wrong and the staged session is declared as failed, meaning that
2112 * it will be ignored at next reboot. Only meaningful if {@code isStaged} is true.
2113 */
Dario Freni60a96c12019-02-24 21:01:29 +00002114 public boolean isStagedSessionFailed() {
2115 checkSessionIsStaged();
2116 return isStagedSessionFailed;
Dario Freni71eee5e2018-12-06 15:47:16 +00002117 }
2118
2119 /**
2120 * If something went wrong with a staged session, clients can check this error code to
2121 * understand which kind of failure happened. Only meaningful if {@code isStaged} is true.
2122 */
Dario Freni60a96c12019-02-24 21:01:29 +00002123 public @StagedSessionErrorCode int getStagedSessionErrorCode() {
2124 checkSessionIsStaged();
Dario Freni71eee5e2018-12-06 15:47:16 +00002125 return mStagedSessionErrorCode;
2126 }
2127
Dario Freni275b4ab2019-01-25 09:55:16 +00002128 /**
2129 * Text description of the error code returned by {@code getStagedSessionErrorCode}, or
2130 * empty string if no error was encountered.
2131 */
2132 public String getStagedSessionErrorMessage() {
Dario Freni60a96c12019-02-24 21:01:29 +00002133 checkSessionIsStaged();
Dario Freni275b4ab2019-01-25 09:55:16 +00002134 return mStagedSessionErrorMessage;
2135 }
2136
Dario Freni71eee5e2018-12-06 15:47:16 +00002137 /** {@hide} */
Dario Freni275b4ab2019-01-25 09:55:16 +00002138 public void setStagedSessionErrorCode(@StagedSessionErrorCode int errorCode,
2139 String errorMessage) {
Dario Freni71eee5e2018-12-06 15:47:16 +00002140 mStagedSessionErrorCode = errorCode;
Dario Freni275b4ab2019-01-25 09:55:16 +00002141 mStagedSessionErrorMessage = errorMessage;
Dario Freni71eee5e2018-12-06 15:47:16 +00002142 }
2143
Jeff Sharkeybb580672014-07-10 12:10:25 -07002144 @Override
Jeff Sharkeya0907432014-08-15 10:23:11 -07002145 public int describeContents() {
2146 return 0;
Jeff Sharkeyfbd0e9f2014-08-06 16:34:34 -07002147 }
2148
2149 @Override
Jeff Sharkeya0907432014-08-15 10:23:11 -07002150 public void writeToParcel(Parcel dest, int flags) {
2151 dest.writeInt(sessionId);
Jon Miranda2b340a22019-01-25 14:03:49 -08002152 dest.writeInt(userId);
Jeff Sharkeya0907432014-08-15 10:23:11 -07002153 dest.writeString(installerPackageName);
2154 dest.writeString(resolvedBaseCodePath);
2155 dest.writeFloat(progress);
2156 dest.writeInt(sealed ? 1 : 0);
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07002157 dest.writeInt(active ? 1 : 0);
Jeff Sharkeybb580672014-07-10 12:10:25 -07002158
Jeff Sharkeya0907432014-08-15 10:23:11 -07002159 dest.writeInt(mode);
Sunny Goyal6d7cb232017-01-30 10:43:18 -08002160 dest.writeInt(installReason);
Jeff Sharkeya0907432014-08-15 10:23:11 -07002161 dest.writeLong(sizeBytes);
2162 dest.writeString(appPackageName);
2163 dest.writeParcelable(appIcon, flags);
2164 dest.writeString(appLabel != null ? appLabel.toString() : null);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002165
2166 dest.writeInt(installLocation);
2167 dest.writeParcelable(originatingUri, flags);
2168 dest.writeInt(originatingUid);
2169 dest.writeParcelable(referrerUri, flags);
2170 dest.writeStringArray(grantedRuntimePermissions);
2171 dest.writeInt(installFlags);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002172 dest.writeBoolean(isMultiPackage);
Dario Freniaac4ba42018-12-06 15:47:16 +00002173 dest.writeBoolean(isStaged);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002174 dest.writeInt(parentSessionId);
2175 dest.writeIntArray(childSessionIds);
Dario Freni60a96c12019-02-24 21:01:29 +00002176 dest.writeBoolean(isStagedSessionApplied);
2177 dest.writeBoolean(isStagedSessionReady);
2178 dest.writeBoolean(isStagedSessionFailed);
Dario Freni71eee5e2018-12-06 15:47:16 +00002179 dest.writeInt(mStagedSessionErrorCode);
Dario Freni275b4ab2019-01-25 09:55:16 +00002180 dest.writeString(mStagedSessionErrorMessage);
Jeff Sharkeybb580672014-07-10 12:10:25 -07002181 }
Jeff Sharkeya0907432014-08-15 10:23:11 -07002182
2183 public static final Parcelable.Creator<SessionInfo>
2184 CREATOR = new Parcelable.Creator<SessionInfo>() {
2185 @Override
2186 public SessionInfo createFromParcel(Parcel p) {
2187 return new SessionInfo(p);
2188 }
2189
2190 @Override
2191 public SessionInfo[] newArray(int size) {
2192 return new SessionInfo[size];
2193 }
2194 };
Jeff Sharkeybb580672014-07-10 12:10:25 -07002195 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002196}