1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.content.pm; 18 19 import android.Manifest; 20 import android.annotation.CurrentTimeMillisLong; 21 import android.annotation.IntDef; 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.annotation.RequiresPermission; 25 import android.annotation.SdkConstant; 26 import android.annotation.SdkConstant.SdkConstantType; 27 import android.annotation.SystemApi; 28 import android.annotation.TestApi; 29 import android.annotation.UnsupportedAppUsage; 30 import android.app.ActivityManager; 31 import android.app.AppGlobals; 32 import android.content.Intent; 33 import android.content.IntentSender; 34 import android.content.pm.PackageManager.DeleteFlags; 35 import android.content.pm.PackageManager.InstallReason; 36 import android.graphics.Bitmap; 37 import android.net.Uri; 38 import android.os.Build; 39 import android.os.FileBridge; 40 import android.os.Handler; 41 import android.os.HandlerExecutor; 42 import android.os.Parcel; 43 import android.os.ParcelFileDescriptor; 44 import android.os.Parcelable; 45 import android.os.ParcelableException; 46 import android.os.RemoteException; 47 import android.os.SystemProperties; 48 import android.os.UserHandle; 49 import android.system.ErrnoException; 50 import android.system.Os; 51 import android.util.ArraySet; 52 import android.util.ExceptionUtils; 53 54 import com.android.internal.util.IndentingPrintWriter; 55 import com.android.internal.util.Preconditions; 56 import com.android.internal.util.function.pooled.PooledLambda; 57 58 import java.io.Closeable; 59 import java.io.IOException; 60 import java.io.InputStream; 61 import java.io.OutputStream; 62 import java.lang.annotation.Retention; 63 import java.lang.annotation.RetentionPolicy; 64 import java.security.MessageDigest; 65 import java.util.ArrayList; 66 import java.util.Collections; 67 import java.util.Iterator; 68 import java.util.List; 69 import java.util.Set; 70 import java.util.concurrent.Executor; 71 72 /** 73 * Offers the ability to install, upgrade, and remove applications on the 74 * device. This includes support for apps packaged either as a single 75 * "monolithic" APK, or apps packaged as multiple "split" APKs. 76 * <p> 77 * An app is delivered for installation through a 78 * {@link PackageInstaller.Session}, which any app can create. Once the session 79 * is created, the installer can stream one or more APKs into place until it 80 * decides to either commit or destroy the session. Committing may require user 81 * intervention to complete the installation, unless the caller falls into one of the 82 * following categories, in which case the installation will complete automatically. 83 * <ul> 84 * <li>the device owner 85 * <li>the affiliated profile owner 86 * </ul> 87 * <p> 88 * Sessions can install brand new apps, upgrade existing apps, or add new splits 89 * into an existing app. 90 * <p> 91 * Apps packaged as multiple split APKs always consist of a single "base" APK 92 * (with a {@code null} split name) and zero or more "split" APKs (with unique 93 * split names). Any subset of these APKs can be installed together, as long as 94 * the following constraints are met: 95 * <ul> 96 * <li>All APKs must have the exact same package name, version code, and signing 97 * certificates. 98 * <li>All APKs must have unique split names. 99 * <li>All installations must contain a single base APK. 100 * </ul> 101 * <p> 102 * The ApiDemos project contains examples of using this API: 103 * <code>ApiDemos/src/com/example/android/apis/content/InstallApk*.java</code>. 104 * <p> 105 * On Android Q or above, an app installed notification will be posted 106 * by system after a new app is installed. 107 * To customize installer's notification icon, you should declare the following in the manifest 108 * <application> as follows: </p> 109 * <pre> 110 * <meta-data android:name="com.android.packageinstaller.notification.smallIcon" 111 * android:resource="@drawable/installer_notification_icon"/> 112 * </pre> 113 * <pre> 114 * <meta-data android:name="com.android.packageinstaller.notification.color" 115 * android:resource="@color/installer_notification_color"/> 116 * </pre> 117 */ 118 public class PackageInstaller { 119 private static final String TAG = "PackageInstaller"; 120 121 /** {@hide} */ 122 public static final boolean ENABLE_REVOCABLE_FD = 123 SystemProperties.getBoolean("fw.revocable_fd", false); 124 125 /** 126 * Activity Action: Show details about a particular install session. This 127 * may surface actions such as pause, resume, or cancel. 128 * <p> 129 * This should always be scoped to the installer package that owns the 130 * session. Clients should use {@link SessionInfo#createDetailsIntent()} to 131 * build this intent correctly. 132 * <p> 133 * In some cases, a matching Activity may not exist, so ensure you safeguard 134 * against this. 135 * <p> 136 * The session to show details for is defined in {@link #EXTRA_SESSION_ID}. 137 */ 138 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 139 public static final String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS"; 140 141 /** 142 * Broadcast Action: Explicit broadcast sent to the last known default launcher when a session 143 * for a new install is committed. For managed profile, this is sent to the default launcher 144 * of the primary profile. 145 * <p> 146 * The associated session is defined in {@link #EXTRA_SESSION} and the user for which this 147 * session was created in {@link Intent#EXTRA_USER}. 148 */ 149 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 150 public static final String ACTION_SESSION_COMMITTED = 151 "android.content.pm.action.SESSION_COMMITTED"; 152 153 /** 154 * Broadcast Action: Send information about a staged install session when its state is updated. 155 * <p> 156 * The associated session information is defined in {@link #EXTRA_SESSION}. 157 */ 158 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 159 public static final String ACTION_SESSION_UPDATED = 160 "android.content.pm.action.SESSION_UPDATED"; 161 162 /** {@hide} */ 163 public static final String ACTION_CONFIRM_INSTALL = "android.content.pm.action.CONFIRM_INSTALL"; 164 165 /** 166 * An integer session ID that an operation is working with. 167 * 168 * @see Intent#getIntExtra(String, int) 169 */ 170 public static final String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID"; 171 172 /** 173 * {@link SessionInfo} that an operation is working with. 174 * 175 * @see Intent#getParcelableExtra(String) 176 */ 177 public static final String EXTRA_SESSION = "android.content.pm.extra.SESSION"; 178 179 /** 180 * Package name that an operation is working with. 181 * 182 * @see Intent#getStringExtra(String) 183 */ 184 public static final String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME"; 185 186 /** 187 * Current status of an operation. Will be one of 188 * {@link #STATUS_PENDING_USER_ACTION}, {@link #STATUS_SUCCESS}, 189 * {@link #STATUS_FAILURE}, {@link #STATUS_FAILURE_ABORTED}, 190 * {@link #STATUS_FAILURE_BLOCKED}, {@link #STATUS_FAILURE_CONFLICT}, 191 * {@link #STATUS_FAILURE_INCOMPATIBLE}, {@link #STATUS_FAILURE_INVALID}, or 192 * {@link #STATUS_FAILURE_STORAGE}. 193 * <p> 194 * More information about a status may be available through additional 195 * extras; see the individual status documentation for details. 196 * 197 * @see Intent#getIntExtra(String, int) 198 */ 199 public static final String EXTRA_STATUS = "android.content.pm.extra.STATUS"; 200 201 /** 202 * Detailed string representation of the status, including raw details that 203 * are useful for debugging. 204 * 205 * @see Intent#getStringExtra(String) 206 */ 207 public static final String EXTRA_STATUS_MESSAGE = "android.content.pm.extra.STATUS_MESSAGE"; 208 209 /** 210 * Another package name relevant to a status. This is typically the package 211 * responsible for causing an operation failure. 212 * 213 * @see Intent#getStringExtra(String) 214 */ 215 public static final String 216 EXTRA_OTHER_PACKAGE_NAME = "android.content.pm.extra.OTHER_PACKAGE_NAME"; 217 218 /** 219 * Storage path relevant to a status. 220 * 221 * @see Intent#getStringExtra(String) 222 */ 223 public static final String EXTRA_STORAGE_PATH = "android.content.pm.extra.STORAGE_PATH"; 224 225 /** {@hide} */ 226 @Deprecated 227 public static final String EXTRA_PACKAGE_NAMES = "android.content.pm.extra.PACKAGE_NAMES"; 228 229 /** {@hide} */ 230 public static final String EXTRA_LEGACY_STATUS = "android.content.pm.extra.LEGACY_STATUS"; 231 /** {@hide} */ 232 public static final String EXTRA_LEGACY_BUNDLE = "android.content.pm.extra.LEGACY_BUNDLE"; 233 /** {@hide} */ 234 public static final String EXTRA_CALLBACK = "android.content.pm.extra.CALLBACK"; 235 236 /** 237 * User action is currently required to proceed. You can launch the intent 238 * activity described by {@link Intent#EXTRA_INTENT} to involve the user and 239 * continue. 240 * <p> 241 * You may choose to immediately launch the intent if the user is actively 242 * using your app. Otherwise, you should use a notification to guide the 243 * user back into your app before launching. 244 * 245 * @see Intent#getParcelableExtra(String) 246 */ 247 public static final int STATUS_PENDING_USER_ACTION = -1; 248 249 /** 250 * The operation succeeded. 251 */ 252 public static final int STATUS_SUCCESS = 0; 253 254 /** 255 * The operation failed in a generic way. The system will always try to 256 * provide a more specific failure reason, but in some rare cases this may 257 * be delivered. 258 * 259 * @see #EXTRA_STATUS_MESSAGE 260 */ 261 public static final int STATUS_FAILURE = 1; 262 263 /** 264 * The operation failed because it was blocked. For example, a device policy 265 * may be blocking the operation, a package verifier may have blocked the 266 * operation, or the app may be required for core system operation. 267 * <p> 268 * The result may also contain {@link #EXTRA_OTHER_PACKAGE_NAME} with the 269 * specific package blocking the install. 270 * 271 * @see #EXTRA_STATUS_MESSAGE 272 * @see #EXTRA_OTHER_PACKAGE_NAME 273 */ 274 public static final int STATUS_FAILURE_BLOCKED = 2; 275 276 /** 277 * The operation failed because it was actively aborted. For example, the 278 * user actively declined requested permissions, or the session was 279 * abandoned. 280 * 281 * @see #EXTRA_STATUS_MESSAGE 282 */ 283 public static final int STATUS_FAILURE_ABORTED = 3; 284 285 /** 286 * The operation failed because one or more of the APKs was invalid. For 287 * example, they might be malformed, corrupt, incorrectly signed, 288 * mismatched, etc. 289 * 290 * @see #EXTRA_STATUS_MESSAGE 291 */ 292 public static final int STATUS_FAILURE_INVALID = 4; 293 294 /** 295 * The operation failed because it conflicts (or is inconsistent with) with 296 * another package already installed on the device. For example, an existing 297 * permission, incompatible certificates, etc. The user may be able to 298 * uninstall another app to fix the issue. 299 * <p> 300 * The result may also contain {@link #EXTRA_OTHER_PACKAGE_NAME} with the 301 * specific package identified as the cause of the conflict. 302 * 303 * @see #EXTRA_STATUS_MESSAGE 304 * @see #EXTRA_OTHER_PACKAGE_NAME 305 */ 306 public static final int STATUS_FAILURE_CONFLICT = 5; 307 308 /** 309 * The operation failed because of storage issues. For example, the device 310 * may be running low on space, or external media may be unavailable. The 311 * user may be able to help free space or insert different external media. 312 * <p> 313 * The result may also contain {@link #EXTRA_STORAGE_PATH} with the path to 314 * the storage device that caused the failure. 315 * 316 * @see #EXTRA_STATUS_MESSAGE 317 * @see #EXTRA_STORAGE_PATH 318 */ 319 public static final int STATUS_FAILURE_STORAGE = 6; 320 321 /** 322 * The operation failed because it is fundamentally incompatible with this 323 * device. For example, the app may require a hardware feature that doesn't 324 * exist, it may be missing native code for the ABIs supported by the 325 * device, or it requires a newer SDK version, etc. 326 * 327 * @see #EXTRA_STATUS_MESSAGE 328 */ 329 public static final int STATUS_FAILURE_INCOMPATIBLE = 7; 330 331 private final IPackageInstaller mInstaller; 332 private final int mUserId; 333 private final String mInstallerPackageName; 334 335 private final ArrayList<SessionCallbackDelegate> mDelegates = new ArrayList<>(); 336 337 /** {@hide} */ PackageInstaller(IPackageInstaller installer, String installerPackageName, int userId)338 public PackageInstaller(IPackageInstaller installer, 339 String installerPackageName, int userId) { 340 mInstaller = installer; 341 mInstallerPackageName = installerPackageName; 342 mUserId = userId; 343 } 344 345 /** 346 * Create a new session using the given parameters, returning a unique ID 347 * that represents the session. Once created, the session can be opened 348 * multiple times across multiple device boots. 349 * <p> 350 * The system may automatically destroy sessions that have not been 351 * finalized (either committed or abandoned) within a reasonable period of 352 * time, typically on the order of a day. 353 * 354 * @throws IOException if parameters were unsatisfiable, such as lack of 355 * disk space or unavailable media. 356 * @throws SecurityException when installation services are unavailable, 357 * such as when called from a restricted user. 358 * @throws IllegalArgumentException when {@link SessionParams} is invalid. 359 * @return positive, non-zero unique ID that represents the created session. 360 * This ID remains consistent across device reboots until the 361 * session is finalized. IDs are not reused during a given boot. 362 */ createSession(@onNull SessionParams params)363 public int createSession(@NonNull SessionParams params) throws IOException { 364 try { 365 final String installerPackage; 366 if (params.installerPackageName == null) { 367 installerPackage = mInstallerPackageName; 368 } else { 369 installerPackage = params.installerPackageName; 370 } 371 372 return mInstaller.createSession(params, installerPackage, mUserId); 373 } catch (RuntimeException e) { 374 ExceptionUtils.maybeUnwrapIOException(e); 375 throw e; 376 } catch (RemoteException e) { 377 throw e.rethrowFromSystemServer(); 378 } 379 } 380 381 /** 382 * Open an existing session to actively perform work. To succeed, the caller 383 * must be the owner of the install session. 384 * 385 * @throws IOException if parameters were unsatisfiable, such as lack of 386 * disk space or unavailable media. 387 * @throws SecurityException when the caller does not own the session, or 388 * the session is invalid. 389 */ openSession(int sessionId)390 public @NonNull Session openSession(int sessionId) throws IOException { 391 try { 392 try { 393 return new Session(mInstaller.openSession(sessionId)); 394 } catch (RemoteException e) { 395 throw e.rethrowFromSystemServer(); 396 } 397 } catch (RuntimeException e) { 398 ExceptionUtils.maybeUnwrapIOException(e); 399 throw e; 400 } 401 } 402 403 /** 404 * Update the icon representing the app being installed in a specific 405 * session. This should be roughly 406 * {@link ActivityManager#getLauncherLargeIconSize()} in both dimensions. 407 * 408 * @throws SecurityException when the caller does not own the session, or 409 * the session is invalid. 410 */ updateSessionAppIcon(int sessionId, @Nullable Bitmap appIcon)411 public void updateSessionAppIcon(int sessionId, @Nullable Bitmap appIcon) { 412 try { 413 mInstaller.updateSessionAppIcon(sessionId, appIcon); 414 } catch (RemoteException e) { 415 throw e.rethrowFromSystemServer(); 416 } 417 } 418 419 /** 420 * Update the label representing the app being installed in a specific 421 * session. 422 * 423 * @throws SecurityException when the caller does not own the session, or 424 * the session is invalid. 425 */ updateSessionAppLabel(int sessionId, @Nullable CharSequence appLabel)426 public void updateSessionAppLabel(int sessionId, @Nullable CharSequence appLabel) { 427 try { 428 final String val = (appLabel != null) ? appLabel.toString() : null; 429 mInstaller.updateSessionAppLabel(sessionId, val); 430 } catch (RemoteException e) { 431 throw e.rethrowFromSystemServer(); 432 } 433 } 434 435 /** 436 * Completely abandon the given session, destroying all staged data and 437 * rendering it invalid. Abandoned sessions will be reported to 438 * {@link SessionCallback} listeners as failures. This is equivalent to 439 * opening the session and calling {@link Session#abandon()}. 440 * 441 * @throws SecurityException when the caller does not own the session, or 442 * the session is invalid. 443 */ abandonSession(int sessionId)444 public void abandonSession(int sessionId) { 445 try { 446 mInstaller.abandonSession(sessionId); 447 } catch (RemoteException e) { 448 throw e.rethrowFromSystemServer(); 449 } 450 } 451 452 /** 453 * Return details for a specific session. No special permissions are 454 * required to retrieve these details. 455 * 456 * @return details for the requested session, or {@code null} if the session 457 * does not exist. 458 */ getSessionInfo(int sessionId)459 public @Nullable SessionInfo getSessionInfo(int sessionId) { 460 try { 461 return mInstaller.getSessionInfo(sessionId); 462 } catch (RemoteException e) { 463 throw e.rethrowFromSystemServer(); 464 } 465 } 466 467 /** 468 * Return list of all known install sessions, regardless of the installer. 469 */ getAllSessions()470 public @NonNull List<SessionInfo> getAllSessions() { 471 try { 472 return mInstaller.getAllSessions(mUserId).getList(); 473 } catch (RemoteException e) { 474 throw e.rethrowFromSystemServer(); 475 } 476 } 477 478 /** 479 * Return list of all known install sessions owned by the calling app. 480 */ getMySessions()481 public @NonNull List<SessionInfo> getMySessions() { 482 try { 483 return mInstaller.getMySessions(mInstallerPackageName, mUserId).getList(); 484 } catch (RemoteException e) { 485 throw e.rethrowFromSystemServer(); 486 } 487 } 488 489 /** 490 * Return list of all staged install sessions. 491 */ getStagedSessions()492 public @NonNull List<SessionInfo> getStagedSessions() { 493 try { 494 // TODO: limit this to the mUserId? 495 return mInstaller.getStagedSessions().getList(); 496 } catch (RemoteException e) { 497 throw e.rethrowFromSystemServer(); 498 } 499 } 500 501 /** 502 * Returns an active staged session, or {@code null} if there is none. 503 * 504 * <p>Staged session is active iff: 505 * <ul> 506 * <li>It is committed, i.e. {@link SessionInfo#isCommitted()} is {@code true}, and 507 * <li>it is not applied, i.e. {@link SessionInfo#isStagedSessionApplied()} is {@code 508 * false}, and 509 * <li>it is not failed, i.e. {@link SessionInfo#isStagedSessionFailed()} is {@code false}. 510 * </ul> 511 * 512 * <p>In case of a multi-apk session, reasoning above is applied to the parent session, since 513 * that is the one that should been {@link Session#commit committed}. 514 */ getActiveStagedSession()515 public @Nullable SessionInfo getActiveStagedSession() { 516 final List<SessionInfo> stagedSessions = getStagedSessions(); 517 for (SessionInfo s : stagedSessions) { 518 if (s.isStagedSessionApplied() || s.isStagedSessionFailed()) { 519 // Finalized session. 520 continue; 521 } 522 if (s.getParentSessionId() != SessionInfo.INVALID_ID) { 523 // Child session. 524 continue; 525 } 526 if (s.isCommitted()) { 527 return s; 528 } 529 } 530 return null; 531 } 532 533 /** 534 * Uninstall the given package, removing it completely from the device. This 535 * method is available to: 536 * <ul> 537 * <li>the current "installer of record" for the package 538 * <li>the device owner 539 * <li>the affiliated profile owner 540 * </ul> 541 * 542 * @param packageName The package to uninstall. 543 * @param statusReceiver Where to deliver the result. 544 * 545 * @see android.app.admin.DevicePolicyManager 546 */ 547 @RequiresPermission(anyOf = { 548 Manifest.permission.DELETE_PACKAGES, 549 Manifest.permission.REQUEST_DELETE_PACKAGES}) uninstall(@onNull String packageName, @NonNull IntentSender statusReceiver)550 public void uninstall(@NonNull String packageName, @NonNull IntentSender statusReceiver) { 551 uninstall(packageName, 0 /*flags*/, statusReceiver); 552 } 553 554 /** 555 * Uninstall the given package, removing it completely from the device. This 556 * method is only available to the current "installer of record" for the 557 * package. 558 * 559 * @param packageName The package to uninstall. 560 * @param flags Flags for uninstall. 561 * @param statusReceiver Where to deliver the result. 562 * 563 * @hide 564 */ uninstall(@onNull String packageName, @DeleteFlags int flags, @NonNull IntentSender statusReceiver)565 public void uninstall(@NonNull String packageName, @DeleteFlags int flags, 566 @NonNull IntentSender statusReceiver) { 567 uninstall(new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST), 568 flags, statusReceiver); 569 } 570 571 /** 572 * Uninstall the given package with a specific version code, removing it 573 * completely from the device. If the version code of the package 574 * does not match the one passed in the versioned package argument this 575 * method is a no-op. Use {@link PackageManager#VERSION_CODE_HIGHEST} to 576 * uninstall the latest version of the package. 577 * <p> 578 * This method is available to: 579 * <ul> 580 * <li>the current "installer of record" for the package 581 * <li>the device owner 582 * <li>the affiliated profile owner 583 * </ul> 584 * 585 * @param versionedPackage The versioned package to uninstall. 586 * @param statusReceiver Where to deliver the result. 587 * 588 * @see android.app.admin.DevicePolicyManager 589 */ 590 @RequiresPermission(anyOf = { 591 Manifest.permission.DELETE_PACKAGES, 592 Manifest.permission.REQUEST_DELETE_PACKAGES}) uninstall(@onNull VersionedPackage versionedPackage, @NonNull IntentSender statusReceiver)593 public void uninstall(@NonNull VersionedPackage versionedPackage, 594 @NonNull IntentSender statusReceiver) { 595 uninstall(versionedPackage, 0 /*flags*/, statusReceiver); 596 } 597 598 /** 599 * Uninstall the given package with a specific version code, removing it 600 * completely from the device. This method is only available to the current 601 * "installer of record" for the package. If the version code of the package 602 * does not match the one passed in the versioned package argument this 603 * method is a no-op. Use {@link PackageManager#VERSION_CODE_HIGHEST} to 604 * uninstall the latest version of the package. 605 * 606 * @param versionedPackage The versioned package to uninstall. 607 * @param flags Flags for uninstall. 608 * @param statusReceiver Where to deliver the result. 609 * 610 * @hide 611 */ 612 @RequiresPermission(anyOf = { 613 Manifest.permission.DELETE_PACKAGES, 614 Manifest.permission.REQUEST_DELETE_PACKAGES}) uninstall(@onNull VersionedPackage versionedPackage, @DeleteFlags int flags, @NonNull IntentSender statusReceiver)615 public void uninstall(@NonNull VersionedPackage versionedPackage, @DeleteFlags int flags, 616 @NonNull IntentSender statusReceiver) { 617 Preconditions.checkNotNull(versionedPackage, "versionedPackage cannot be null"); 618 try { 619 mInstaller.uninstall(versionedPackage, mInstallerPackageName, 620 flags, statusReceiver, mUserId); 621 } catch (RemoteException e) { 622 throw e.rethrowFromSystemServer(); 623 } 624 } 625 626 /** 627 * Install the given package, which already exists on the device, for the user for which this 628 * installer was created. 629 * 630 * <p>This will 631 * {@link PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set) whitelist 632 * all restricted permissions}. 633 * 634 * @param packageName The package to install. 635 * @param installReason Reason for install. 636 * @param statusReceiver Where to deliver the result. 637 */ 638 @RequiresPermission(allOf = { 639 Manifest.permission.INSTALL_PACKAGES, 640 Manifest.permission.INSTALL_EXISTING_PACKAGES}) installExistingPackage(@onNull String packageName, @InstallReason int installReason, @Nullable IntentSender statusReceiver)641 public void installExistingPackage(@NonNull String packageName, 642 @InstallReason int installReason, 643 @Nullable IntentSender statusReceiver) { 644 Preconditions.checkNotNull(packageName, "packageName cannot be null"); 645 try { 646 mInstaller.installExistingPackage(packageName, 647 PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS, installReason, 648 statusReceiver, mUserId, null); 649 } catch (RemoteException e) { 650 throw e.rethrowFromSystemServer(); 651 } 652 } 653 654 655 /** {@hide} */ 656 @SystemApi 657 @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) setPermissionsResult(int sessionId, boolean accepted)658 public void setPermissionsResult(int sessionId, boolean accepted) { 659 try { 660 mInstaller.setPermissionsResult(sessionId, accepted); 661 } catch (RemoteException e) { 662 throw e.rethrowFromSystemServer(); 663 } 664 } 665 666 /** 667 * Events for observing session lifecycle. 668 * <p> 669 * A typical session lifecycle looks like this: 670 * <ul> 671 * <li>An installer creates a session to indicate pending app delivery. All 672 * install details are available at this point. 673 * <li>The installer opens the session to deliver APK data. Note that a 674 * session may be opened and closed multiple times as network connectivity 675 * changes. The installer may deliver periodic progress updates. 676 * <li>The installer commits or abandons the session, resulting in the 677 * session being finished. 678 * </ul> 679 */ 680 public static abstract class SessionCallback { 681 /** 682 * New session has been created. Details about the session can be 683 * obtained from {@link PackageInstaller#getSessionInfo(int)}. 684 */ onCreated(int sessionId)685 public abstract void onCreated(int sessionId); 686 687 /** 688 * Badging details for an existing session has changed. For example, the 689 * app icon or label has been updated. 690 */ onBadgingChanged(int sessionId)691 public abstract void onBadgingChanged(int sessionId); 692 693 /** 694 * Active state for session has been changed. 695 * <p> 696 * A session is considered active whenever there is ongoing forward 697 * progress being made, such as the installer holding an open 698 * {@link Session} instance while streaming data into place, or the 699 * system optimizing code as the result of 700 * {@link Session#commit(IntentSender)}. 701 * <p> 702 * If the installer closes the {@link Session} without committing, the 703 * session is considered inactive until the installer opens the session 704 * again. 705 */ onActiveChanged(int sessionId, boolean active)706 public abstract void onActiveChanged(int sessionId, boolean active); 707 708 /** 709 * Progress for given session has been updated. 710 * <p> 711 * Note that this progress may not directly correspond to the value 712 * reported by 713 * {@link PackageInstaller.Session#setStagingProgress(float)}, as the 714 * system may carve out a portion of the overall progress to represent 715 * its own internal installation work. 716 */ onProgressChanged(int sessionId, float progress)717 public abstract void onProgressChanged(int sessionId, float progress); 718 719 /** 720 * Session has completely finished, either with success or failure. 721 */ onFinished(int sessionId, boolean success)722 public abstract void onFinished(int sessionId, boolean success); 723 } 724 725 /** {@hide} */ 726 static class SessionCallbackDelegate extends IPackageInstallerCallback.Stub { 727 private static final int MSG_SESSION_CREATED = 1; 728 private static final int MSG_SESSION_BADGING_CHANGED = 2; 729 private static final int MSG_SESSION_ACTIVE_CHANGED = 3; 730 private static final int MSG_SESSION_PROGRESS_CHANGED = 4; 731 private static final int MSG_SESSION_FINISHED = 5; 732 733 final SessionCallback mCallback; 734 final Executor mExecutor; 735 SessionCallbackDelegate(SessionCallback callback, Executor executor)736 SessionCallbackDelegate(SessionCallback callback, Executor executor) { 737 mCallback = callback; 738 mExecutor = executor; 739 } 740 741 @Override onSessionCreated(int sessionId)742 public void onSessionCreated(int sessionId) { 743 mExecutor.execute(PooledLambda.obtainRunnable(SessionCallback::onCreated, mCallback, 744 sessionId).recycleOnUse()); 745 } 746 747 @Override onSessionBadgingChanged(int sessionId)748 public void onSessionBadgingChanged(int sessionId) { 749 mExecutor.execute(PooledLambda.obtainRunnable(SessionCallback::onBadgingChanged, 750 mCallback, sessionId).recycleOnUse()); 751 } 752 753 @Override onSessionActiveChanged(int sessionId, boolean active)754 public void onSessionActiveChanged(int sessionId, boolean active) { 755 mExecutor.execute(PooledLambda.obtainRunnable(SessionCallback::onActiveChanged, 756 mCallback, sessionId, active).recycleOnUse()); 757 } 758 759 @Override onSessionProgressChanged(int sessionId, float progress)760 public void onSessionProgressChanged(int sessionId, float progress) { 761 mExecutor.execute(PooledLambda.obtainRunnable(SessionCallback::onProgressChanged, 762 mCallback, sessionId, progress).recycleOnUse()); 763 } 764 765 @Override onSessionFinished(int sessionId, boolean success)766 public void onSessionFinished(int sessionId, boolean success) { 767 mExecutor.execute(PooledLambda.obtainRunnable(SessionCallback::onFinished, 768 mCallback, sessionId, success).recycleOnUse()); 769 } 770 } 771 772 /** {@hide} */ 773 @Deprecated addSessionCallback(@onNull SessionCallback callback)774 public void addSessionCallback(@NonNull SessionCallback callback) { 775 registerSessionCallback(callback); 776 } 777 778 /** 779 * Register to watch for session lifecycle events. No special permissions 780 * are required to watch for these events. 781 */ registerSessionCallback(@onNull SessionCallback callback)782 public void registerSessionCallback(@NonNull SessionCallback callback) { 783 registerSessionCallback(callback, new Handler()); 784 } 785 786 /** {@hide} */ 787 @Deprecated addSessionCallback(@onNull SessionCallback callback, @NonNull Handler handler)788 public void addSessionCallback(@NonNull SessionCallback callback, @NonNull Handler handler) { 789 registerSessionCallback(callback, handler); 790 } 791 792 /** 793 * Register to watch for session lifecycle events. No special permissions 794 * are required to watch for these events. 795 * 796 * @param handler to dispatch callback events through, otherwise uses 797 * calling thread. 798 */ registerSessionCallback(@onNull SessionCallback callback, @NonNull Handler handler)799 public void registerSessionCallback(@NonNull SessionCallback callback, @NonNull Handler handler) { 800 synchronized (mDelegates) { 801 final SessionCallbackDelegate delegate = new SessionCallbackDelegate(callback, 802 new HandlerExecutor(handler)); 803 try { 804 mInstaller.registerCallback(delegate, mUserId); 805 } catch (RemoteException e) { 806 throw e.rethrowFromSystemServer(); 807 } 808 mDelegates.add(delegate); 809 } 810 } 811 812 /** {@hide} */ 813 @Deprecated removeSessionCallback(@onNull SessionCallback callback)814 public void removeSessionCallback(@NonNull SessionCallback callback) { 815 unregisterSessionCallback(callback); 816 } 817 818 /** 819 * Unregister a previously registered callback. 820 */ unregisterSessionCallback(@onNull SessionCallback callback)821 public void unregisterSessionCallback(@NonNull SessionCallback callback) { 822 synchronized (mDelegates) { 823 for (Iterator<SessionCallbackDelegate> i = mDelegates.iterator(); i.hasNext();) { 824 final SessionCallbackDelegate delegate = i.next(); 825 if (delegate.mCallback == callback) { 826 try { 827 mInstaller.unregisterCallback(delegate); 828 } catch (RemoteException e) { 829 throw e.rethrowFromSystemServer(); 830 } 831 i.remove(); 832 } 833 } 834 } 835 } 836 837 /** 838 * An installation that is being actively staged. For an install to succeed, 839 * all existing and new packages must have identical package names, version 840 * codes, and signing certificates. 841 * <p> 842 * A session may contain any number of split packages. If the application 843 * does not yet exist, this session must include a base package. 844 * <p> 845 * If an APK included in this session is already defined by the existing 846 * installation (for example, the same split name), the APK in this session 847 * will replace the existing APK. 848 * <p> 849 * In such a case that multiple packages need to be committed simultaneously, 850 * multiple sessions can be referenced by a single multi-package session. 851 * This session is created with no package name and calling 852 * {@link SessionParams#setMultiPackage()}. The individual session IDs can be 853 * added with {@link #addChildSessionId(int)} and commit of the multi-package 854 * session will result in all child sessions being committed atomically. 855 */ 856 public static class Session implements Closeable { 857 /** {@hide} */ 858 protected final IPackageInstallerSession mSession; 859 860 /** {@hide} */ Session(IPackageInstallerSession session)861 public Session(IPackageInstallerSession session) { 862 mSession = session; 863 } 864 865 /** {@hide} */ 866 @Deprecated setProgress(float progress)867 public void setProgress(float progress) { 868 setStagingProgress(progress); 869 } 870 871 /** 872 * Set current progress of staging this session. Valid values are 873 * anywhere between 0 and 1. 874 * <p> 875 * Note that this progress may not directly correspond to the value 876 * reported by {@link SessionCallback#onProgressChanged(int, float)}, as 877 * the system may carve out a portion of the overall progress to 878 * represent its own internal installation work. 879 */ setStagingProgress(float progress)880 public void setStagingProgress(float progress) { 881 try { 882 mSession.setClientProgress(progress); 883 } catch (RemoteException e) { 884 throw e.rethrowFromSystemServer(); 885 } 886 } 887 888 /** {@hide} */ 889 @UnsupportedAppUsage addProgress(float progress)890 public void addProgress(float progress) { 891 try { 892 mSession.addClientProgress(progress); 893 } catch (RemoteException e) { 894 throw e.rethrowFromSystemServer(); 895 } 896 } 897 898 /** 899 * Open a stream to write an APK file into the session. 900 * <p> 901 * The returned stream will start writing data at the requested offset 902 * in the underlying file, which can be used to resume a partially 903 * written file. If a valid file length is specified, the system will 904 * preallocate the underlying disk space to optimize placement on disk. 905 * It's strongly recommended to provide a valid file length when known. 906 * <p> 907 * You can write data into the returned stream, optionally call 908 * {@link #fsync(OutputStream)} as needed to ensure bytes have been 909 * persisted to disk, and then close when finished. All streams must be 910 * closed before calling {@link #commit(IntentSender)}. 911 * 912 * @param name arbitrary, unique name of your choosing to identify the 913 * APK being written. You can open a file again for 914 * additional writes (such as after a reboot) by using the 915 * same name. This name is only meaningful within the context 916 * of a single install session. 917 * @param offsetBytes offset into the file to begin writing at, or 0 to 918 * start at the beginning of the file. 919 * @param lengthBytes total size of the file being written, used to 920 * preallocate the underlying disk space, or -1 if unknown. 921 * The system may clear various caches as needed to allocate 922 * this space. 923 * @throws IOException if trouble opening the file for writing, such as 924 * lack of disk space or unavailable media. 925 * @throws SecurityException if called after the session has been 926 * sealed or abandoned 927 */ openWrite(@onNull String name, long offsetBytes, long lengthBytes)928 public @NonNull OutputStream openWrite(@NonNull String name, long offsetBytes, 929 long lengthBytes) throws IOException { 930 try { 931 if (ENABLE_REVOCABLE_FD) { 932 return new ParcelFileDescriptor.AutoCloseOutputStream( 933 mSession.openWrite(name, offsetBytes, lengthBytes)); 934 } else { 935 final ParcelFileDescriptor clientSocket = mSession.openWrite(name, 936 offsetBytes, lengthBytes); 937 return new FileBridge.FileBridgeOutputStream(clientSocket); 938 } 939 } catch (RuntimeException e) { 940 ExceptionUtils.maybeUnwrapIOException(e); 941 throw e; 942 } catch (RemoteException e) { 943 throw e.rethrowFromSystemServer(); 944 } 945 } 946 947 /** {@hide} */ write(@onNull String name, long offsetBytes, long lengthBytes, @NonNull ParcelFileDescriptor fd)948 public void write(@NonNull String name, long offsetBytes, long lengthBytes, 949 @NonNull ParcelFileDescriptor fd) throws IOException { 950 try { 951 mSession.write(name, offsetBytes, lengthBytes, fd); 952 } catch (RuntimeException e) { 953 ExceptionUtils.maybeUnwrapIOException(e); 954 throw e; 955 } catch (RemoteException e) { 956 throw e.rethrowFromSystemServer(); 957 } 958 } 959 960 /** 961 * Ensure that any outstanding data for given stream has been committed 962 * to disk. This is only valid for streams returned from 963 * {@link #openWrite(String, long, long)}. 964 */ fsync(@onNull OutputStream out)965 public void fsync(@NonNull OutputStream out) throws IOException { 966 if (ENABLE_REVOCABLE_FD) { 967 if (out instanceof ParcelFileDescriptor.AutoCloseOutputStream) { 968 try { 969 Os.fsync(((ParcelFileDescriptor.AutoCloseOutputStream) out).getFD()); 970 } catch (ErrnoException e) { 971 throw e.rethrowAsIOException(); 972 } 973 } else { 974 throw new IllegalArgumentException("Unrecognized stream"); 975 } 976 } else { 977 if (out instanceof FileBridge.FileBridgeOutputStream) { 978 ((FileBridge.FileBridgeOutputStream) out).fsync(); 979 } else { 980 throw new IllegalArgumentException("Unrecognized stream"); 981 } 982 } 983 } 984 985 /** 986 * Return all APK names contained in this session. 987 * <p> 988 * This returns all names which have been previously written through 989 * {@link #openWrite(String, long, long)} as part of this session. 990 * 991 * @throws SecurityException if called after the session has been 992 * committed or abandoned. 993 */ getNames()994 public @NonNull String[] getNames() throws IOException { 995 try { 996 return mSession.getNames(); 997 } catch (RuntimeException e) { 998 ExceptionUtils.maybeUnwrapIOException(e); 999 throw e; 1000 } catch (RemoteException e) { 1001 throw e.rethrowFromSystemServer(); 1002 } 1003 } 1004 1005 /** 1006 * Open a stream to read an APK file from the session. 1007 * <p> 1008 * This is only valid for names which have been previously written 1009 * through {@link #openWrite(String, long, long)} as part of this 1010 * session. For example, this stream may be used to calculate a 1011 * {@link MessageDigest} of a written APK before committing. 1012 * 1013 * @throws SecurityException if called after the session has been 1014 * committed or abandoned. 1015 */ openRead(@onNull String name)1016 public @NonNull InputStream openRead(@NonNull String name) throws IOException { 1017 try { 1018 final ParcelFileDescriptor pfd = mSession.openRead(name); 1019 return new ParcelFileDescriptor.AutoCloseInputStream(pfd); 1020 } catch (RuntimeException e) { 1021 ExceptionUtils.maybeUnwrapIOException(e); 1022 throw e; 1023 } catch (RemoteException e) { 1024 throw e.rethrowFromSystemServer(); 1025 } 1026 } 1027 1028 /** 1029 * Removes a split. 1030 * <p> 1031 * Split removals occur prior to adding new APKs. If upgrading a feature 1032 * split, it is not expected nor desirable to remove the split prior to 1033 * upgrading. 1034 * <p> 1035 * When split removal is bundled with new APKs, the packageName must be 1036 * identical. 1037 */ removeSplit(@onNull String splitName)1038 public void removeSplit(@NonNull String splitName) throws IOException { 1039 try { 1040 mSession.removeSplit(splitName); 1041 } catch (RuntimeException e) { 1042 ExceptionUtils.maybeUnwrapIOException(e); 1043 throw e; 1044 } catch (RemoteException e) { 1045 throw e.rethrowFromSystemServer(); 1046 } 1047 } 1048 1049 /** 1050 * Attempt to commit everything staged in this session. This may require 1051 * user intervention, and so it may not happen immediately. The final 1052 * result of the commit will be reported through the given callback. 1053 * <p> 1054 * Once this method is called, the session is sealed and no additional 1055 * mutations may be performed on the session. If the device reboots 1056 * before the session has been finalized, you may commit the session again. 1057 * <p> 1058 * If the installer is the device owner or the affiliated profile owner, there will be no 1059 * user intervention. 1060 * 1061 * @param statusReceiver Called when the state of the session changes. Intents 1062 * sent to this receiver contain {@link #EXTRA_STATUS}. Refer to the 1063 * individual status codes on how to handle them. 1064 * 1065 * @throws SecurityException if streams opened through 1066 * {@link #openWrite(String, long, long)} are still open. 1067 * 1068 * @see android.app.admin.DevicePolicyManager 1069 */ commit(@onNull IntentSender statusReceiver)1070 public void commit(@NonNull IntentSender statusReceiver) { 1071 try { 1072 mSession.commit(statusReceiver, false); 1073 } catch (RemoteException e) { 1074 throw e.rethrowFromSystemServer(); 1075 } 1076 } 1077 1078 /** 1079 * Attempt to commit a session that has been {@link #transfer(String) transferred}. 1080 * 1081 * <p>If the device reboots before the session has been finalized, you may commit the 1082 * session again. 1083 * 1084 * <p>The caller of this method is responsible to ensure the safety of the session. As the 1085 * session was created by another - usually less trusted - app, it is paramount that before 1086 * committing <u>all</u> public and system {@link SessionInfo properties of the session} 1087 * and <u>all</u> {@link #openRead(String) APKs} are verified by the caller. It might happen 1088 * that new properties are added to the session with a new API revision. In this case the 1089 * callers need to be updated. 1090 * 1091 * @param statusReceiver Called when the state of the session changes. Intents 1092 * sent to this receiver contain {@link #EXTRA_STATUS}. Refer to the 1093 * individual status codes on how to handle them. 1094 * 1095 * @hide 1096 */ 1097 @SystemApi 1098 @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) commitTransferred(@onNull IntentSender statusReceiver)1099 public void commitTransferred(@NonNull IntentSender statusReceiver) { 1100 try { 1101 mSession.commit(statusReceiver, true); 1102 } catch (RemoteException e) { 1103 throw e.rethrowFromSystemServer(); 1104 } 1105 } 1106 1107 /** 1108 * Transfer the session to a new owner. 1109 * <p> 1110 * Only sessions that update the installing app can be transferred. 1111 * <p> 1112 * After the transfer to a package with a different uid all method calls on the session 1113 * will cause {@link SecurityException}s. 1114 * <p> 1115 * Once this method is called, the session is sealed and no additional mutations beside 1116 * committing it may be performed on the session. 1117 * 1118 * @param packageName The package of the new owner. Needs to hold the INSTALL_PACKAGES 1119 * permission. 1120 * 1121 * @throws PackageManager.NameNotFoundException if the new owner could not be found. 1122 * @throws SecurityException if called after the session has been committed or abandoned. 1123 * @throws SecurityException if the session does not update the original installer 1124 * @throws SecurityException if streams opened through 1125 * {@link #openWrite(String, long, long) are still open. 1126 */ transfer(@onNull String packageName)1127 public void transfer(@NonNull String packageName) 1128 throws PackageManager.NameNotFoundException { 1129 Preconditions.checkNotNull(packageName); 1130 1131 try { 1132 mSession.transfer(packageName); 1133 } catch (ParcelableException e) { 1134 e.maybeRethrow(PackageManager.NameNotFoundException.class); 1135 throw new RuntimeException(e); 1136 } catch (RemoteException e) { 1137 throw e.rethrowFromSystemServer(); 1138 } 1139 } 1140 1141 /** 1142 * Release this session object. You can open the session again if it 1143 * hasn't been finalized. 1144 */ 1145 @Override close()1146 public void close() { 1147 try { 1148 mSession.close(); 1149 } catch (RemoteException e) { 1150 throw e.rethrowFromSystemServer(); 1151 } 1152 } 1153 1154 /** 1155 * Completely abandon this session, destroying all staged data and 1156 * rendering it invalid. Abandoned sessions will be reported to 1157 * {@link SessionCallback} listeners as failures. This is equivalent to 1158 * opening the session and calling {@link Session#abandon()}. 1159 */ abandon()1160 public void abandon() { 1161 try { 1162 mSession.abandon(); 1163 } catch (RemoteException e) { 1164 throw e.rethrowFromSystemServer(); 1165 } 1166 } 1167 1168 /** 1169 * @return {@code true} if this session will commit more than one package when it is 1170 * committed. 1171 */ isMultiPackage()1172 public boolean isMultiPackage() { 1173 try { 1174 return mSession.isMultiPackage(); 1175 } catch (RemoteException e) { 1176 throw e.rethrowFromSystemServer(); 1177 } 1178 } 1179 1180 /** 1181 * @return {@code true} if this session will be staged and applied at next reboot. 1182 */ isStaged()1183 public boolean isStaged() { 1184 try { 1185 return mSession.isStaged(); 1186 } catch (RemoteException e) { 1187 throw e.rethrowFromSystemServer(); 1188 } 1189 } 1190 1191 /** 1192 * @return the session ID of the multi-package session that this belongs to or 1193 * {@link SessionInfo#INVALID_ID} if it does not belong to a multi-package session. 1194 */ getParentSessionId()1195 public int getParentSessionId() { 1196 try { 1197 return mSession.getParentSessionId(); 1198 } catch (RemoteException e) { 1199 throw e.rethrowFromSystemServer(); 1200 } 1201 } 1202 1203 /** 1204 * @return the set of session IDs that will be committed atomically when this session is 1205 * committed if this is a multi-package session or null if none exist. 1206 */ 1207 @NonNull getChildSessionIds()1208 public int[] getChildSessionIds() { 1209 try { 1210 return mSession.getChildSessionIds(); 1211 } catch (RemoteException e) { 1212 throw e.rethrowFromSystemServer(); 1213 } 1214 } 1215 1216 /** 1217 * Adds a session ID to the set of sessions that will be committed atomically 1218 * when this session is committed. 1219 * 1220 * <p>If the parent is staged or has rollback enabled, all children must have 1221 * the same properties. 1222 * 1223 * @param sessionId the session ID to add to this multi-package session. 1224 */ addChildSessionId(int sessionId)1225 public void addChildSessionId(int sessionId) { 1226 try { 1227 mSession.addChildSessionId(sessionId); 1228 } catch (RemoteException e) { 1229 e.rethrowFromSystemServer(); 1230 } 1231 } 1232 1233 /** 1234 * Removes a session ID from the set of sessions that will be committed 1235 * atomically when this session is committed. 1236 * 1237 * @param sessionId the session ID to remove from this multi-package session. 1238 */ removeChildSessionId(int sessionId)1239 public void removeChildSessionId(int sessionId) { 1240 try { 1241 mSession.removeChildSessionId(sessionId); 1242 } catch (RemoteException e) { 1243 e.rethrowFromSystemServer(); 1244 } 1245 } 1246 } 1247 1248 /** 1249 * Parameters for creating a new {@link PackageInstaller.Session}. 1250 */ 1251 public static class SessionParams implements Parcelable { 1252 1253 /** {@hide} */ 1254 public static final int MODE_INVALID = -1; 1255 1256 /** 1257 * Mode for an install session whose staged APKs should fully replace any 1258 * existing APKs for the target app. 1259 */ 1260 public static final int MODE_FULL_INSTALL = 1; 1261 1262 /** 1263 * Mode for an install session that should inherit any existing APKs for the 1264 * target app, unless they have been explicitly overridden (based on split 1265 * name) by the session. For example, this can be used to add one or more 1266 * split APKs to an existing installation. 1267 * <p> 1268 * If there are no existing APKs for the target app, this behaves like 1269 * {@link #MODE_FULL_INSTALL}. 1270 */ 1271 public static final int MODE_INHERIT_EXISTING = 2; 1272 1273 /** 1274 * Special constant to refer to all restricted permissions. 1275 */ 1276 public static final @NonNull Set<String> RESTRICTED_PERMISSIONS_ALL = new ArraySet<>(); 1277 1278 /** {@hide} */ 1279 public static final int UID_UNKNOWN = -1; 1280 1281 /** {@hide} */ 1282 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 1283 public int mode = MODE_INVALID; 1284 /** {@hide} */ 1285 @UnsupportedAppUsage 1286 public int installFlags = PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS; 1287 /** {@hide} */ 1288 public int installLocation = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY; 1289 /** {@hide} */ 1290 public @InstallReason int installReason = PackageManager.INSTALL_REASON_UNKNOWN; 1291 /** {@hide} */ 1292 @UnsupportedAppUsage 1293 public long sizeBytes = -1; 1294 /** {@hide} */ 1295 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 1296 public String appPackageName; 1297 /** {@hide} */ 1298 @UnsupportedAppUsage 1299 public Bitmap appIcon; 1300 /** {@hide} */ 1301 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 1302 public String appLabel; 1303 /** {@hide} */ 1304 public long appIconLastModified = -1; 1305 /** {@hide} */ 1306 public Uri originatingUri; 1307 /** {@hide} */ 1308 @UnsupportedAppUsage 1309 public int originatingUid = UID_UNKNOWN; 1310 /** {@hide} */ 1311 public Uri referrerUri; 1312 /** {@hide} */ 1313 public String abiOverride; 1314 /** {@hide} */ 1315 public String volumeUuid; 1316 /** {@hide} */ 1317 public String[] grantedRuntimePermissions; 1318 /** {@hide} */ 1319 public List<String> whitelistedRestrictedPermissions; 1320 /** {@hide} */ 1321 public String installerPackageName; 1322 /** {@hide} */ 1323 public boolean isMultiPackage; 1324 /** {@hide} */ 1325 public boolean isStaged; 1326 /** {@hide} */ 1327 public long requiredInstalledVersionCode = PackageManager.VERSION_CODE_HIGHEST; 1328 1329 /** 1330 * Construct parameters for a new package install session. 1331 * 1332 * @param mode one of {@link #MODE_FULL_INSTALL} or 1333 * {@link #MODE_INHERIT_EXISTING} describing how the session 1334 * should interact with an existing app. 1335 */ SessionParams(int mode)1336 public SessionParams(int mode) { 1337 this.mode = mode; 1338 } 1339 1340 /** {@hide} */ SessionParams(Parcel source)1341 public SessionParams(Parcel source) { 1342 mode = source.readInt(); 1343 installFlags = source.readInt(); 1344 installLocation = source.readInt(); 1345 installReason = source.readInt(); 1346 sizeBytes = source.readLong(); 1347 appPackageName = source.readString(); 1348 appIcon = source.readParcelable(null); 1349 appLabel = source.readString(); 1350 originatingUri = source.readParcelable(null); 1351 originatingUid = source.readInt(); 1352 referrerUri = source.readParcelable(null); 1353 abiOverride = source.readString(); 1354 volumeUuid = source.readString(); 1355 grantedRuntimePermissions = source.readStringArray(); 1356 whitelistedRestrictedPermissions = source.createStringArrayList(); 1357 installerPackageName = source.readString(); 1358 isMultiPackage = source.readBoolean(); 1359 isStaged = source.readBoolean(); 1360 requiredInstalledVersionCode = source.readLong(); 1361 } 1362 1363 /** {@hide} */ copy()1364 public SessionParams copy() { 1365 SessionParams ret = new SessionParams(mode); 1366 ret.installFlags = installFlags; 1367 ret.installLocation = installLocation; 1368 ret.installReason = installReason; 1369 ret.sizeBytes = sizeBytes; 1370 ret.appPackageName = appPackageName; 1371 ret.appIcon = appIcon; // not a copy. 1372 ret.appLabel = appLabel; 1373 ret.originatingUri = originatingUri; // not a copy, but immutable. 1374 ret.originatingUid = originatingUid; 1375 ret.referrerUri = referrerUri; // not a copy, but immutable. 1376 ret.abiOverride = abiOverride; 1377 ret.volumeUuid = volumeUuid; 1378 ret.grantedRuntimePermissions = grantedRuntimePermissions; 1379 ret.whitelistedRestrictedPermissions = whitelistedRestrictedPermissions; 1380 ret.installerPackageName = installerPackageName; 1381 ret.isMultiPackage = isMultiPackage; 1382 ret.isStaged = isStaged; 1383 ret.requiredInstalledVersionCode = requiredInstalledVersionCode; 1384 return ret; 1385 } 1386 1387 /** 1388 * Check if there are hidden options set. 1389 * 1390 * <p>Hidden options are those options that cannot be verified via public or system-api 1391 * methods on {@link SessionInfo}. 1392 * 1393 * @return {@code true} if any hidden option is set. 1394 * 1395 * @hide 1396 */ areHiddenOptionsSet()1397 public boolean areHiddenOptionsSet() { 1398 return (installFlags & (PackageManager.INSTALL_REQUEST_DOWNGRADE 1399 | PackageManager.INSTALL_ALLOW_DOWNGRADE 1400 | PackageManager.INSTALL_DONT_KILL_APP 1401 | PackageManager.INSTALL_INSTANT_APP 1402 | PackageManager.INSTALL_FULL_APP 1403 | PackageManager.INSTALL_VIRTUAL_PRELOAD 1404 | PackageManager.INSTALL_ALLOCATE_AGGRESSIVE)) != installFlags 1405 || abiOverride != null || volumeUuid != null; 1406 } 1407 1408 /** 1409 * Provide value of {@link PackageInfo#installLocation}, which may be used 1410 * to determine where the app will be staged. Defaults to 1411 * {@link PackageInfo#INSTALL_LOCATION_INTERNAL_ONLY}. 1412 */ setInstallLocation(int installLocation)1413 public void setInstallLocation(int installLocation) { 1414 this.installLocation = installLocation; 1415 } 1416 1417 /** 1418 * Optionally indicate the total size (in bytes) of all APKs that will be 1419 * delivered in this session. The system may use this to ensure enough disk 1420 * space exists before proceeding, or to estimate container size for 1421 * installations living on external storage. 1422 * 1423 * @see PackageInfo#INSTALL_LOCATION_AUTO 1424 * @see PackageInfo#INSTALL_LOCATION_PREFER_EXTERNAL 1425 */ setSize(long sizeBytes)1426 public void setSize(long sizeBytes) { 1427 this.sizeBytes = sizeBytes; 1428 } 1429 1430 /** 1431 * Optionally set the package name of the app being installed. It's strongly 1432 * recommended that you provide this value when known, so that observers can 1433 * communicate installing apps to users. 1434 * <p> 1435 * If the APKs staged in the session aren't consistent with this package 1436 * name, the install will fail. Regardless of this value, all APKs in the 1437 * app must have the same package name. 1438 */ setAppPackageName(@ullable String appPackageName)1439 public void setAppPackageName(@Nullable String appPackageName) { 1440 this.appPackageName = appPackageName; 1441 } 1442 1443 /** 1444 * Optionally set an icon representing the app being installed. This should 1445 * be roughly {@link ActivityManager#getLauncherLargeIconSize()} in both 1446 * dimensions. 1447 */ setAppIcon(@ullable Bitmap appIcon)1448 public void setAppIcon(@Nullable Bitmap appIcon) { 1449 this.appIcon = appIcon; 1450 } 1451 1452 /** 1453 * Optionally set a label representing the app being installed. 1454 */ setAppLabel(@ullable CharSequence appLabel)1455 public void setAppLabel(@Nullable CharSequence appLabel) { 1456 this.appLabel = (appLabel != null) ? appLabel.toString() : null; 1457 } 1458 1459 /** 1460 * Optionally set the URI where this package was downloaded from. This is 1461 * informational and may be used as a signal for anti-malware purposes. 1462 * 1463 * @see Intent#EXTRA_ORIGINATING_URI 1464 */ setOriginatingUri(@ullable Uri originatingUri)1465 public void setOriginatingUri(@Nullable Uri originatingUri) { 1466 this.originatingUri = originatingUri; 1467 } 1468 1469 /** 1470 * Sets the UID that initiated the package installation. This is informational 1471 * and may be used as a signal for anti-malware purposes. 1472 */ setOriginatingUid(int originatingUid)1473 public void setOriginatingUid(int originatingUid) { 1474 this.originatingUid = originatingUid; 1475 } 1476 1477 /** 1478 * Optionally set the URI that referred you to install this package. This is 1479 * informational and may be used as a signal for anti-malware purposes. 1480 * 1481 * @see Intent#EXTRA_REFERRER 1482 */ setReferrerUri(@ullable Uri referrerUri)1483 public void setReferrerUri(@Nullable Uri referrerUri) { 1484 this.referrerUri = referrerUri; 1485 } 1486 1487 /** 1488 * Sets which runtime permissions to be granted to the package at installation. 1489 * 1490 * @param permissions The permissions to grant or null to grant all runtime 1491 * permissions. 1492 * 1493 * @hide 1494 */ 1495 @TestApi 1496 @SystemApi 1497 @RequiresPermission(android.Manifest.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS) setGrantedRuntimePermissions(String[] permissions)1498 public void setGrantedRuntimePermissions(String[] permissions) { 1499 installFlags |= PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS; 1500 this.grantedRuntimePermissions = permissions; 1501 } 1502 1503 /** 1504 * Sets which restricted permissions to be whitelisted for the app. Whitelisting 1505 * is not granting the permissions, rather it allows the app to hold permissions 1506 * which are otherwise restricted. Whitelisting a non restricted permission has 1507 * no effect. 1508 * 1509 * <p> Permissions can be hard restricted which means that the app cannot hold 1510 * them or soft restricted where the app can hold the permission but in a weaker 1511 * form. Whether a permission is {@link PermissionInfo#FLAG_HARD_RESTRICTED hard 1512 * restricted} or {@link PermissionInfo#FLAG_SOFT_RESTRICTED soft restricted} 1513 * depends on the permission declaration. Whitelisting a hard restricted permission 1514 * allows the app to hold that permission and whitelisting a soft restricted 1515 * permission allows the app to hold the permission in its full, unrestricted form. 1516 * 1517 * <p> Permissions can also be immutably restricted which means that the whitelist 1518 * state of the permission can be determined only at install time and cannot be 1519 * changed on updated or at a later point via the package manager APIs. 1520 * 1521 * <p>Initially, all restricted permissions are whitelisted but you can change 1522 * which ones are whitelisted by calling this method or the corresponding ones 1523 * on the {@link PackageManager}. 1524 * 1525 * @see PackageManager#addWhitelistedRestrictedPermission(String, String, int) 1526 * @see PackageManager#removeWhitelistedRestrictedPermission(String, String, int) 1527 */ setWhitelistedRestrictedPermissions(@ullable Set<String> permissions)1528 public void setWhitelistedRestrictedPermissions(@Nullable Set<String> permissions) { 1529 if (permissions == RESTRICTED_PERMISSIONS_ALL) { 1530 installFlags |= PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS; 1531 whitelistedRestrictedPermissions = null; 1532 } else { 1533 installFlags &= ~PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS; 1534 whitelistedRestrictedPermissions = (permissions != null) 1535 ? new ArrayList<>(permissions) : null; 1536 } 1537 } 1538 1539 /** 1540 * Request that rollbacks be enabled or disabled for the given upgrade. 1541 * 1542 * <p>If the parent session is staged or has rollback enabled, all children sessions 1543 * must have the same properties. 1544 * 1545 * @param enable set to {@code true} to enable, {@code false} to disable 1546 * @hide 1547 */ 1548 @SystemApi @TestApi setEnableRollback(boolean enable)1549 public void setEnableRollback(boolean enable) { 1550 if (enable) { 1551 installFlags |= PackageManager.INSTALL_ENABLE_ROLLBACK; 1552 } else { 1553 installFlags &= ~PackageManager.INSTALL_ENABLE_ROLLBACK; 1554 } 1555 } 1556 1557 /** 1558 * @deprecated use {@link #setRequestDowngrade(boolean)}. 1559 * {@hide} 1560 */ 1561 @SystemApi 1562 @Deprecated setAllowDowngrade(boolean allowDowngrade)1563 public void setAllowDowngrade(boolean allowDowngrade) { 1564 setRequestDowngrade(allowDowngrade); 1565 } 1566 1567 /** {@hide} */ 1568 @SystemApi setRequestDowngrade(boolean requestDowngrade)1569 public void setRequestDowngrade(boolean requestDowngrade) { 1570 if (requestDowngrade) { 1571 installFlags |= PackageManager.INSTALL_REQUEST_DOWNGRADE; 1572 } else { 1573 installFlags &= ~PackageManager.INSTALL_REQUEST_DOWNGRADE; 1574 } 1575 } 1576 1577 /** 1578 * Require the given version of the package be installed. 1579 * The install will only be allowed if the existing version code of 1580 * the package installed on the device matches the given version code. 1581 * Use {@link * PackageManager#VERSION_CODE_HIGHEST} to allow 1582 * installation regardless of the currently installed package version. 1583 * 1584 * @hide 1585 */ setRequiredInstalledVersionCode(long versionCode)1586 public void setRequiredInstalledVersionCode(long versionCode) { 1587 requiredInstalledVersionCode = versionCode; 1588 } 1589 1590 /** {@hide} */ setInstallFlagsForcePermissionPrompt()1591 public void setInstallFlagsForcePermissionPrompt() { 1592 installFlags |= PackageManager.INSTALL_FORCE_PERMISSION_PROMPT; 1593 } 1594 1595 /** {@hide} */ 1596 @SystemApi setDontKillApp(boolean dontKillApp)1597 public void setDontKillApp(boolean dontKillApp) { 1598 if (dontKillApp) { 1599 installFlags |= PackageManager.INSTALL_DONT_KILL_APP; 1600 } else { 1601 installFlags &= ~PackageManager.INSTALL_DONT_KILL_APP; 1602 } 1603 } 1604 1605 /** {@hide} */ 1606 @SystemApi setInstallAsInstantApp(boolean isInstantApp)1607 public void setInstallAsInstantApp(boolean isInstantApp) { 1608 if (isInstantApp) { 1609 installFlags |= PackageManager.INSTALL_INSTANT_APP; 1610 installFlags &= ~PackageManager.INSTALL_FULL_APP; 1611 } else { 1612 installFlags &= ~PackageManager.INSTALL_INSTANT_APP; 1613 installFlags |= PackageManager.INSTALL_FULL_APP; 1614 } 1615 } 1616 1617 /** 1618 * Sets the install as a virtual preload. Will only have effect when called 1619 * by the verifier. 1620 * {@hide} 1621 */ 1622 @SystemApi setInstallAsVirtualPreload()1623 public void setInstallAsVirtualPreload() { 1624 installFlags |= PackageManager.INSTALL_VIRTUAL_PRELOAD; 1625 } 1626 1627 /** 1628 * Set the reason for installing this package. 1629 * <p> 1630 * The install reason should be a pre-defined integer. The behavior is 1631 * undefined if other values are used. 1632 * 1633 * @see PackageManager#INSTALL_REASON_UNKNOWN 1634 * @see PackageManager#INSTALL_REASON_POLICY 1635 * @see PackageManager#INSTALL_REASON_DEVICE_RESTORE 1636 * @see PackageManager#INSTALL_REASON_DEVICE_SETUP 1637 * @see PackageManager#INSTALL_REASON_USER 1638 */ setInstallReason(@nstallReason int installReason)1639 public void setInstallReason(@InstallReason int installReason) { 1640 this.installReason = installReason; 1641 } 1642 1643 /** {@hide} */ 1644 @SystemApi 1645 @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE) setAllocateAggressive(boolean allocateAggressive)1646 public void setAllocateAggressive(boolean allocateAggressive) { 1647 if (allocateAggressive) { 1648 installFlags |= PackageManager.INSTALL_ALLOCATE_AGGRESSIVE; 1649 } else { 1650 installFlags &= ~PackageManager.INSTALL_ALLOCATE_AGGRESSIVE; 1651 } 1652 } 1653 1654 /** 1655 * Set the installer package for the app. 1656 * 1657 * By default this is the app that created the {@link PackageInstaller} object. 1658 * 1659 * @param installerPackageName name of the installer package 1660 * {@hide} 1661 */ setInstallerPackageName(String installerPackageName)1662 public void setInstallerPackageName(String installerPackageName) { 1663 this.installerPackageName = installerPackageName; 1664 } 1665 1666 /** 1667 * Set this session to be the parent of a multi-package install. 1668 * 1669 * A multi-package install session contains no APKs and only references other install 1670 * sessions via ID. When a multi-package session is committed, all of its children 1671 * are committed to the system in an atomic manner. If any children fail to install, 1672 * all of them do, including the multi-package session. 1673 */ setMultiPackage()1674 public void setMultiPackage() { 1675 this.isMultiPackage = true; 1676 } 1677 1678 /** 1679 * Set this session to be staged to be installed at reboot. 1680 * 1681 * Staged sessions are scheduled to be installed at next reboot. Staged sessions can also be 1682 * multi-package. In that case, if any of the children sessions fail to install at reboot, 1683 * all the other children sessions are aborted as well. 1684 * 1685 * <p>If the parent session is staged or has rollback enabled, all children sessions 1686 * must have the same properties. 1687 * 1688 * {@hide} 1689 */ 1690 @SystemApi @TestApi 1691 @RequiresPermission(Manifest.permission.INSTALL_PACKAGES) setStaged()1692 public void setStaged() { 1693 this.isStaged = true; 1694 } 1695 1696 /** 1697 * Set this session to be installing an APEX package. 1698 * 1699 * {@hide} 1700 */ 1701 @SystemApi @TestApi 1702 @RequiresPermission(Manifest.permission.INSTALL_PACKAGES) setInstallAsApex()1703 public void setInstallAsApex() { 1704 installFlags |= PackageManager.INSTALL_APEX; 1705 } 1706 1707 /** @hide */ getEnableRollback()1708 public boolean getEnableRollback() { 1709 return (installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0; 1710 } 1711 1712 /** {@hide} */ dump(IndentingPrintWriter pw)1713 public void dump(IndentingPrintWriter pw) { 1714 pw.printPair("mode", mode); 1715 pw.printHexPair("installFlags", installFlags); 1716 pw.printPair("installLocation", installLocation); 1717 pw.printPair("sizeBytes", sizeBytes); 1718 pw.printPair("appPackageName", appPackageName); 1719 pw.printPair("appIcon", (appIcon != null)); 1720 pw.printPair("appLabel", appLabel); 1721 pw.printPair("originatingUri", originatingUri); 1722 pw.printPair("originatingUid", originatingUid); 1723 pw.printPair("referrerUri", referrerUri); 1724 pw.printPair("abiOverride", abiOverride); 1725 pw.printPair("volumeUuid", volumeUuid); 1726 pw.printPair("grantedRuntimePermissions", grantedRuntimePermissions); 1727 pw.printPair("whitelistedRestrictedPermissions", whitelistedRestrictedPermissions); 1728 pw.printPair("installerPackageName", installerPackageName); 1729 pw.printPair("isMultiPackage", isMultiPackage); 1730 pw.printPair("isStaged", isStaged); 1731 pw.printPair("requiredInstalledVersionCode", requiredInstalledVersionCode); 1732 pw.println(); 1733 } 1734 1735 @Override describeContents()1736 public int describeContents() { 1737 return 0; 1738 } 1739 1740 @Override writeToParcel(Parcel dest, int flags)1741 public void writeToParcel(Parcel dest, int flags) { 1742 dest.writeInt(mode); 1743 dest.writeInt(installFlags); 1744 dest.writeInt(installLocation); 1745 dest.writeInt(installReason); 1746 dest.writeLong(sizeBytes); 1747 dest.writeString(appPackageName); 1748 dest.writeParcelable(appIcon, flags); 1749 dest.writeString(appLabel); 1750 dest.writeParcelable(originatingUri, flags); 1751 dest.writeInt(originatingUid); 1752 dest.writeParcelable(referrerUri, flags); 1753 dest.writeString(abiOverride); 1754 dest.writeString(volumeUuid); 1755 dest.writeStringArray(grantedRuntimePermissions); 1756 dest.writeStringList(whitelistedRestrictedPermissions); 1757 dest.writeString(installerPackageName); 1758 dest.writeBoolean(isMultiPackage); 1759 dest.writeBoolean(isStaged); 1760 dest.writeLong(requiredInstalledVersionCode); 1761 } 1762 1763 public static final Parcelable.Creator<SessionParams> 1764 CREATOR = new Parcelable.Creator<SessionParams>() { 1765 @Override 1766 public SessionParams createFromParcel(Parcel p) { 1767 return new SessionParams(p); 1768 } 1769 1770 @Override 1771 public SessionParams[] newArray(int size) { 1772 return new SessionParams[size]; 1773 } 1774 }; 1775 } 1776 1777 /** 1778 * Details for an active install session. 1779 */ 1780 public static class SessionInfo implements Parcelable { 1781 1782 /** 1783 * A session ID that does not exist or is invalid. 1784 */ 1785 public static final int INVALID_ID = -1; 1786 /** {@hide} */ 1787 private static final int[] NO_SESSIONS = {}; 1788 1789 /** @hide */ 1790 @IntDef(prefix = { "STAGED_SESSION_" }, value = { 1791 STAGED_SESSION_NO_ERROR, 1792 STAGED_SESSION_VERIFICATION_FAILED, 1793 STAGED_SESSION_ACTIVATION_FAILED, 1794 STAGED_SESSION_UNKNOWN}) 1795 @Retention(RetentionPolicy.SOURCE) 1796 public @interface StagedSessionErrorCode{} 1797 /** 1798 * Constant indicating that no error occurred during the preparation or the activation of 1799 * this staged session. 1800 */ 1801 public static final int STAGED_SESSION_NO_ERROR = 0; 1802 1803 /** 1804 * Constant indicating that an error occurred during the verification phase (pre-reboot) of 1805 * this staged session. 1806 */ 1807 public static final int STAGED_SESSION_VERIFICATION_FAILED = 1; 1808 1809 /** 1810 * Constant indicating that an error occurred during the activation phase (post-reboot) of 1811 * this staged session. 1812 */ 1813 public static final int STAGED_SESSION_ACTIVATION_FAILED = 2; 1814 1815 /** 1816 * Constant indicating that an unknown error occurred while processing this staged session. 1817 */ 1818 public static final int STAGED_SESSION_UNKNOWN = 3; 1819 1820 /** {@hide} */ 1821 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 1822 public int sessionId; 1823 /** {@hide} */ 1824 public int userId; 1825 /** {@hide} */ 1826 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 1827 public String installerPackageName; 1828 /** {@hide} */ 1829 @UnsupportedAppUsage 1830 public String resolvedBaseCodePath; 1831 /** {@hide} */ 1832 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 1833 public float progress; 1834 /** {@hide} */ 1835 @UnsupportedAppUsage 1836 public boolean sealed; 1837 /** {@hide} */ 1838 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 1839 public boolean active; 1840 1841 /** {@hide} */ 1842 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 1843 public int mode; 1844 /** {@hide} */ 1845 public @InstallReason int installReason; 1846 /** {@hide} */ 1847 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 1848 public long sizeBytes; 1849 /** {@hide} */ 1850 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 1851 public String appPackageName; 1852 /** {@hide} */ 1853 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 1854 public Bitmap appIcon; 1855 /** {@hide} */ 1856 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 1857 public CharSequence appLabel; 1858 1859 /** {@hide} */ 1860 public int installLocation; 1861 /** {@hide} */ 1862 public Uri originatingUri; 1863 /** {@hide} */ 1864 public int originatingUid; 1865 /** {@hide} */ 1866 public Uri referrerUri; 1867 /** {@hide} */ 1868 public String[] grantedRuntimePermissions; 1869 /** {@hide}*/ 1870 public List<String> whitelistedRestrictedPermissions; 1871 /** {@hide} */ 1872 public int installFlags; 1873 /** {@hide} */ 1874 public boolean isMultiPackage; 1875 /** {@hide} */ 1876 public boolean isStaged; 1877 /** {@hide} */ 1878 public int parentSessionId = INVALID_ID; 1879 /** {@hide} */ 1880 public int[] childSessionIds = NO_SESSIONS; 1881 1882 /** {@hide} */ 1883 public boolean isStagedSessionApplied; 1884 /** {@hide} */ 1885 public boolean isStagedSessionReady; 1886 /** {@hide} */ 1887 public boolean isStagedSessionFailed; 1888 private int mStagedSessionErrorCode; 1889 private String mStagedSessionErrorMessage; 1890 1891 /** {@hide} */ 1892 public boolean isCommitted; 1893 1894 /** {@hide} */ 1895 public long updatedMillis; 1896 1897 /** {@hide} */ 1898 @UnsupportedAppUsage SessionInfo()1899 public SessionInfo() { 1900 } 1901 1902 /** {@hide} */ SessionInfo(Parcel source)1903 public SessionInfo(Parcel source) { 1904 sessionId = source.readInt(); 1905 userId = source.readInt(); 1906 installerPackageName = source.readString(); 1907 resolvedBaseCodePath = source.readString(); 1908 progress = source.readFloat(); 1909 sealed = source.readInt() != 0; 1910 active = source.readInt() != 0; 1911 1912 mode = source.readInt(); 1913 installReason = source.readInt(); 1914 sizeBytes = source.readLong(); 1915 appPackageName = source.readString(); 1916 appIcon = source.readParcelable(null); 1917 appLabel = source.readString(); 1918 1919 installLocation = source.readInt(); 1920 originatingUri = source.readParcelable(null); 1921 originatingUid = source.readInt(); 1922 referrerUri = source.readParcelable(null); 1923 grantedRuntimePermissions = source.readStringArray(); 1924 whitelistedRestrictedPermissions = source.createStringArrayList(); 1925 1926 installFlags = source.readInt(); 1927 isMultiPackage = source.readBoolean(); 1928 isStaged = source.readBoolean(); 1929 parentSessionId = source.readInt(); 1930 childSessionIds = source.createIntArray(); 1931 if (childSessionIds == null) { 1932 childSessionIds = NO_SESSIONS; 1933 } 1934 isStagedSessionApplied = source.readBoolean(); 1935 isStagedSessionReady = source.readBoolean(); 1936 isStagedSessionFailed = source.readBoolean(); 1937 mStagedSessionErrorCode = source.readInt(); 1938 mStagedSessionErrorMessage = source.readString(); 1939 isCommitted = source.readBoolean(); 1940 } 1941 1942 /** 1943 * Return the ID for this session. 1944 */ getSessionId()1945 public int getSessionId() { 1946 return sessionId; 1947 } 1948 1949 /** 1950 * Return the user associated with this session. 1951 */ getUser()1952 public @NonNull UserHandle getUser() { 1953 return new UserHandle(userId); 1954 } 1955 1956 /** 1957 * Return the package name of the app that owns this session. 1958 */ getInstallerPackageName()1959 public @Nullable String getInstallerPackageName() { 1960 return installerPackageName; 1961 } 1962 1963 /** 1964 * Return current overall progress of this session, between 0 and 1. 1965 * <p> 1966 * Note that this progress may not directly correspond to the value 1967 * reported by 1968 * {@link PackageInstaller.Session#setStagingProgress(float)}, as the 1969 * system may carve out a portion of the overall progress to represent 1970 * its own internal installation work. 1971 */ getProgress()1972 public float getProgress() { 1973 return progress; 1974 } 1975 1976 /** 1977 * Return if this session is currently active. 1978 * <p> 1979 * A session is considered active whenever there is ongoing forward 1980 * progress being made, such as the installer holding an open 1981 * {@link Session} instance while streaming data into place, or the 1982 * system optimizing code as the result of 1983 * {@link Session#commit(IntentSender)}. 1984 * <p> 1985 * If the installer closes the {@link Session} without committing, the 1986 * session is considered inactive until the installer opens the session 1987 * again. 1988 */ isActive()1989 public boolean isActive() { 1990 return active; 1991 } 1992 1993 /** 1994 * Return if this session is sealed. 1995 * <p> 1996 * Once sealed, no further changes may be made to the session. A session 1997 * is sealed the moment {@link Session#commit(IntentSender)} is called. 1998 */ isSealed()1999 public boolean isSealed() { 2000 return sealed; 2001 } 2002 2003 /** 2004 * Return the reason for installing this package. 2005 * 2006 * @return The install reason. 2007 */ getInstallReason()2008 public @InstallReason int getInstallReason() { 2009 return installReason; 2010 } 2011 2012 /** {@hide} */ 2013 @Deprecated isOpen()2014 public boolean isOpen() { 2015 return isActive(); 2016 } 2017 2018 /** 2019 * Return the package name this session is working with. May be {@code null} 2020 * if unknown. 2021 */ getAppPackageName()2022 public @Nullable String getAppPackageName() { 2023 return appPackageName; 2024 } 2025 2026 /** 2027 * Return an icon representing the app being installed. May be {@code null} 2028 * if unavailable. 2029 */ getAppIcon()2030 public @Nullable Bitmap getAppIcon() { 2031 if (appIcon == null) { 2032 // Icon may have been omitted for calls that return bulk session 2033 // lists, so try fetching the specific icon. 2034 try { 2035 final SessionInfo info = AppGlobals.getPackageManager().getPackageInstaller() 2036 .getSessionInfo(sessionId); 2037 appIcon = (info != null) ? info.appIcon : null; 2038 } catch (RemoteException e) { 2039 throw e.rethrowFromSystemServer(); 2040 } 2041 } 2042 return appIcon; 2043 } 2044 2045 /** 2046 * Return a label representing the app being installed. May be {@code null} 2047 * if unavailable. 2048 */ getAppLabel()2049 public @Nullable CharSequence getAppLabel() { 2050 return appLabel; 2051 } 2052 2053 /** 2054 * Return an Intent that can be started to view details about this install 2055 * session. This may surface actions such as pause, resume, or cancel. 2056 * <p> 2057 * In some cases, a matching Activity may not exist, so ensure you safeguard 2058 * against this. 2059 * 2060 * @see PackageInstaller#ACTION_SESSION_DETAILS 2061 */ createDetailsIntent()2062 public @Nullable Intent createDetailsIntent() { 2063 final Intent intent = new Intent(PackageInstaller.ACTION_SESSION_DETAILS); 2064 intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId); 2065 intent.setPackage(installerPackageName); 2066 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 2067 return intent; 2068 } 2069 2070 /** 2071 * Get the mode of the session as set in the constructor of the {@link SessionParams}. 2072 * 2073 * @return One of {@link SessionParams#MODE_FULL_INSTALL} 2074 * or {@link SessionParams#MODE_INHERIT_EXISTING} 2075 */ getMode()2076 public int getMode() { 2077 return mode; 2078 } 2079 2080 /** 2081 * Get the value set in {@link SessionParams#setInstallLocation(int)}. 2082 */ getInstallLocation()2083 public int getInstallLocation() { 2084 return installLocation; 2085 } 2086 2087 /** 2088 * Get the value as set in {@link SessionParams#setSize(long)}. 2089 * 2090 * <p>The value is a hint and does not have to match the actual size. 2091 */ getSize()2092 public long getSize() { 2093 return sizeBytes; 2094 } 2095 2096 /** 2097 * Get the value set in {@link SessionParams#setOriginatingUri(Uri)}. 2098 * Note: This value will only be non-null for the owner of the session. 2099 */ getOriginatingUri()2100 public @Nullable Uri getOriginatingUri() { 2101 return originatingUri; 2102 } 2103 2104 /** 2105 * Get the value set in {@link SessionParams#setOriginatingUid(int)}. 2106 */ getOriginatingUid()2107 public int getOriginatingUid() { 2108 return originatingUid; 2109 } 2110 2111 /** 2112 * Get the value set in {@link SessionParams#setReferrerUri(Uri)} 2113 * Note: This value will only be non-null for the owner of the session. 2114 */ getReferrerUri()2115 public @Nullable Uri getReferrerUri() { 2116 return referrerUri; 2117 } 2118 2119 /** 2120 * Get the value set in {@link SessionParams#setGrantedRuntimePermissions(String[])}. 2121 * 2122 * @hide 2123 */ 2124 @SystemApi getGrantedRuntimePermissions()2125 public @Nullable String[] getGrantedRuntimePermissions() { 2126 return grantedRuntimePermissions; 2127 } 2128 2129 /** 2130 * Get the value set in {@link SessionParams#setWhitelistedRestrictedPermissions(Set)}. 2131 * Note that if all permissions are whitelisted this method returns {@link 2132 * SessionParams#RESTRICTED_PERMISSIONS_ALL}. 2133 * 2134 * @hide 2135 */ 2136 @TestApi 2137 @SystemApi getWhitelistedRestrictedPermissions()2138 public @NonNull Set<String> getWhitelistedRestrictedPermissions() { 2139 if ((installFlags & PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS) != 0) { 2140 return SessionParams.RESTRICTED_PERMISSIONS_ALL; 2141 } 2142 if (whitelistedRestrictedPermissions != null) { 2143 return new ArraySet<>(whitelistedRestrictedPermissions); 2144 } 2145 return Collections.emptySet(); 2146 } 2147 2148 /** 2149 * Get the value set in {@link SessionParams#setAllowDowngrade(boolean)}. 2150 * 2151 * @deprecated use {@link #getRequestDowngrade()}. 2152 * @hide 2153 */ 2154 @SystemApi 2155 @Deprecated getAllowDowngrade()2156 public boolean getAllowDowngrade() { 2157 return getRequestDowngrade(); 2158 } 2159 2160 /** 2161 * Get the value set in {@link SessionParams#setRequestDowngrade(boolean)}. 2162 * 2163 * @hide 2164 */ 2165 @SystemApi getRequestDowngrade()2166 public boolean getRequestDowngrade() { 2167 return (installFlags & PackageManager.INSTALL_REQUEST_DOWNGRADE) != 0; 2168 } 2169 2170 /** 2171 * Get the value set in {@link SessionParams#setDontKillApp(boolean)}. 2172 * 2173 * @hide 2174 */ 2175 @SystemApi getDontKillApp()2176 public boolean getDontKillApp() { 2177 return (installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0; 2178 } 2179 2180 /** 2181 * If {@link SessionParams#setInstallAsInstantApp(boolean)} was called with {@code true}, 2182 * return true. If it was called with {@code false} or if it was not called return false. 2183 * 2184 * @hide 2185 * 2186 * @see #getInstallAsFullApp 2187 */ 2188 @SystemApi getInstallAsInstantApp(boolean isInstantApp)2189 public boolean getInstallAsInstantApp(boolean isInstantApp) { 2190 return (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0; 2191 } 2192 2193 /** 2194 * If {@link SessionParams#setInstallAsInstantApp(boolean)} was called with {@code false}, 2195 * return true. If it was called with {@code true} or if it was not called return false. 2196 * 2197 * @hide 2198 * 2199 * @see #getInstallAsInstantApp 2200 */ 2201 @SystemApi getInstallAsFullApp(boolean isInstantApp)2202 public boolean getInstallAsFullApp(boolean isInstantApp) { 2203 return (installFlags & PackageManager.INSTALL_FULL_APP) != 0; 2204 } 2205 2206 /** 2207 * Get if {@link SessionParams#setInstallAsVirtualPreload()} was called. 2208 * 2209 * @hide 2210 */ 2211 @SystemApi getInstallAsVirtualPreload()2212 public boolean getInstallAsVirtualPreload() { 2213 return (installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0; 2214 } 2215 2216 /** 2217 * Return whether rollback is enabled or disabled for the given upgrade. 2218 * 2219 * @hide 2220 */ 2221 @SystemApi getEnableRollback()2222 public boolean getEnableRollback() { 2223 return (installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0; 2224 } 2225 2226 /** 2227 * Get the value set in {@link SessionParams#setAllocateAggressive(boolean)}. 2228 * 2229 * @hide 2230 */ 2231 @SystemApi getAllocateAggressive()2232 public boolean getAllocateAggressive() { 2233 return (installFlags & PackageManager.INSTALL_ALLOCATE_AGGRESSIVE) != 0; 2234 } 2235 2236 2237 /** {@hide} */ 2238 @Deprecated getDetailsIntent()2239 public @Nullable Intent getDetailsIntent() { 2240 return createDetailsIntent(); 2241 } 2242 2243 /** 2244 * Returns true if this session is a multi-package session containing references to other 2245 * sessions. 2246 */ isMultiPackage()2247 public boolean isMultiPackage() { 2248 return isMultiPackage; 2249 } 2250 2251 /** 2252 * Returns true if this session is a staged session which will be applied at next reboot. 2253 */ isStaged()2254 public boolean isStaged() { 2255 return isStaged; 2256 } 2257 2258 /** 2259 * Returns the parent multi-package session ID if this session belongs to one, 2260 * {@link #INVALID_ID} otherwise. 2261 */ getParentSessionId()2262 public int getParentSessionId() { 2263 return parentSessionId; 2264 } 2265 2266 /** 2267 * Returns the set of session IDs that will be committed when this session is commited if 2268 * this session is a multi-package session. 2269 */ 2270 @NonNull getChildSessionIds()2271 public int[] getChildSessionIds() { 2272 return childSessionIds; 2273 } 2274 checkSessionIsStaged()2275 private void checkSessionIsStaged() { 2276 if (!isStaged) { 2277 throw new IllegalStateException("Session is not marked as staged."); 2278 } 2279 } 2280 2281 /** 2282 * Whether the staged session has been applied successfully, meaning that all of its 2283 * packages have been activated and no further action is required. 2284 * Only meaningful if {@code isStaged} is true. 2285 */ isStagedSessionApplied()2286 public boolean isStagedSessionApplied() { 2287 checkSessionIsStaged(); 2288 return isStagedSessionApplied; 2289 } 2290 2291 /** 2292 * Whether the staged session is ready to be applied at next reboot. Only meaningful if 2293 * {@code isStaged} is true. 2294 */ isStagedSessionReady()2295 public boolean isStagedSessionReady() { 2296 checkSessionIsStaged(); 2297 return isStagedSessionReady; 2298 } 2299 2300 /** 2301 * Whether something went wrong and the staged session is declared as failed, meaning that 2302 * it will be ignored at next reboot. Only meaningful if {@code isStaged} is true. 2303 */ isStagedSessionFailed()2304 public boolean isStagedSessionFailed() { 2305 checkSessionIsStaged(); 2306 return isStagedSessionFailed; 2307 } 2308 2309 /** 2310 * If something went wrong with a staged session, clients can check this error code to 2311 * understand which kind of failure happened. Only meaningful if {@code isStaged} is true. 2312 */ getStagedSessionErrorCode()2313 public @StagedSessionErrorCode int getStagedSessionErrorCode() { 2314 checkSessionIsStaged(); 2315 return mStagedSessionErrorCode; 2316 } 2317 2318 /** 2319 * Text description of the error code returned by {@code getStagedSessionErrorCode}, or 2320 * empty string if no error was encountered. 2321 */ getStagedSessionErrorMessage()2322 public @NonNull String getStagedSessionErrorMessage() { 2323 checkSessionIsStaged(); 2324 return mStagedSessionErrorMessage; 2325 } 2326 2327 /** {@hide} */ setStagedSessionErrorCode(@tagedSessionErrorCode int errorCode, String errorMessage)2328 public void setStagedSessionErrorCode(@StagedSessionErrorCode int errorCode, 2329 String errorMessage) { 2330 mStagedSessionErrorCode = errorCode; 2331 mStagedSessionErrorMessage = errorMessage; 2332 } 2333 2334 /** 2335 * Returns {@code true} if {@link Session#commit(IntentSender)}} was called for this 2336 * session. 2337 */ isCommitted()2338 public boolean isCommitted() { 2339 return isCommitted; 2340 } 2341 2342 /** 2343 * The timestamp of the last update that occurred to the session, including changing of 2344 * states in case of staged sessions. 2345 */ 2346 @CurrentTimeMillisLong getUpdatedMillis()2347 public long getUpdatedMillis() { 2348 return updatedMillis; 2349 } 2350 2351 @Override describeContents()2352 public int describeContents() { 2353 return 0; 2354 } 2355 2356 @Override writeToParcel(Parcel dest, int flags)2357 public void writeToParcel(Parcel dest, int flags) { 2358 dest.writeInt(sessionId); 2359 dest.writeInt(userId); 2360 dest.writeString(installerPackageName); 2361 dest.writeString(resolvedBaseCodePath); 2362 dest.writeFloat(progress); 2363 dest.writeInt(sealed ? 1 : 0); 2364 dest.writeInt(active ? 1 : 0); 2365 2366 dest.writeInt(mode); 2367 dest.writeInt(installReason); 2368 dest.writeLong(sizeBytes); 2369 dest.writeString(appPackageName); 2370 dest.writeParcelable(appIcon, flags); 2371 dest.writeString(appLabel != null ? appLabel.toString() : null); 2372 2373 dest.writeInt(installLocation); 2374 dest.writeParcelable(originatingUri, flags); 2375 dest.writeInt(originatingUid); 2376 dest.writeParcelable(referrerUri, flags); 2377 dest.writeStringArray(grantedRuntimePermissions); 2378 dest.writeStringList(whitelistedRestrictedPermissions); 2379 dest.writeInt(installFlags); 2380 dest.writeBoolean(isMultiPackage); 2381 dest.writeBoolean(isStaged); 2382 dest.writeInt(parentSessionId); 2383 dest.writeIntArray(childSessionIds); 2384 dest.writeBoolean(isStagedSessionApplied); 2385 dest.writeBoolean(isStagedSessionReady); 2386 dest.writeBoolean(isStagedSessionFailed); 2387 dest.writeInt(mStagedSessionErrorCode); 2388 dest.writeString(mStagedSessionErrorMessage); 2389 dest.writeBoolean(isCommitted); 2390 } 2391 2392 public static final Parcelable.Creator<SessionInfo> 2393 CREATOR = new Parcelable.Creator<SessionInfo>() { 2394 @Override 2395 public SessionInfo createFromParcel(Parcel p) { 2396 return new SessionInfo(p); 2397 } 2398 2399 @Override 2400 public SessionInfo[] newArray(int size) { 2401 return new SessionInfo[size]; 2402 } 2403 }; 2404 } 2405 } 2406