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