blob: 25af1a76700ff0be81eae4b2879634c0c50b0dff [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;
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -070020import android.annotation.NonNull;
21import android.annotation.Nullable;
Svet Ganov7121e182015-07-13 22:38:12 -070022import android.annotation.RequiresPermission;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070023import android.annotation.SdkConstant;
24import android.annotation.SdkConstant.SdkConstantType;
Svet Ganov7121e182015-07-13 22:38:12 -070025import android.annotation.SystemApi;
Jeff Sharkeya0907432014-08-15 10:23:11 -070026import android.app.ActivityManager;
Jeff Sharkeyda1247a2017-06-08 14:13:29 -060027import android.app.AppGlobals;
Jeff Sharkeyfbd0e9f2014-08-06 16:34:34 -070028import android.content.Intent;
Jeff Sharkeya0907432014-08-15 10:23:11 -070029import android.content.IntentSender;
Todd Kennedycda831f2017-05-16 10:54:33 -070030import android.content.pm.PackageManager.DeleteFlags;
Bartosz Fabianowski40a00622017-04-18 14:39:23 +020031import android.content.pm.PackageManager.InstallReason;
Jeff Sharkeya0907432014-08-15 10:23:11 -070032import android.graphics.Bitmap;
33import android.net.Uri;
Jeff Sharkey78cc3402014-05-22 10:52:49 -070034import android.os.FileBridge;
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -070035import android.os.Handler;
36import android.os.Looper;
37import android.os.Message;
Jeff Sharkeya0907432014-08-15 10:23:11 -070038import android.os.Parcel;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070039import android.os.ParcelFileDescriptor;
Jeff Sharkeya0907432014-08-15 10:23:11 -070040import android.os.Parcelable;
Philip P. Moltmann7460c592017-08-08 20:07:11 +000041import android.os.ParcelableException;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070042import android.os.RemoteException;
Jeff Sharkey02d4e342017-03-10 21:53:48 -070043import android.os.SystemProperties;
44import android.system.ErrnoException;
45import android.system.Os;
Jeff Sharkeya1031142014-07-12 18:09:46 -070046import android.util.ExceptionUtils;
Jeff Sharkeya0907432014-08-15 10:23:11 -070047
48import com.android.internal.util.IndentingPrintWriter;
Svet Ganov67882122016-12-11 16:36:34 -080049import com.android.internal.util.Preconditions;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070050
Jeff Sharkeyec55ef02014-07-08 11:28:00 -070051import java.io.Closeable;
Jeff Sharkeya1031142014-07-12 18:09:46 -070052import java.io.IOException;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070053import java.io.InputStream;
Jeff Sharkey78cc3402014-05-22 10:52:49 -070054import java.io.OutputStream;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070055import java.security.MessageDigest;
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -070056import java.util.ArrayList;
57import java.util.Iterator;
Jeff Sharkeybb580672014-07-10 12:10:25 -070058import java.util.List;
Jeff Sharkey78cc3402014-05-22 10:52:49 -070059
Jeff Sharkey6c833e02014-07-14 22:44:30 -070060/**
61 * Offers the ability to install, upgrade, and remove applications on the
62 * device. This includes support for apps packaged either as a single
63 * "monolithic" APK, or apps packaged as multiple "split" APKs.
64 * <p>
65 * An app is delivered for installation through a
66 * {@link PackageInstaller.Session}, which any app can create. Once the session
67 * is created, the installer can stream one or more APKs into place until it
68 * decides to either commit or destroy the session. Committing may require user
69 * intervention to complete the installation.
70 * <p>
71 * Sessions can install brand new apps, upgrade existing apps, or add new splits
Jeff Sharkeyda96e132014-07-15 14:54:09 -070072 * into an existing app.
Jeff Sharkey6c833e02014-07-14 22:44:30 -070073 * <p>
Jeff Sharkeyda96e132014-07-15 14:54:09 -070074 * Apps packaged as multiple split APKs always consist of a single "base" APK
Jeff Sharkey6c833e02014-07-14 22:44:30 -070075 * (with a {@code null} split name) and zero or more "split" APKs (with unique
76 * split names). Any subset of these APKs can be installed together, as long as
77 * the following constraints are met:
78 * <ul>
79 * <li>All APKs must have the exact same package name, version code, and signing
80 * certificates.
Jeff Sharkey6c833e02014-07-14 22:44:30 -070081 * <li>All APKs must have unique split names.
Jeff Sharkeyda96e132014-07-15 14:54:09 -070082 * <li>All installations must contain a single base APK.
Jeff Sharkey6c833e02014-07-14 22:44:30 -070083 * </ul>
Peter Visontayf702fd42017-11-17 14:00:47 +000084 * <p>
85 * The ApiDemos project contains examples of using this API:
86 * <code>ApiDemos/src/com/example/android/apis/content/InstallApk*.java</code>.
Jeff Sharkey6c833e02014-07-14 22:44:30 -070087 */
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070088public class PackageInstaller {
Jeff Sharkeya0907432014-08-15 10:23:11 -070089 private static final String TAG = "PackageInstaller";
90
Jeff Sharkey02d4e342017-03-10 21:53:48 -070091 /** {@hide} */
92 public static final boolean ENABLE_REVOCABLE_FD =
93 SystemProperties.getBoolean("fw.revocable_fd", false);
94
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070095 /**
96 * Activity Action: Show details about a particular install session. This
97 * may surface actions such as pause, resume, or cancel.
98 * <p>
99 * This should always be scoped to the installer package that owns the
Jeff Sharkeyde742312014-09-15 14:04:56 -0700100 * session. Clients should use {@link SessionInfo#createDetailsIntent()} to
Jeff Sharkeya0907432014-08-15 10:23:11 -0700101 * build this intent correctly.
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700102 * <p>
103 * In some cases, a matching Activity may not exist, so ensure you safeguard
104 * against this.
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700105 * <p>
106 * The session to show details for is defined in {@link #EXTRA_SESSION_ID}.
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700107 */
108 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
109 public static final String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS";
110
Sunny Goyal6d7cb232017-01-30 10:43:18 -0800111 /**
112 * Broadcast Action: Explicit broadcast sent to the last known default launcher when a session
113 * for a new install is committed. For managed profile, this is sent to the default launcher
114 * of the primary profile.
115 * <p>
116 * The associated session is defined in {@link #EXTRA_SESSION} and the user for which this
117 * session was created in {@link Intent#EXTRA_USER}.
118 */
119 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
120 public static final String ACTION_SESSION_COMMITTED =
121 "android.content.pm.action.SESSION_COMMITTED";
122
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700123 /** {@hide} */
124 public static final String
125 ACTION_CONFIRM_PERMISSIONS = "android.content.pm.action.CONFIRM_PERMISSIONS";
126
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700127 /**
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700128 * An integer session ID that an operation is working with.
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700129 *
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700130 * @see Intent#getIntExtra(String, int)
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700131 */
132 public static final String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID";
133
Jeff Sharkeya0907432014-08-15 10:23:11 -0700134 /**
Sunny Goyal6d7cb232017-01-30 10:43:18 -0800135 * {@link SessionInfo} that an operation is working with.
136 *
137 * @see Intent#getParcelableExtra(String)
138 */
139 public static final String EXTRA_SESSION = "android.content.pm.extra.SESSION";
140
141 /**
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700142 * Package name that an operation is working with.
Jeff Sharkeya0907432014-08-15 10:23:11 -0700143 *
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700144 * @see Intent#getStringExtra(String)
Jeff Sharkeya0907432014-08-15 10:23:11 -0700145 */
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700146 public static final String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME";
147
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700148 /**
149 * Current status of an operation. Will be one of
150 * {@link #STATUS_PENDING_USER_ACTION}, {@link #STATUS_SUCCESS},
151 * {@link #STATUS_FAILURE}, {@link #STATUS_FAILURE_ABORTED},
152 * {@link #STATUS_FAILURE_BLOCKED}, {@link #STATUS_FAILURE_CONFLICT},
153 * {@link #STATUS_FAILURE_INCOMPATIBLE}, {@link #STATUS_FAILURE_INVALID}, or
154 * {@link #STATUS_FAILURE_STORAGE}.
155 * <p>
156 * More information about a status may be available through additional
157 * extras; see the individual status documentation for details.
158 *
159 * @see Intent#getIntExtra(String, int)
160 */
161 public static final String EXTRA_STATUS = "android.content.pm.extra.STATUS";
162
163 /**
164 * Detailed string representation of the status, including raw details that
165 * are useful for debugging.
166 *
167 * @see Intent#getStringExtra(String)
168 */
169 public static final String EXTRA_STATUS_MESSAGE = "android.content.pm.extra.STATUS_MESSAGE";
170
171 /**
172 * Another package name relevant to a status. This is typically the package
173 * responsible for causing an operation failure.
174 *
175 * @see Intent#getStringExtra(String)
176 */
177 public static final String
178 EXTRA_OTHER_PACKAGE_NAME = "android.content.pm.extra.OTHER_PACKAGE_NAME";
179
180 /**
181 * Storage path relevant to a status.
182 *
183 * @see Intent#getStringExtra(String)
184 */
185 public static final String EXTRA_STORAGE_PATH = "android.content.pm.extra.STORAGE_PATH";
186
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700187 /** {@hide} */
188 @Deprecated
Jeff Sharkeya0907432014-08-15 10:23:11 -0700189 public static final String EXTRA_PACKAGE_NAMES = "android.content.pm.extra.PACKAGE_NAMES";
190
191 /** {@hide} */
192 public static final String EXTRA_LEGACY_STATUS = "android.content.pm.extra.LEGACY_STATUS";
193 /** {@hide} */
194 public static final String EXTRA_LEGACY_BUNDLE = "android.content.pm.extra.LEGACY_BUNDLE";
Jeff Sharkeyf0600952014-08-07 17:31:53 -0700195 /** {@hide} */
196 public static final String EXTRA_CALLBACK = "android.content.pm.extra.CALLBACK";
197
Jeff Sharkeya0907432014-08-15 10:23:11 -0700198 /**
199 * User action is currently required to proceed. You can launch the intent
200 * activity described by {@link Intent#EXTRA_INTENT} to involve the user and
201 * continue.
202 * <p>
203 * You may choose to immediately launch the intent if the user is actively
204 * using your app. Otherwise, you should use a notification to guide the
205 * user back into your app before launching.
206 *
207 * @see Intent#getParcelableExtra(String)
208 */
Jeff Sharkey742e7902014-08-16 19:09:13 -0700209 public static final int STATUS_PENDING_USER_ACTION = -1;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700210
211 /**
212 * The operation succeeded.
213 */
214 public static final int STATUS_SUCCESS = 0;
215
216 /**
217 * The operation failed in a generic way. The system will always try to
218 * provide a more specific failure reason, but in some rare cases this may
219 * be delivered.
220 *
221 * @see #EXTRA_STATUS_MESSAGE
222 */
223 public static final int STATUS_FAILURE = 1;
224
225 /**
226 * The operation failed because it was blocked. For example, a device policy
227 * may be blocking the operation, a package verifier may have blocked the
228 * operation, or the app may be required for core system operation.
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700229 * <p>
230 * The result may also contain {@link #EXTRA_OTHER_PACKAGE_NAME} with the
231 * specific package blocking the install.
Jeff Sharkeya0907432014-08-15 10:23:11 -0700232 *
233 * @see #EXTRA_STATUS_MESSAGE
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700234 * @see #EXTRA_OTHER_PACKAGE_NAME
Jeff Sharkeya0907432014-08-15 10:23:11 -0700235 */
Jeff Sharkey742e7902014-08-16 19:09:13 -0700236 public static final int STATUS_FAILURE_BLOCKED = 2;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700237
238 /**
239 * The operation failed because it was actively aborted. For example, the
240 * user actively declined requested permissions, or the session was
241 * abandoned.
242 *
243 * @see #EXTRA_STATUS_MESSAGE
244 */
Jeff Sharkey742e7902014-08-16 19:09:13 -0700245 public static final int STATUS_FAILURE_ABORTED = 3;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700246
247 /**
248 * The operation failed because one or more of the APKs was invalid. For
249 * example, they might be malformed, corrupt, incorrectly signed,
250 * mismatched, etc.
251 *
252 * @see #EXTRA_STATUS_MESSAGE
253 */
Jeff Sharkey742e7902014-08-16 19:09:13 -0700254 public static final int STATUS_FAILURE_INVALID = 4;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700255
256 /**
257 * The operation failed because it conflicts (or is inconsistent with) with
258 * another package already installed on the device. For example, an existing
259 * permission, incompatible certificates, etc. The user may be able to
260 * uninstall another app to fix the issue.
261 * <p>
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700262 * The result may also contain {@link #EXTRA_OTHER_PACKAGE_NAME} with the
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700263 * specific package identified as the cause of the conflict.
Jeff Sharkeya0907432014-08-15 10:23:11 -0700264 *
265 * @see #EXTRA_STATUS_MESSAGE
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700266 * @see #EXTRA_OTHER_PACKAGE_NAME
Jeff Sharkeya0907432014-08-15 10:23:11 -0700267 */
Jeff Sharkey742e7902014-08-16 19:09:13 -0700268 public static final int STATUS_FAILURE_CONFLICT = 5;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700269
270 /**
271 * The operation failed because of storage issues. For example, the device
272 * may be running low on space, or external media may be unavailable. The
273 * user may be able to help free space or insert different external media.
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700274 * <p>
275 * The result may also contain {@link #EXTRA_STORAGE_PATH} with the path to
276 * the storage device that caused the failure.
Jeff Sharkeya0907432014-08-15 10:23:11 -0700277 *
278 * @see #EXTRA_STATUS_MESSAGE
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700279 * @see #EXTRA_STORAGE_PATH
Jeff Sharkeya0907432014-08-15 10:23:11 -0700280 */
Jeff Sharkey742e7902014-08-16 19:09:13 -0700281 public static final int STATUS_FAILURE_STORAGE = 6;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700282
283 /**
284 * The operation failed because it is fundamentally incompatible with this
285 * device. For example, the app may require a hardware feature that doesn't
286 * exist, it may be missing native code for the ABIs supported by the
287 * device, or it requires a newer SDK version, etc.
288 *
289 * @see #EXTRA_STATUS_MESSAGE
290 */
Jeff Sharkey742e7902014-08-16 19:09:13 -0700291 public static final int STATUS_FAILURE_INCOMPATIBLE = 7;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700292
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700293 private final IPackageInstaller mInstaller;
294 private final int mUserId;
295 private final String mInstallerPackageName;
296
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700297 private final ArrayList<SessionCallbackDelegate> mDelegates = new ArrayList<>();
298
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700299 /** {@hide} */
Svet Ganov67882122016-12-11 16:36:34 -0800300 public PackageInstaller(IPackageInstaller installer,
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700301 String installerPackageName, int userId) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700302 mInstaller = installer;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700303 mInstallerPackageName = installerPackageName;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700304 mUserId = userId;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700305 }
306
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700307 /**
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700308 * Create a new session using the given parameters, returning a unique ID
309 * that represents the session. Once created, the session can be opened
310 * multiple times across multiple device boots.
311 * <p>
312 * The system may automatically destroy sessions that have not been
313 * finalized (either committed or abandoned) within a reasonable period of
314 * time, typically on the order of a day.
315 *
316 * @throws IOException if parameters were unsatisfiable, such as lack of
317 * disk space or unavailable media.
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700318 * @throws SecurityException when installation services are unavailable,
319 * such as when called from a restricted user.
320 * @throws IllegalArgumentException when {@link SessionParams} is invalid.
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700321 * @return positive, non-zero unique ID that represents the created session.
322 * This ID remains consistent across device reboots until the
323 * session is finalized. IDs are not reused during a given boot.
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700324 */
Jeff Sharkeya0907432014-08-15 10:23:11 -0700325 public int createSession(@NonNull SessionParams params) throws IOException {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700326 try {
Philip P. Moltmann79c238a2017-12-13 15:59:07 -0800327 final String installerPackage;
328 if (params.installerPackageName == null) {
329 installerPackage = mInstallerPackageName;
330 } else {
331 installerPackage = params.installerPackageName;
332 }
333
334 return mInstaller.createSession(params, installerPackage, mUserId);
Jeff Sharkeya1031142014-07-12 18:09:46 -0700335 } catch (RuntimeException e) {
336 ExceptionUtils.maybeUnwrapIOException(e);
337 throw e;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700338 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700339 throw e.rethrowFromSystemServer();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700340 }
341 }
342
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700343 /**
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700344 * Open an existing session to actively perform work. To succeed, the caller
345 * must be the owner of the install session.
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700346 *
347 * @throws IOException if parameters were unsatisfiable, such as lack of
348 * disk space or unavailable media.
349 * @throws SecurityException when the caller does not own the session, or
350 * the session is invalid.
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700351 */
Jeff Sharkeybc7bce32014-09-05 15:53:05 -0700352 public @NonNull Session openSession(int sessionId) throws IOException {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700353 try {
354 return new Session(mInstaller.openSession(sessionId));
Jeff Sharkeybc7bce32014-09-05 15:53:05 -0700355 } catch (RuntimeException e) {
356 ExceptionUtils.maybeUnwrapIOException(e);
357 throw e;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700358 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700359 throw e.rethrowFromSystemServer();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700360 }
361 }
362
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700363 /**
364 * Update the icon representing the app being installed in a specific
365 * session. This should be roughly
366 * {@link ActivityManager#getLauncherLargeIconSize()} in both dimensions.
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700367 *
368 * @throws SecurityException when the caller does not own the session, or
369 * the session is invalid.
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700370 */
371 public void updateSessionAppIcon(int sessionId, @Nullable Bitmap appIcon) {
372 try {
373 mInstaller.updateSessionAppIcon(sessionId, appIcon);
374 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700375 throw e.rethrowFromSystemServer();
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700376 }
377 }
378
379 /**
380 * Update the label representing the app being installed in a specific
381 * session.
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700382 *
383 * @throws SecurityException when the caller does not own the session, or
384 * the session is invalid.
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700385 */
386 public void updateSessionAppLabel(int sessionId, @Nullable CharSequence appLabel) {
387 try {
388 final String val = (appLabel != null) ? appLabel.toString() : null;
389 mInstaller.updateSessionAppLabel(sessionId, val);
390 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700391 throw e.rethrowFromSystemServer();
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700392 }
393 }
394
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700395 /**
396 * Completely abandon the given session, destroying all staged data and
397 * rendering it invalid. Abandoned sessions will be reported to
398 * {@link SessionCallback} listeners as failures. This is equivalent to
399 * opening the session and calling {@link Session#abandon()}.
400 *
401 * @throws SecurityException when the caller does not own the session, or
402 * the session is invalid.
403 */
Jeff Sharkey381d94b2014-08-24 14:45:56 -0700404 public void abandonSession(int sessionId) {
405 try {
406 mInstaller.abandonSession(sessionId);
407 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700408 throw e.rethrowFromSystemServer();
Jeff Sharkey381d94b2014-08-24 14:45:56 -0700409 }
410 }
411
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700412 /**
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700413 * Return details for a specific session. No special permissions are
414 * required to retrieve these details.
415 *
416 * @return details for the requested session, or {@code null} if the session
417 * does not exist.
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700418 */
Jeff Sharkeya0907432014-08-15 10:23:11 -0700419 public @Nullable SessionInfo getSessionInfo(int sessionId) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700420 try {
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700421 return mInstaller.getSessionInfo(sessionId);
422 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700423 throw e.rethrowFromSystemServer();
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700424 }
425 }
426
427 /**
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700428 * Return list of all known install sessions, regardless of the installer.
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700429 */
Jeff Sharkeya0907432014-08-15 10:23:11 -0700430 public @NonNull List<SessionInfo> getAllSessions() {
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700431 try {
Jeff Sharkey97d47ed2014-10-15 09:19:47 -0700432 return mInstaller.getAllSessions(mUserId).getList();
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700433 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700434 throw e.rethrowFromSystemServer();
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700435 }
436 }
437
438 /**
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700439 * Return list of all known install sessions owned by the calling app.
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700440 */
Jeff Sharkeya0907432014-08-15 10:23:11 -0700441 public @NonNull List<SessionInfo> getMySessions() {
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700442 try {
Jeff Sharkey97d47ed2014-10-15 09:19:47 -0700443 return mInstaller.getMySessions(mInstallerPackageName, mUserId).getList();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700444 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700445 throw e.rethrowFromSystemServer();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700446 }
447 }
448
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700449 /**
450 * Uninstall the given package, removing it completely from the device. This
Tony Mak366ee622018-02-12 17:52:34 +0000451 * method is available to:
452 * <ul>
453 * <li>the current "installer of record" for the package
454 * <li>the device owner
455 * <li>the affiliated profile owner
456 * </ul>
Svet Ganov67882122016-12-11 16:36:34 -0800457 *
458 * @param packageName The package to uninstall.
459 * @param statusReceiver Where to deliver the result.
Tony Mak366ee622018-02-12 17:52:34 +0000460 *
461 * @see android.app.admin.DevicePolicyManager
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700462 */
Philip P. Moltmannd9bb39a2017-09-05 12:41:15 -0700463 @RequiresPermission(anyOf = {
464 Manifest.permission.DELETE_PACKAGES,
465 Manifest.permission.REQUEST_DELETE_PACKAGES})
Jeff Sharkeya0907432014-08-15 10:23:11 -0700466 public void uninstall(@NonNull String packageName, @NonNull IntentSender statusReceiver) {
Todd Kennedycda831f2017-05-16 10:54:33 -0700467 uninstall(packageName, 0 /*flags*/, statusReceiver);
468 }
469
470 /**
471 * Uninstall the given package, removing it completely from the device. This
472 * method is only available to the current "installer of record" for the
473 * package.
474 *
475 * @param packageName The package to uninstall.
476 * @param flags Flags for uninstall.
477 * @param statusReceiver Where to deliver the result.
478 *
479 * @hide
480 */
481 public void uninstall(@NonNull String packageName, @DeleteFlags int flags,
482 @NonNull IntentSender statusReceiver) {
483 uninstall(new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST),
484 flags, statusReceiver);
Svet Ganov67882122016-12-11 16:36:34 -0800485 }
486
487 /**
488 * Uninstall the given package with a specific version code, removing it
Tony Mak366ee622018-02-12 17:52:34 +0000489 * completely from the device. If the version code of the package
Svet Ganov67882122016-12-11 16:36:34 -0800490 * does not match the one passed in the versioned package argument this
491 * method is a no-op. Use {@link PackageManager#VERSION_CODE_HIGHEST} to
492 * uninstall the latest version of the package.
Tony Mak366ee622018-02-12 17:52:34 +0000493 * <p>
494 * This method is available to:
495 * <ul>
496 * <li>the current "installer of record" for the package
497 * <li>the device owner
498 * <li>the affiliated profile owner
499 * </ul>
Svet Ganov67882122016-12-11 16:36:34 -0800500 *
501 * @param versionedPackage The versioned package to uninstall.
502 * @param statusReceiver Where to deliver the result.
Tony Mak366ee622018-02-12 17:52:34 +0000503 *
504 * @see android.app.admin.DevicePolicyManager
Svet Ganov67882122016-12-11 16:36:34 -0800505 */
Philip P. Moltmannd9bb39a2017-09-05 12:41:15 -0700506 @RequiresPermission(anyOf = {
507 Manifest.permission.DELETE_PACKAGES,
508 Manifest.permission.REQUEST_DELETE_PACKAGES})
Todd Kennedycda831f2017-05-16 10:54:33 -0700509 public void uninstall(@NonNull VersionedPackage versionedPackage,
510 @NonNull IntentSender statusReceiver) {
511 uninstall(versionedPackage, 0 /*flags*/, statusReceiver);
512 }
513
514 /**
515 * Uninstall the given package with a specific version code, removing it
516 * completely from the device. This method is only available to the current
517 * "installer of record" for the package. If the version code of the package
518 * does not match the one passed in the versioned package argument this
519 * method is a no-op. Use {@link PackageManager#VERSION_CODE_HIGHEST} to
520 * uninstall the latest version of the package.
521 *
522 * @param versionedPackage The versioned package to uninstall.
523 * @param flags Flags for uninstall.
524 * @param statusReceiver Where to deliver the result.
525 *
526 * @hide
527 */
Svet Ganov67882122016-12-11 16:36:34 -0800528 @RequiresPermission(anyOf = {
529 Manifest.permission.DELETE_PACKAGES,
530 Manifest.permission.REQUEST_DELETE_PACKAGES})
Todd Kennedycda831f2017-05-16 10:54:33 -0700531 public void uninstall(@NonNull VersionedPackage versionedPackage, @DeleteFlags int flags,
Svet Ganov67882122016-12-11 16:36:34 -0800532 @NonNull IntentSender statusReceiver) {
533 Preconditions.checkNotNull(versionedPackage, "versionedPackage cannot be null");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700534 try {
Svet Ganov67882122016-12-11 16:36:34 -0800535 mInstaller.uninstall(versionedPackage, mInstallerPackageName,
Todd Kennedycda831f2017-05-16 10:54:33 -0700536 flags, statusReceiver, mUserId);
Jeff Sharkeybb580672014-07-10 12:10:25 -0700537 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700538 throw e.rethrowFromSystemServer();
Jeff Sharkeybb580672014-07-10 12:10:25 -0700539 }
540 }
541
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700542 /** {@hide} */
Todd Kennedy04cc1912017-03-03 13:05:12 -0800543 @SystemApi
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -0600544 @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES)
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700545 public void setPermissionsResult(int sessionId, boolean accepted) {
546 try {
547 mInstaller.setPermissionsResult(sessionId, accepted);
548 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700549 throw e.rethrowFromSystemServer();
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700550 }
551 }
552
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700553 /**
554 * Events for observing session lifecycle.
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700555 * <p>
556 * A typical session lifecycle looks like this:
557 * <ul>
558 * <li>An installer creates a session to indicate pending app delivery. All
559 * install details are available at this point.
560 * <li>The installer opens the session to deliver APK data. Note that a
561 * session may be opened and closed multiple times as network connectivity
562 * changes. The installer may deliver periodic progress updates.
563 * <li>The installer commits or abandons the session, resulting in the
564 * session being finished.
565 * </ul>
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700566 */
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700567 public static abstract class SessionCallback {
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700568 /**
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700569 * New session has been created. Details about the session can be
570 * obtained from {@link PackageInstaller#getSessionInfo(int)}.
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700571 */
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700572 public abstract void onCreated(int sessionId);
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700573
574 /**
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700575 * Badging details for an existing session has changed. For example, the
576 * app icon or label has been updated.
577 */
578 public abstract void onBadgingChanged(int sessionId);
579
580 /**
Jeff Sharkeybc7bce32014-09-05 15:53:05 -0700581 * Active state for session has been changed.
582 * <p>
583 * A session is considered active whenever there is ongoing forward
584 * progress being made, such as the installer holding an open
585 * {@link Session} instance while streaming data into place, or the
586 * system optimizing code as the result of
587 * {@link Session#commit(IntentSender)}.
588 * <p>
589 * If the installer closes the {@link Session} without committing, the
590 * session is considered inactive until the installer opens the session
591 * again.
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700592 */
Jeff Sharkeybc7bce32014-09-05 15:53:05 -0700593 public abstract void onActiveChanged(int sessionId, boolean active);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700594
595 /**
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700596 * Progress for given session has been updated.
597 * <p>
598 * Note that this progress may not directly correspond to the value
Jeff Sharkeybc7bce32014-09-05 15:53:05 -0700599 * reported by
600 * {@link PackageInstaller.Session#setStagingProgress(float)}, as the
601 * system may carve out a portion of the overall progress to represent
602 * its own internal installation work.
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700603 */
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700604 public abstract void onProgressChanged(int sessionId, float progress);
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700605
606 /**
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700607 * Session has completely finished, either with success or failure.
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700608 */
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700609 public abstract void onFinished(int sessionId, boolean success);
Jeff Sharkeybb580672014-07-10 12:10:25 -0700610 }
611
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700612 /** {@hide} */
613 private static class SessionCallbackDelegate extends IPackageInstallerCallback.Stub implements
614 Handler.Callback {
615 private static final int MSG_SESSION_CREATED = 1;
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700616 private static final int MSG_SESSION_BADGING_CHANGED = 2;
Jeff Sharkeybc7bce32014-09-05 15:53:05 -0700617 private static final int MSG_SESSION_ACTIVE_CHANGED = 3;
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700618 private static final int MSG_SESSION_PROGRESS_CHANGED = 4;
Jeff Sharkeybc7bce32014-09-05 15:53:05 -0700619 private static final int MSG_SESSION_FINISHED = 5;
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700620
621 final SessionCallback mCallback;
622 final Handler mHandler;
623
624 public SessionCallbackDelegate(SessionCallback callback, Looper looper) {
625 mCallback = callback;
626 mHandler = new Handler(looper, this);
627 }
628
629 @Override
630 public boolean handleMessage(Message msg) {
Jeff Sharkeybc7bce32014-09-05 15:53:05 -0700631 final int sessionId = msg.arg1;
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700632 switch (msg.what) {
633 case MSG_SESSION_CREATED:
Jeff Sharkeybc7bce32014-09-05 15:53:05 -0700634 mCallback.onCreated(sessionId);
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700635 return true;
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700636 case MSG_SESSION_BADGING_CHANGED:
Jeff Sharkeybc7bce32014-09-05 15:53:05 -0700637 mCallback.onBadgingChanged(sessionId);
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700638 return true;
Jeff Sharkeybc7bce32014-09-05 15:53:05 -0700639 case MSG_SESSION_ACTIVE_CHANGED:
640 final boolean active = msg.arg2 != 0;
641 mCallback.onActiveChanged(sessionId, active);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700642 return true;
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700643 case MSG_SESSION_PROGRESS_CHANGED:
Jeff Sharkeybc7bce32014-09-05 15:53:05 -0700644 mCallback.onProgressChanged(sessionId, (float) msg.obj);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700645 return true;
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700646 case MSG_SESSION_FINISHED:
Jeff Sharkeybc7bce32014-09-05 15:53:05 -0700647 mCallback.onFinished(sessionId, msg.arg2 != 0);
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700648 return true;
649 }
650 return false;
651 }
652
653 @Override
654 public void onSessionCreated(int sessionId) {
655 mHandler.obtainMessage(MSG_SESSION_CREATED, sessionId, 0).sendToTarget();
656 }
657
658 @Override
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700659 public void onSessionBadgingChanged(int sessionId) {
660 mHandler.obtainMessage(MSG_SESSION_BADGING_CHANGED, sessionId, 0).sendToTarget();
661 }
662
663 @Override
Jeff Sharkeybc7bce32014-09-05 15:53:05 -0700664 public void onSessionActiveChanged(int sessionId, boolean active) {
665 mHandler.obtainMessage(MSG_SESSION_ACTIVE_CHANGED, sessionId, active ? 1 : 0)
666 .sendToTarget();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700667 }
668
669 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700670 public void onSessionProgressChanged(int sessionId, float progress) {
671 mHandler.obtainMessage(MSG_SESSION_PROGRESS_CHANGED, sessionId, 0, progress)
672 .sendToTarget();
673 }
674
675 @Override
676 public void onSessionFinished(int sessionId, boolean success) {
677 mHandler.obtainMessage(MSG_SESSION_FINISHED, sessionId, success ? 1 : 0)
678 .sendToTarget();
Jeff Sharkeybb580672014-07-10 12:10:25 -0700679 }
680 }
681
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700682 /** {@hide} */
683 @Deprecated
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700684 public void addSessionCallback(@NonNull SessionCallback callback) {
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700685 registerSessionCallback(callback);
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700686 }
687
688 /**
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700689 * Register to watch for session lifecycle events. No special permissions
690 * are required to watch for these events.
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700691 */
692 public void registerSessionCallback(@NonNull SessionCallback callback) {
693 registerSessionCallback(callback, new Handler());
694 }
695
696 /** {@hide} */
697 @Deprecated
698 public void addSessionCallback(@NonNull SessionCallback callback, @NonNull Handler handler) {
699 registerSessionCallback(callback, handler);
700 }
701
702 /**
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700703 * Register to watch for session lifecycle events. No special permissions
704 * are required to watch for these events.
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700705 *
706 * @param handler to dispatch callback events through, otherwise uses
707 * calling thread.
708 */
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700709 public void registerSessionCallback(@NonNull SessionCallback callback, @NonNull Handler handler) {
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700710 synchronized (mDelegates) {
711 final SessionCallbackDelegate delegate = new SessionCallbackDelegate(callback,
712 handler.getLooper());
713 try {
714 mInstaller.registerCallback(delegate, mUserId);
715 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700716 throw e.rethrowFromSystemServer();
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700717 }
718 mDelegates.add(delegate);
719 }
720 }
721
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700722 /** {@hide} */
723 @Deprecated
724 public void removeSessionCallback(@NonNull SessionCallback callback) {
725 unregisterSessionCallback(callback);
726 }
727
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700728 /**
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700729 * Unregister a previously registered callback.
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700730 */
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700731 public void unregisterSessionCallback(@NonNull SessionCallback callback) {
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700732 synchronized (mDelegates) {
733 for (Iterator<SessionCallbackDelegate> i = mDelegates.iterator(); i.hasNext();) {
734 final SessionCallbackDelegate delegate = i.next();
735 if (delegate.mCallback == callback) {
736 try {
737 mInstaller.unregisterCallback(delegate);
738 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700739 throw e.rethrowFromSystemServer();
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700740 }
741 i.remove();
742 }
743 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700744 }
745 }
746
747 /**
748 * An installation that is being actively staged. For an install to succeed,
749 * all existing and new packages must have identical package names, version
750 * codes, and signing certificates.
751 * <p>
752 * A session may contain any number of split packages. If the application
753 * does not yet exist, this session must include a base package.
754 * <p>
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700755 * If an APK included in this session is already defined by the existing
756 * installation (for example, the same split name), the APK in this session
757 * will replace the existing APK.
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700758 */
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700759 public static class Session implements Closeable {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700760 private IPackageInstallerSession mSession;
761
762 /** {@hide} */
763 public Session(IPackageInstallerSession session) {
764 mSession = session;
765 }
766
Jeff Sharkeybc7bce32014-09-05 15:53:05 -0700767 /** {@hide} */
768 @Deprecated
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700769 public void setProgress(float progress) {
Jeff Sharkeybc7bce32014-09-05 15:53:05 -0700770 setStagingProgress(progress);
771 }
772
773 /**
774 * Set current progress of staging this session. Valid values are
775 * anywhere between 0 and 1.
776 * <p>
777 * Note that this progress may not directly correspond to the value
778 * reported by {@link SessionCallback#onProgressChanged(int, float)}, as
779 * the system may carve out a portion of the overall progress to
780 * represent its own internal installation work.
781 */
782 public void setStagingProgress(float progress) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700783 try {
Jeff Sharkeya1031142014-07-12 18:09:46 -0700784 mSession.setClientProgress(progress);
785 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700786 throw e.rethrowFromSystemServer();
Jeff Sharkeya1031142014-07-12 18:09:46 -0700787 }
788 }
789
790 /** {@hide} */
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700791 public void addProgress(float progress) {
Jeff Sharkeya1031142014-07-12 18:09:46 -0700792 try {
793 mSession.addClientProgress(progress);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700794 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700795 throw e.rethrowFromSystemServer();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700796 }
797 }
798
Jeff Sharkey78cc3402014-05-22 10:52:49 -0700799 /**
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700800 * Open a stream to write an APK file into the session.
801 * <p>
802 * The returned stream will start writing data at the requested offset
803 * in the underlying file, which can be used to resume a partially
804 * written file. If a valid file length is specified, the system will
805 * preallocate the underlying disk space to optimize placement on disk.
806 * It's strongly recommended to provide a valid file length when known.
807 * <p>
808 * You can write data into the returned stream, optionally call
809 * {@link #fsync(OutputStream)} as needed to ensure bytes have been
810 * persisted to disk, and then close when finished. All streams must be
Jeff Sharkeya0907432014-08-15 10:23:11 -0700811 * closed before calling {@link #commit(IntentSender)}.
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700812 *
813 * @param name arbitrary, unique name of your choosing to identify the
814 * APK being written. You can open a file again for
815 * additional writes (such as after a reboot) by using the
816 * same name. This name is only meaningful within the context
817 * of a single install session.
818 * @param offsetBytes offset into the file to begin writing at, or 0 to
819 * start at the beginning of the file.
820 * @param lengthBytes total size of the file being written, used to
821 * preallocate the underlying disk space, or -1 if unknown.
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700822 * The system may clear various caches as needed to allocate
823 * this space.
824 * @throws IOException if trouble opening the file for writing, such as
825 * lack of disk space or unavailable media.
826 * @throws SecurityException if called after the session has been
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000827 * sealed or abandoned
Jeff Sharkey78cc3402014-05-22 10:52:49 -0700828 */
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700829 public @NonNull OutputStream openWrite(@NonNull String name, long offsetBytes,
830 long lengthBytes) throws IOException {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700831 try {
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700832 if (ENABLE_REVOCABLE_FD) {
833 return new ParcelFileDescriptor.AutoCloseOutputStream(
834 mSession.openWrite(name, offsetBytes, lengthBytes));
835 } else {
836 final ParcelFileDescriptor clientSocket = mSession.openWrite(name,
837 offsetBytes, lengthBytes);
838 return new FileBridge.FileBridgeOutputStream(clientSocket);
839 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700840 } catch (RuntimeException e) {
841 ExceptionUtils.maybeUnwrapIOException(e);
842 throw e;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700843 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700844 throw e.rethrowFromSystemServer();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700845 }
Jeff Sharkey0451de62018-02-02 11:27:21 -0700846 }
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700847
Jeff Sharkey0451de62018-02-02 11:27:21 -0700848 /** {@hide} */
849 public void write(@NonNull String name, long offsetBytes, long lengthBytes,
850 @NonNull ParcelFileDescriptor fd) throws IOException {
851 try {
852 mSession.write(name, offsetBytes, lengthBytes, fd);
853 } catch (RuntimeException e) {
854 ExceptionUtils.maybeUnwrapIOException(e);
855 throw e;
856 } catch (RemoteException e) {
857 throw e.rethrowFromSystemServer();
858 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700859 }
860
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700861 /**
862 * Ensure that any outstanding data for given stream has been committed
863 * to disk. This is only valid for streams returned from
864 * {@link #openWrite(String, long, long)}.
865 */
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700866 public void fsync(@NonNull OutputStream out) throws IOException {
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700867 if (ENABLE_REVOCABLE_FD) {
868 if (out instanceof ParcelFileDescriptor.AutoCloseOutputStream) {
869 try {
870 Os.fsync(((ParcelFileDescriptor.AutoCloseOutputStream) out).getFD());
871 } catch (ErrnoException e) {
872 throw e.rethrowAsIOException();
873 }
874 } else {
875 throw new IllegalArgumentException("Unrecognized stream");
876 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700877 } else {
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700878 if (out instanceof FileBridge.FileBridgeOutputStream) {
879 ((FileBridge.FileBridgeOutputStream) out).fsync();
880 } else {
881 throw new IllegalArgumentException("Unrecognized stream");
882 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700883 }
884 }
885
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700886 /**
Jeff Sharkeya0907432014-08-15 10:23:11 -0700887 * Return all APK names contained in this session.
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700888 * <p>
889 * This returns all names which have been previously written through
890 * {@link #openWrite(String, long, long)} as part of this session.
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700891 *
892 * @throws SecurityException if called after the session has been
893 * committed or abandoned.
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700894 */
Jeff Sharkey742e7902014-08-16 19:09:13 -0700895 public @NonNull String[] getNames() throws IOException {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700896 try {
Jeff Sharkeya0907432014-08-15 10:23:11 -0700897 return mSession.getNames();
Jeff Sharkey742e7902014-08-16 19:09:13 -0700898 } catch (RuntimeException e) {
899 ExceptionUtils.maybeUnwrapIOException(e);
900 throw e;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700901 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700902 throw e.rethrowFromSystemServer();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700903 }
904 }
905
906 /**
907 * Open a stream to read an APK file from the session.
908 * <p>
909 * This is only valid for names which have been previously written
910 * through {@link #openWrite(String, long, long)} as part of this
911 * session. For example, this stream may be used to calculate a
912 * {@link MessageDigest} of a written APK before committing.
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700913 *
914 * @throws SecurityException if called after the session has been
915 * committed or abandoned.
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700916 */
917 public @NonNull InputStream openRead(@NonNull String name) throws IOException {
918 try {
919 final ParcelFileDescriptor pfd = mSession.openRead(name);
920 return new ParcelFileDescriptor.AutoCloseInputStream(pfd);
921 } catch (RuntimeException e) {
922 ExceptionUtils.maybeUnwrapIOException(e);
923 throw e;
924 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700925 throw e.rethrowFromSystemServer();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700926 }
927 }
928
929 /**
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800930 * Removes a split.
931 * <p>
932 * Split removals occur prior to adding new APKs. If upgrading a feature
933 * split, it is not expected nor desirable to remove the split prior to
934 * upgrading.
935 * <p>
936 * When split removal is bundled with new APKs, the packageName must be
937 * identical.
938 */
939 public void removeSplit(@NonNull String splitName) throws IOException {
940 try {
941 mSession.removeSplit(splitName);
942 } catch (RuntimeException e) {
943 ExceptionUtils.maybeUnwrapIOException(e);
944 throw e;
945 } catch (RemoteException e) {
946 throw e.rethrowFromSystemServer();
947 }
948 }
949
950 /**
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700951 * Attempt to commit everything staged in this session. This may require
952 * user intervention, and so it may not happen immediately. The final
953 * result of the commit will be reported through the given callback.
954 * <p>
Todd Kennedy04cc1912017-03-03 13:05:12 -0800955 * Once this method is called, the session is sealed and no additional
956 * mutations may be performed on the session. If the device reboots
957 * before the session has been finalized, you may commit the session again.
Tony Mak366ee622018-02-12 17:52:34 +0000958 * <p>
959 * If the installer is the device owner or the affiliated profile owner, there will be no
960 * user intervention.
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700961 *
962 * @throws SecurityException if streams opened through
963 * {@link #openWrite(String, long, long)} are still open.
Tony Mak366ee622018-02-12 17:52:34 +0000964 *
965 * @see android.app.admin.DevicePolicyManager
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700966 */
Jeff Sharkeya0907432014-08-15 10:23:11 -0700967 public void commit(@NonNull IntentSender statusReceiver) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700968 try {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000969 mSession.commit(statusReceiver, false);
970 } catch (RemoteException e) {
971 throw e.rethrowFromSystemServer();
972 }
973 }
974
975 /**
976 * Attempt to commit a session that has been {@link #transfer(String) transferred}.
977 *
978 * <p>If the device reboots before the session has been finalized, you may commit the
979 * session again.
980 *
981 * <p>The caller of this method is responsible to ensure the safety of the session. As the
982 * session was created by another - usually less trusted - app, it is paramount that before
983 * committing <u>all</u> public and system {@link SessionInfo properties of the session}
984 * and <u>all</u> {@link #openRead(String) APKs} are verified by the caller. It might happen
985 * that new properties are added to the session with a new API revision. In this case the
986 * callers need to be updated.
987 *
988 * @param statusReceiver Callbacks called when the state of the session changes.
989 *
990 * @hide
991 */
992 @SystemApi
993 @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES)
994 public void commitTransferred(@NonNull IntentSender statusReceiver) {
995 try {
996 mSession.commit(statusReceiver, true);
997 } catch (RemoteException e) {
998 throw e.rethrowFromSystemServer();
999 }
1000 }
1001
1002 /**
1003 * Transfer the session to a new owner.
1004 * <p>
1005 * Only sessions that update the installing app can be transferred.
1006 * <p>
1007 * After the transfer to a package with a different uid all method calls on the session
1008 * will cause {@link SecurityException}s.
1009 * <p>
1010 * Once this method is called, the session is sealed and no additional mutations beside
1011 * committing it may be performed on the session.
1012 *
1013 * @param packageName The package of the new owner. Needs to hold the INSTALL_PACKAGES
1014 * permission.
1015 *
1016 * @throws PackageManager.NameNotFoundException if the new owner could not be found.
1017 * @throws SecurityException if called after the session has been committed or abandoned.
1018 * @throws SecurityException if the session does not update the original installer
1019 * @throws SecurityException if streams opened through
1020 * {@link #openWrite(String, long, long) are still open.
1021 */
1022 public void transfer(@NonNull String packageName)
1023 throws PackageManager.NameNotFoundException {
1024 Preconditions.checkNotNull(packageName);
1025
1026 try {
1027 mSession.transfer(packageName);
1028 } catch (ParcelableException e) {
1029 e.maybeRethrow(PackageManager.NameNotFoundException.class);
1030 throw new RuntimeException(e);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001031 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001032 throw e.rethrowFromSystemServer();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001033 }
1034 }
1035
Jeff Sharkey6c833e02014-07-14 22:44:30 -07001036 /**
1037 * Release this session object. You can open the session again if it
1038 * hasn't been finalized.
1039 */
Jeff Sharkeyec55ef02014-07-08 11:28:00 -07001040 @Override
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001041 public void close() {
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07001042 try {
1043 mSession.close();
1044 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001045 throw e.rethrowFromSystemServer();
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07001046 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001047 }
1048
Jeff Sharkey6c833e02014-07-14 22:44:30 -07001049 /**
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07001050 * Completely abandon this session, destroying all staged data and
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001051 * rendering it invalid. Abandoned sessions will be reported to
1052 * {@link SessionCallback} listeners as failures. This is equivalent to
1053 * opening the session and calling {@link Session#abandon()}.
Jeff Sharkey6c833e02014-07-14 22:44:30 -07001054 */
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07001055 public void abandon() {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001056 try {
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07001057 mSession.abandon();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001058 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001059 throw e.rethrowFromSystemServer();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001060 }
1061 }
1062 }
Jeff Sharkeybb580672014-07-10 12:10:25 -07001063
Jeff Sharkey6c833e02014-07-14 22:44:30 -07001064 /**
Jeff Sharkeya0907432014-08-15 10:23:11 -07001065 * Parameters for creating a new {@link PackageInstaller.Session}.
Jeff Sharkey6c833e02014-07-14 22:44:30 -07001066 */
Jeff Sharkeya0907432014-08-15 10:23:11 -07001067 public static class SessionParams implements Parcelable {
1068
1069 /** {@hide} */
1070 public static final int MODE_INVALID = -1;
Jeff Sharkeyf0600952014-08-07 17:31:53 -07001071
1072 /**
Jeff Sharkeya0907432014-08-15 10:23:11 -07001073 * Mode for an install session whose staged APKs should fully replace any
1074 * existing APKs for the target app.
Jeff Sharkeyf0600952014-08-07 17:31:53 -07001075 */
Jeff Sharkeya0907432014-08-15 10:23:11 -07001076 public static final int MODE_FULL_INSTALL = 1;
Jeff Sharkeyf0600952014-08-07 17:31:53 -07001077
1078 /**
Jeff Sharkeya0907432014-08-15 10:23:11 -07001079 * Mode for an install session that should inherit any existing APKs for the
1080 * target app, unless they have been explicitly overridden (based on split
1081 * name) by the session. For example, this can be used to add one or more
1082 * split APKs to an existing installation.
Jeff Sharkeyfbd0e9f2014-08-06 16:34:34 -07001083 * <p>
Jeff Sharkeya0907432014-08-15 10:23:11 -07001084 * If there are no existing APKs for the target app, this behaves like
1085 * {@link #MODE_FULL_INSTALL}.
Jeff Sharkeyfbd0e9f2014-08-06 16:34:34 -07001086 */
Jeff Sharkeya0907432014-08-15 10:23:11 -07001087 public static final int MODE_INHERIT_EXISTING = 2;
Jeff Sharkeyfbd0e9f2014-08-06 16:34:34 -07001088
Jeff Sharkeya0907432014-08-15 10:23:11 -07001089 /** {@hide} */
Todd Kennedya1d12cf2015-09-29 15:43:00 -07001090 public static final int UID_UNKNOWN = -1;
1091
1092 /** {@hide} */
Jeff Sharkeya0907432014-08-15 10:23:11 -07001093 public int mode = MODE_INVALID;
1094 /** {@hide} */
1095 public int installFlags;
1096 /** {@hide} */
1097 public int installLocation = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY;
1098 /** {@hide} */
Bartosz Fabianowski40a00622017-04-18 14:39:23 +02001099 public @InstallReason int installReason = PackageManager.INSTALL_REASON_UNKNOWN;
Bartosz Fabianowskia34f53f2017-01-11 18:08:47 +01001100 /** {@hide} */
Jeff Sharkeya0907432014-08-15 10:23:11 -07001101 public long sizeBytes = -1;
1102 /** {@hide} */
1103 public String appPackageName;
1104 /** {@hide} */
1105 public Bitmap appIcon;
1106 /** {@hide} */
1107 public String appLabel;
1108 /** {@hide} */
Jeff Sharkey02bd7842014-10-06 15:14:27 -07001109 public long appIconLastModified = -1;
1110 /** {@hide} */
Jeff Sharkeya0907432014-08-15 10:23:11 -07001111 public Uri originatingUri;
1112 /** {@hide} */
Todd Kennedya1d12cf2015-09-29 15:43:00 -07001113 public int originatingUid = UID_UNKNOWN;
1114 /** {@hide} */
Jeff Sharkeya0907432014-08-15 10:23:11 -07001115 public Uri referrerUri;
1116 /** {@hide} */
1117 public String abiOverride;
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -07001118 /** {@hide} */
1119 public String volumeUuid;
Svet Ganov7121e182015-07-13 22:38:12 -07001120 /** {@hide} */
1121 public String[] grantedRuntimePermissions;
Philip P. Moltmann79c238a2017-12-13 15:59:07 -08001122 /** {@hide} */
1123 public String installerPackageName;
Jeff Sharkeybb580672014-07-10 12:10:25 -07001124
Jeff Sharkeya0907432014-08-15 10:23:11 -07001125 /**
1126 * Construct parameters for a new package install session.
1127 *
1128 * @param mode one of {@link #MODE_FULL_INSTALL} or
1129 * {@link #MODE_INHERIT_EXISTING} describing how the session
1130 * should interact with an existing app.
1131 */
1132 public SessionParams(int mode) {
1133 this.mode = mode;
1134 }
Jeff Sharkeybb580672014-07-10 12:10:25 -07001135
Jeff Sharkeya0907432014-08-15 10:23:11 -07001136 /** {@hide} */
1137 public SessionParams(Parcel source) {
1138 mode = source.readInt();
1139 installFlags = source.readInt();
1140 installLocation = source.readInt();
Bartosz Fabianowskia34f53f2017-01-11 18:08:47 +01001141 installReason = source.readInt();
Jeff Sharkeya0907432014-08-15 10:23:11 -07001142 sizeBytes = source.readLong();
1143 appPackageName = source.readString();
1144 appIcon = source.readParcelable(null);
1145 appLabel = source.readString();
1146 originatingUri = source.readParcelable(null);
Todd Kennedya1d12cf2015-09-29 15:43:00 -07001147 originatingUid = source.readInt();
Jeff Sharkeya0907432014-08-15 10:23:11 -07001148 referrerUri = source.readParcelable(null);
1149 abiOverride = source.readString();
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -07001150 volumeUuid = source.readString();
Svet Ganov7121e182015-07-13 22:38:12 -07001151 grantedRuntimePermissions = source.readStringArray();
Philip P. Moltmann79c238a2017-12-13 15:59:07 -08001152 installerPackageName = source.readString();
Jeff Sharkeya0907432014-08-15 10:23:11 -07001153 }
1154
1155 /**
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001156 * Check if there are hidden options set.
1157 *
1158 * <p>Hidden options are those options that cannot be verified via public or system-api
1159 * methods on {@link SessionInfo}.
1160 *
1161 * @return {@code true} if any hidden option is set.
1162 *
1163 * @hide
1164 */
1165 public boolean areHiddenOptionsSet() {
1166 return (installFlags & (PackageManager.INSTALL_ALLOW_DOWNGRADE
1167 | PackageManager.INSTALL_DONT_KILL_APP
1168 | PackageManager.INSTALL_INSTANT_APP
1169 | PackageManager.INSTALL_FULL_APP
1170 | PackageManager.INSTALL_VIRTUAL_PRELOAD
1171 | PackageManager.INSTALL_ALLOCATE_AGGRESSIVE)) != installFlags
1172 || abiOverride != null || volumeUuid != null;
1173 }
1174
1175 /**
Jeff Sharkeya0907432014-08-15 10:23:11 -07001176 * Provide value of {@link PackageInfo#installLocation}, which may be used
1177 * to determine where the app will be staged. Defaults to
1178 * {@link PackageInfo#INSTALL_LOCATION_INTERNAL_ONLY}.
1179 */
1180 public void setInstallLocation(int installLocation) {
1181 this.installLocation = installLocation;
1182 }
1183
1184 /**
1185 * Optionally indicate the total size (in bytes) of all APKs that will be
1186 * delivered in this session. The system may use this to ensure enough disk
1187 * space exists before proceeding, or to estimate container size for
1188 * installations living on external storage.
1189 *
1190 * @see PackageInfo#INSTALL_LOCATION_AUTO
1191 * @see PackageInfo#INSTALL_LOCATION_PREFER_EXTERNAL
1192 */
1193 public void setSize(long sizeBytes) {
1194 this.sizeBytes = sizeBytes;
1195 }
1196
1197 /**
1198 * Optionally set the package name of the app being installed. It's strongly
1199 * recommended that you provide this value when known, so that observers can
1200 * communicate installing apps to users.
1201 * <p>
1202 * If the APKs staged in the session aren't consistent with this package
1203 * name, the install will fail. Regardless of this value, all APKs in the
1204 * app must have the same package name.
1205 */
1206 public void setAppPackageName(@Nullable String appPackageName) {
1207 this.appPackageName = appPackageName;
1208 }
1209
1210 /**
1211 * Optionally set an icon representing the app being installed. This should
1212 * be roughly {@link ActivityManager#getLauncherLargeIconSize()} in both
1213 * dimensions.
1214 */
1215 public void setAppIcon(@Nullable Bitmap appIcon) {
1216 this.appIcon = appIcon;
1217 }
1218
1219 /**
1220 * Optionally set a label representing the app being installed.
1221 */
1222 public void setAppLabel(@Nullable CharSequence appLabel) {
1223 this.appLabel = (appLabel != null) ? appLabel.toString() : null;
1224 }
1225
1226 /**
Todd Kennedy1ed6b872016-03-10 10:07:00 -08001227 * Optionally set the URI where this package was downloaded from. This is
1228 * informational and may be used as a signal for anti-malware purposes.
Jeff Sharkeya0907432014-08-15 10:23:11 -07001229 *
1230 * @see Intent#EXTRA_ORIGINATING_URI
1231 */
1232 public void setOriginatingUri(@Nullable Uri originatingUri) {
1233 this.originatingUri = originatingUri;
1234 }
1235
1236 /**
Nikolas Bravo62831002017-11-07 21:07:15 +00001237 * Sets the UID that initiated the package installation. This is informational
Todd Kennedy1ed6b872016-03-10 10:07:00 -08001238 * and may be used as a signal for anti-malware purposes.
Todd Kennedya1d12cf2015-09-29 15:43:00 -07001239 *
Nikolas Bravo62831002017-11-07 21:07:15 +00001240 * @see Intent#EXTRA_ORIGINATING_UID
Todd Kennedya1d12cf2015-09-29 15:43:00 -07001241 */
1242 public void setOriginatingUid(int originatingUid) {
1243 this.originatingUid = originatingUid;
1244 }
1245
1246 /**
Todd Kennedy1ed6b872016-03-10 10:07:00 -08001247 * Optionally set the URI that referred you to install this package. This is
1248 * informational and may be used as a signal for anti-malware purposes.
Jeff Sharkeya0907432014-08-15 10:23:11 -07001249 *
1250 * @see Intent#EXTRA_REFERRER
1251 */
1252 public void setReferrerUri(@Nullable Uri referrerUri) {
1253 this.referrerUri = referrerUri;
1254 }
1255
Svet Ganov7121e182015-07-13 22:38:12 -07001256 /**
1257 * Sets which runtime permissions to be granted to the package at installation.
Svet Ganov7121e182015-07-13 22:38:12 -07001258 *
1259 * @param permissions The permissions to grant or null to grant all runtime
1260 * permissions.
1261 *
1262 * @hide
1263 */
1264 @SystemApi
1265 @RequiresPermission(android.Manifest.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS)
1266 public void setGrantedRuntimePermissions(String[] permissions) {
1267 installFlags |= PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS;
1268 this.grantedRuntimePermissions = permissions;
1269 }
1270
Jeff Sharkeya0907432014-08-15 10:23:11 -07001271 /** {@hide} */
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001272 public void setInstallFlagsInternal() {
1273 installFlags |= PackageManager.INSTALL_INTERNAL;
1274 installFlags &= ~PackageManager.INSTALL_EXTERNAL;
1275 }
1276
1277 /** {@hide} */
Todd Kennedyc84d1ab2016-03-11 11:37:17 -08001278 @SystemApi
Todd Kennedy948b7022016-03-14 14:29:52 -07001279 public void setAllowDowngrade(boolean allowDowngrade) {
1280 if (allowDowngrade) {
1281 installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE;
1282 } else {
1283 installFlags &= ~PackageManager.INSTALL_ALLOW_DOWNGRADE;
1284 }
Todd Kennedyc84d1ab2016-03-11 11:37:17 -08001285 }
1286
1287 /** {@hide} */
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001288 public void setInstallFlagsExternal() {
1289 installFlags |= PackageManager.INSTALL_EXTERNAL;
1290 installFlags &= ~PackageManager.INSTALL_INTERNAL;
1291 }
1292
1293 /** {@hide} */
Todd Kennedya1d12cf2015-09-29 15:43:00 -07001294 public void setInstallFlagsForcePermissionPrompt() {
1295 installFlags |= PackageManager.INSTALL_FORCE_PERMISSION_PROMPT;
1296 }
1297
1298 /** {@hide} */
Todd Kennedy24ca5c62016-03-16 15:42:01 -07001299 @SystemApi
1300 public void setDontKillApp(boolean dontKillApp) {
1301 if (dontKillApp) {
1302 installFlags |= PackageManager.INSTALL_DONT_KILL_APP;
1303 } else {
1304 installFlags &= ~PackageManager.INSTALL_DONT_KILL_APP;
1305 }
Todd Kennedy39bfee52016-02-24 10:28:21 -08001306 }
1307
1308 /** {@hide} */
Todd Kennedyb7717682016-11-30 15:41:21 -08001309 @SystemApi
1310 public void setInstallAsInstantApp(boolean isInstantApp) {
1311 if (isInstantApp) {
Todd Kennedybe0b8892017-02-15 14:13:52 -08001312 installFlags |= PackageManager.INSTALL_INSTANT_APP;
1313 installFlags &= ~PackageManager.INSTALL_FULL_APP;
Todd Kennedyb7717682016-11-30 15:41:21 -08001314 } else {
Todd Kennedybe0b8892017-02-15 14:13:52 -08001315 installFlags &= ~PackageManager.INSTALL_INSTANT_APP;
1316 installFlags |= PackageManager.INSTALL_FULL_APP;
Todd Kennedyb7717682016-11-30 15:41:21 -08001317 }
1318 }
1319
Bartosz Fabianowski40a00622017-04-18 14:39:23 +02001320 /**
Todd Kennedy78a72502017-07-19 12:49:30 -07001321 * Sets the install as a virtual preload. Will only have effect when called
1322 * by the verifier.
1323 * {@hide}
1324 */
1325 @SystemApi
1326 public void setInstallAsVirtualPreload() {
1327 installFlags |= PackageManager.INSTALL_VIRTUAL_PRELOAD;
1328 }
1329
1330 /**
Bartosz Fabianowski40a00622017-04-18 14:39:23 +02001331 * Set the reason for installing this package.
1332 */
1333 public void setInstallReason(@InstallReason int installReason) {
Bartosz Fabianowskia34f53f2017-01-11 18:08:47 +01001334 this.installReason = installReason;
1335 }
1336
Todd Kennedyb7717682016-11-30 15:41:21 -08001337 /** {@hide} */
Jeff Sharkey683bcd32017-03-18 17:54:51 -06001338 @SystemApi
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -06001339 @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE)
Jeff Sharkey683bcd32017-03-18 17:54:51 -06001340 public void setAllocateAggressive(boolean allocateAggressive) {
1341 if (allocateAggressive) {
1342 installFlags |= PackageManager.INSTALL_ALLOCATE_AGGRESSIVE;
1343 } else {
1344 installFlags &= ~PackageManager.INSTALL_ALLOCATE_AGGRESSIVE;
1345 }
1346 }
1347
Philip P. Moltmann79c238a2017-12-13 15:59:07 -08001348 /**
1349 * Set the installer package for the app.
1350 *
1351 * By default this is the app that created the {@link PackageInstaller} object.
1352 *
1353 * @param installerPackageName name of the installer package
1354 * {@hide}
1355 */
1356 public void setInstallerPackageName(String installerPackageName) {
1357 this.installerPackageName = installerPackageName;
1358 }
1359
Jeff Sharkey683bcd32017-03-18 17:54:51 -06001360 /** {@hide} */
Jeff Sharkeya0907432014-08-15 10:23:11 -07001361 public void dump(IndentingPrintWriter pw) {
1362 pw.printPair("mode", mode);
1363 pw.printHexPair("installFlags", installFlags);
1364 pw.printPair("installLocation", installLocation);
1365 pw.printPair("sizeBytes", sizeBytes);
1366 pw.printPair("appPackageName", appPackageName);
1367 pw.printPair("appIcon", (appIcon != null));
1368 pw.printPair("appLabel", appLabel);
1369 pw.printPair("originatingUri", originatingUri);
Todd Kennedya1d12cf2015-09-29 15:43:00 -07001370 pw.printPair("originatingUid", originatingUid);
Jeff Sharkeya0907432014-08-15 10:23:11 -07001371 pw.printPair("referrerUri", referrerUri);
1372 pw.printPair("abiOverride", abiOverride);
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -07001373 pw.printPair("volumeUuid", volumeUuid);
Svet Ganov7121e182015-07-13 22:38:12 -07001374 pw.printPair("grantedRuntimePermissions", grantedRuntimePermissions);
Philip P. Moltmann79c238a2017-12-13 15:59:07 -08001375 pw.printPair("installerPackageName", installerPackageName);
Jeff Sharkeya0907432014-08-15 10:23:11 -07001376 pw.println();
Jeff Sharkeybb580672014-07-10 12:10:25 -07001377 }
1378
1379 @Override
Jeff Sharkeya0907432014-08-15 10:23:11 -07001380 public int describeContents() {
1381 return 0;
Jeff Sharkeyfbd0e9f2014-08-06 16:34:34 -07001382 }
1383
1384 @Override
Jeff Sharkeya0907432014-08-15 10:23:11 -07001385 public void writeToParcel(Parcel dest, int flags) {
1386 dest.writeInt(mode);
1387 dest.writeInt(installFlags);
1388 dest.writeInt(installLocation);
Bartosz Fabianowskia34f53f2017-01-11 18:08:47 +01001389 dest.writeInt(installReason);
Jeff Sharkeya0907432014-08-15 10:23:11 -07001390 dest.writeLong(sizeBytes);
1391 dest.writeString(appPackageName);
1392 dest.writeParcelable(appIcon, flags);
1393 dest.writeString(appLabel);
1394 dest.writeParcelable(originatingUri, flags);
Todd Kennedya1d12cf2015-09-29 15:43:00 -07001395 dest.writeInt(originatingUid);
Jeff Sharkeya0907432014-08-15 10:23:11 -07001396 dest.writeParcelable(referrerUri, flags);
1397 dest.writeString(abiOverride);
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -07001398 dest.writeString(volumeUuid);
Svet Ganov7121e182015-07-13 22:38:12 -07001399 dest.writeStringArray(grantedRuntimePermissions);
Philip P. Moltmann79c238a2017-12-13 15:59:07 -08001400 dest.writeString(installerPackageName);
Jeff Sharkeybb580672014-07-10 12:10:25 -07001401 }
Jeff Sharkeya0907432014-08-15 10:23:11 -07001402
1403 public static final Parcelable.Creator<SessionParams>
1404 CREATOR = new Parcelable.Creator<SessionParams>() {
1405 @Override
1406 public SessionParams createFromParcel(Parcel p) {
1407 return new SessionParams(p);
1408 }
1409
1410 @Override
1411 public SessionParams[] newArray(int size) {
1412 return new SessionParams[size];
1413 }
1414 };
Jeff Sharkeybb580672014-07-10 12:10:25 -07001415 }
1416
Jeff Sharkey6c833e02014-07-14 22:44:30 -07001417 /**
Jeff Sharkeya0907432014-08-15 10:23:11 -07001418 * Details for an active install session.
Jeff Sharkey6c833e02014-07-14 22:44:30 -07001419 */
Jeff Sharkeya0907432014-08-15 10:23:11 -07001420 public static class SessionInfo implements Parcelable {
1421
1422 /** {@hide} */
1423 public int sessionId;
1424 /** {@hide} */
1425 public String installerPackageName;
1426 /** {@hide} */
1427 public String resolvedBaseCodePath;
1428 /** {@hide} */
1429 public float progress;
1430 /** {@hide} */
1431 public boolean sealed;
1432 /** {@hide} */
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001433 public boolean active;
Jeff Sharkeya0907432014-08-15 10:23:11 -07001434
1435 /** {@hide} */
1436 public int mode;
1437 /** {@hide} */
Bartosz Fabianowski40a00622017-04-18 14:39:23 +02001438 public @InstallReason int installReason;
Sunny Goyal6d7cb232017-01-30 10:43:18 -08001439 /** {@hide} */
Jeff Sharkeya0907432014-08-15 10:23:11 -07001440 public long sizeBytes;
1441 /** {@hide} */
1442 public String appPackageName;
1443 /** {@hide} */
1444 public Bitmap appIcon;
1445 /** {@hide} */
1446 public CharSequence appLabel;
1447
1448 /** {@hide} */
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001449 public int installLocation;
1450 /** {@hide} */
1451 public Uri originatingUri;
1452 /** {@hide} */
1453 public int originatingUid;
1454 /** {@hide} */
1455 public Uri referrerUri;
1456 /** {@hide} */
1457 public String[] grantedRuntimePermissions;
1458 /** {@hide} */
1459 public int installFlags;
1460
1461 /** {@hide} */
Jeff Sharkeya0907432014-08-15 10:23:11 -07001462 public SessionInfo() {
1463 }
1464
1465 /** {@hide} */
1466 public SessionInfo(Parcel source) {
1467 sessionId = source.readInt();
1468 installerPackageName = source.readString();
1469 resolvedBaseCodePath = source.readString();
1470 progress = source.readFloat();
1471 sealed = source.readInt() != 0;
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001472 active = source.readInt() != 0;
Jeff Sharkeya0907432014-08-15 10:23:11 -07001473
1474 mode = source.readInt();
Sunny Goyal6d7cb232017-01-30 10:43:18 -08001475 installReason = source.readInt();
Jeff Sharkeya0907432014-08-15 10:23:11 -07001476 sizeBytes = source.readLong();
1477 appPackageName = source.readString();
1478 appIcon = source.readParcelable(null);
1479 appLabel = source.readString();
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001480
1481 installLocation = source.readInt();
1482 originatingUri = source.readParcelable(null);
1483 originatingUid = source.readInt();
1484 referrerUri = source.readParcelable(null);
1485 grantedRuntimePermissions = source.readStringArray();
1486 installFlags = source.readInt();
Jeff Sharkeya0907432014-08-15 10:23:11 -07001487 }
Jeff Sharkeybb580672014-07-10 12:10:25 -07001488
1489 /**
Jeff Sharkeya0907432014-08-15 10:23:11 -07001490 * Return the ID for this session.
Jeff Sharkeybb580672014-07-10 12:10:25 -07001491 */
Jeff Sharkeya0907432014-08-15 10:23:11 -07001492 public int getSessionId() {
1493 return sessionId;
1494 }
Jeff Sharkeybb580672014-07-10 12:10:25 -07001495
1496 /**
Jeff Sharkeya0907432014-08-15 10:23:11 -07001497 * Return the package name of the app that owns this session.
1498 */
1499 public @Nullable String getInstallerPackageName() {
1500 return installerPackageName;
1501 }
1502
1503 /**
1504 * Return current overall progress of this session, between 0 and 1.
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07001505 * <p>
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001506 * Note that this progress may not directly correspond to the value
1507 * reported by
1508 * {@link PackageInstaller.Session#setStagingProgress(float)}, as the
1509 * system may carve out a portion of the overall progress to represent
1510 * its own internal installation work.
Jeff Sharkeybb580672014-07-10 12:10:25 -07001511 */
Jeff Sharkeya0907432014-08-15 10:23:11 -07001512 public float getProgress() {
1513 return progress;
1514 }
Jeff Sharkeybb580672014-07-10 12:10:25 -07001515
1516 /**
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001517 * Return if this session is currently active.
1518 * <p>
1519 * A session is considered active whenever there is ongoing forward
1520 * progress being made, such as the installer holding an open
1521 * {@link Session} instance while streaming data into place, or the
1522 * system optimizing code as the result of
1523 * {@link Session#commit(IntentSender)}.
1524 * <p>
1525 * If the installer closes the {@link Session} without committing, the
1526 * session is considered inactive until the installer opens the session
1527 * again.
Jeff Sharkeybb580672014-07-10 12:10:25 -07001528 */
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001529 public boolean isActive() {
1530 return active;
1531 }
1532
Sunny Goyal6d7cb232017-01-30 10:43:18 -08001533 /**
Todd Kennedy04cc1912017-03-03 13:05:12 -08001534 * Return if this session is sealed.
1535 * <p>
1536 * Once sealed, no further changes may be made to the session. A session
1537 * is sealed the moment {@link Session#commit(IntentSender)} is called.
1538 */
1539 public boolean isSealed() {
1540 return sealed;
1541 }
1542
1543 /**
Sunny Goyal6d7cb232017-01-30 10:43:18 -08001544 * Return the reason for installing this package.
1545 *
Bartosz Fabianowski40a00622017-04-18 14:39:23 +02001546 * @return The install reason.
Sunny Goyal6d7cb232017-01-30 10:43:18 -08001547 */
Bartosz Fabianowski40a00622017-04-18 14:39:23 +02001548 public @InstallReason int getInstallReason() {
Sunny Goyal6d7cb232017-01-30 10:43:18 -08001549 return installReason;
1550 }
1551
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001552 /** {@hide} */
1553 @Deprecated
Jeff Sharkeya0907432014-08-15 10:23:11 -07001554 public boolean isOpen() {
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001555 return isActive();
Jeff Sharkeya0907432014-08-15 10:23:11 -07001556 }
Jeff Sharkeybb580672014-07-10 12:10:25 -07001557
1558 /**
Jeff Sharkeya0907432014-08-15 10:23:11 -07001559 * Return the package name this session is working with. May be {@code null}
1560 * if unknown.
Jeff Sharkeybb580672014-07-10 12:10:25 -07001561 */
Jeff Sharkeya0907432014-08-15 10:23:11 -07001562 public @Nullable String getAppPackageName() {
1563 return appPackageName;
1564 }
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07001565
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001566 /**
Jeff Sharkeya0907432014-08-15 10:23:11 -07001567 * Return an icon representing the app being installed. May be {@code null}
1568 * if unavailable.
1569 */
1570 public @Nullable Bitmap getAppIcon() {
Jeff Sharkeyda1247a2017-06-08 14:13:29 -06001571 if (appIcon == null) {
1572 // Icon may have been omitted for calls that return bulk session
1573 // lists, so try fetching the specific icon.
1574 try {
Jeff Sharkeyd1dd2c62017-08-02 09:28:53 -06001575 final SessionInfo info = AppGlobals.getPackageManager().getPackageInstaller()
1576 .getSessionInfo(sessionId);
1577 appIcon = (info != null) ? info.appIcon : null;
Jeff Sharkeyda1247a2017-06-08 14:13:29 -06001578 } catch (RemoteException e) {
1579 throw e.rethrowFromSystemServer();
1580 }
1581 }
Jeff Sharkeya0907432014-08-15 10:23:11 -07001582 return appIcon;
1583 }
1584
1585 /**
1586 * Return a label representing the app being installed. May be {@code null}
1587 * if unavailable.
1588 */
1589 public @Nullable CharSequence getAppLabel() {
1590 return appLabel;
1591 }
1592
1593 /**
1594 * Return an Intent that can be started to view details about this install
1595 * session. This may surface actions such as pause, resume, or cancel.
1596 * <p>
1597 * In some cases, a matching Activity may not exist, so ensure you safeguard
1598 * against this.
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001599 *
Jeff Sharkeya0907432014-08-15 10:23:11 -07001600 * @see PackageInstaller#ACTION_SESSION_DETAILS
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001601 */
Jeff Sharkeyde742312014-09-15 14:04:56 -07001602 public @Nullable Intent createDetailsIntent() {
Jeff Sharkeya0907432014-08-15 10:23:11 -07001603 final Intent intent = new Intent(PackageInstaller.ACTION_SESSION_DETAILS);
1604 intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
1605 intent.setPackage(installerPackageName);
1606 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1607 return intent;
Jeff Sharkeybb580672014-07-10 12:10:25 -07001608 }
1609
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001610 /**
1611 * Get the mode of the session as set in the constructor of the {@link SessionParams}.
1612 *
1613 * @return One of {@link SessionParams#MODE_FULL_INSTALL}
1614 * or {@link SessionParams#MODE_INHERIT_EXISTING}
1615 */
1616 public int getMode() {
1617 return mode;
1618 }
1619
1620 /**
1621 * Get the value set in {@link SessionParams#setInstallLocation(int)}.
1622 */
1623 public int getInstallLocation() {
1624 return installLocation;
1625 }
1626
1627 /**
1628 * Get the value as set in {@link SessionParams#setSize(long)}.
1629 *
1630 * <p>The value is a hint and does not have to match the actual size.
1631 */
1632 public long getSize() {
1633 return sizeBytes;
1634 }
1635
1636 /**
1637 * Get the value set in {@link SessionParams#setOriginatingUri(Uri)}.
1638 */
1639 public @Nullable Uri getOriginatingUri() {
1640 return originatingUri;
1641 }
1642
1643 /**
1644 * Get the value set in {@link SessionParams#setOriginatingUid(int)}.
1645 */
1646 public int getOriginatingUid() {
1647 return originatingUid;
1648 }
1649
1650 /**
1651 * Get the value set in {@link SessionParams#setReferrerUri(Uri)}
1652 */
1653 public @Nullable Uri getReferrerUri() {
1654 return referrerUri;
1655 }
1656
1657 /**
1658 * Get the value set in {@link SessionParams#setGrantedRuntimePermissions(String[])}.
1659 *
1660 * @hide
1661 */
1662 @SystemApi
1663 public @Nullable String[] getGrantedRuntimePermissions() {
1664 return grantedRuntimePermissions;
1665 }
1666
1667 /**
1668 * Get the value set in {@link SessionParams#setAllowDowngrade(boolean)}.
1669 *
1670 * @hide
1671 */
1672 @SystemApi
1673 public boolean getAllowDowngrade() {
1674 return (installFlags & PackageManager.INSTALL_ALLOW_DOWNGRADE) != 0;
1675 }
1676
1677 /**
1678 * Get the value set in {@link SessionParams#setDontKillApp(boolean)}.
1679 *
1680 * @hide
1681 */
1682 @SystemApi
1683 public boolean getDontKillApp() {
1684 return (installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0;
1685 }
1686
1687 /**
1688 * If {@link SessionParams#setInstallAsInstantApp(boolean)} was called with {@code true},
1689 * return true. If it was called with {@code false} or if it was not called return false.
1690 *
1691 * @hide
1692 *
1693 * @see #getInstallAsFullApp
1694 */
1695 @SystemApi
1696 public boolean getInstallAsInstantApp(boolean isInstantApp) {
1697 return (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
1698 }
1699
1700 /**
1701 * If {@link SessionParams#setInstallAsInstantApp(boolean)} was called with {@code false},
1702 * return true. If it was called with {@code true} or if it was not called return false.
1703 *
1704 * @hide
1705 *
1706 * @see #getInstallAsInstantApp
1707 */
1708 @SystemApi
1709 public boolean getInstallAsFullApp(boolean isInstantApp) {
1710 return (installFlags & PackageManager.INSTALL_FULL_APP) != 0;
1711 }
1712
1713 /**
1714 * Get if {@link SessionParams#setInstallAsVirtualPreload()} was called.
1715 *
1716 * @hide
1717 */
1718 @SystemApi
1719 public boolean getInstallAsVirtualPreload() {
1720 return (installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0;
1721 }
1722
1723 /**
1724 * Get the value set in {@link SessionParams#setAllocateAggressive(boolean)}.
1725 *
1726 * @hide
1727 */
1728 @SystemApi
1729 public boolean getAllocateAggressive() {
1730 return (installFlags & PackageManager.INSTALL_ALLOCATE_AGGRESSIVE) != 0;
1731 }
1732
1733
Jeff Sharkeyde742312014-09-15 14:04:56 -07001734 /** {@hide} */
1735 @Deprecated
1736 public @Nullable Intent getDetailsIntent() {
1737 return createDetailsIntent();
1738 }
1739
Jeff Sharkeybb580672014-07-10 12:10:25 -07001740 @Override
Jeff Sharkeya0907432014-08-15 10:23:11 -07001741 public int describeContents() {
1742 return 0;
Jeff Sharkeyfbd0e9f2014-08-06 16:34:34 -07001743 }
1744
1745 @Override
Jeff Sharkeya0907432014-08-15 10:23:11 -07001746 public void writeToParcel(Parcel dest, int flags) {
1747 dest.writeInt(sessionId);
1748 dest.writeString(installerPackageName);
1749 dest.writeString(resolvedBaseCodePath);
1750 dest.writeFloat(progress);
1751 dest.writeInt(sealed ? 1 : 0);
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001752 dest.writeInt(active ? 1 : 0);
Jeff Sharkeybb580672014-07-10 12:10:25 -07001753
Jeff Sharkeya0907432014-08-15 10:23:11 -07001754 dest.writeInt(mode);
Sunny Goyal6d7cb232017-01-30 10:43:18 -08001755 dest.writeInt(installReason);
Jeff Sharkeya0907432014-08-15 10:23:11 -07001756 dest.writeLong(sizeBytes);
1757 dest.writeString(appPackageName);
1758 dest.writeParcelable(appIcon, flags);
1759 dest.writeString(appLabel != null ? appLabel.toString() : null);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001760
1761 dest.writeInt(installLocation);
1762 dest.writeParcelable(originatingUri, flags);
1763 dest.writeInt(originatingUid);
1764 dest.writeParcelable(referrerUri, flags);
1765 dest.writeStringArray(grantedRuntimePermissions);
1766 dest.writeInt(installFlags);
Jeff Sharkeybb580672014-07-10 12:10:25 -07001767 }
Jeff Sharkeya0907432014-08-15 10:23:11 -07001768
1769 public static final Parcelable.Creator<SessionInfo>
1770 CREATOR = new Parcelable.Creator<SessionInfo>() {
1771 @Override
1772 public SessionInfo createFromParcel(Parcel p) {
1773 return new SessionInfo(p);
1774 }
1775
1776 @Override
1777 public SessionInfo[] newArray(int size) {
1778 return new SessionInfo[size];
1779 }
1780 };
Jeff Sharkeybb580672014-07-10 12:10:25 -07001781 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001782}