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 static android.app.AppOpsManager.MODE_ALLOWED; 20 import static android.app.AppOpsManager.MODE_DEFAULT; 21 import static android.app.AppOpsManager.MODE_IGNORED; 22 import static android.content.pm.Checksum.TYPE_PARTIAL_MERKLE_ROOT_1M_SHA256; 23 import static android.content.pm.Checksum.TYPE_PARTIAL_MERKLE_ROOT_1M_SHA512; 24 import static android.content.pm.Checksum.TYPE_WHOLE_MD5; 25 import static android.content.pm.Checksum.TYPE_WHOLE_MERKLE_ROOT_4K_SHA256; 26 import static android.content.pm.Checksum.TYPE_WHOLE_SHA1; 27 import static android.content.pm.Checksum.TYPE_WHOLE_SHA256; 28 import static android.content.pm.Checksum.TYPE_WHOLE_SHA512; 29 import static android.content.pm.PackageInfo.INSTALL_LOCATION_AUTO; 30 import static android.content.pm.PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY; 31 import static android.content.pm.PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL; 32 33 import android.Manifest; 34 import android.annotation.CallbackExecutor; 35 import android.annotation.CurrentTimeMillisLong; 36 import android.annotation.DurationMillisLong; 37 import android.annotation.IntDef; 38 import android.annotation.NonNull; 39 import android.annotation.Nullable; 40 import android.annotation.RequiresPermission; 41 import android.annotation.SdkConstant; 42 import android.annotation.SdkConstant.SdkConstantType; 43 import android.annotation.SuppressLint; 44 import android.annotation.SystemApi; 45 import android.annotation.TestApi; 46 import android.app.ActivityManager; 47 import android.app.ActivityThread; 48 import android.app.AppGlobals; 49 import android.compat.annotation.UnsupportedAppUsage; 50 import android.content.IIntentReceiver; 51 import android.content.IIntentSender; 52 import android.content.Intent; 53 import android.content.IntentSender; 54 import android.content.pm.PackageManager.DeleteFlags; 55 import android.content.pm.PackageManager.InstallReason; 56 import android.content.pm.PackageManager.InstallScenario; 57 import android.content.pm.parsing.ApkLiteParseUtils; 58 import android.content.pm.parsing.PackageLite; 59 import android.content.pm.parsing.result.ParseResult; 60 import android.content.pm.parsing.result.ParseTypeImpl; 61 import android.graphics.Bitmap; 62 import android.icu.util.ULocale; 63 import android.net.Uri; 64 import android.os.Build; 65 import android.os.Bundle; 66 import android.os.FileBridge; 67 import android.os.Handler; 68 import android.os.HandlerExecutor; 69 import android.os.IBinder; 70 import android.os.Parcel; 71 import android.os.ParcelFileDescriptor; 72 import android.os.Parcelable; 73 import android.os.ParcelableException; 74 import android.os.PersistableBundle; 75 import android.os.RemoteCallback; 76 import android.os.RemoteException; 77 import android.os.SystemProperties; 78 import android.os.UserHandle; 79 import android.system.ErrnoException; 80 import android.system.Os; 81 import android.text.TextUtils; 82 import android.util.ArrayMap; 83 import android.util.ArraySet; 84 import android.util.ExceptionUtils; 85 86 import com.android.internal.content.InstallLocationUtils; 87 import com.android.internal.util.ArrayUtils; 88 import com.android.internal.util.DataClass; 89 import com.android.internal.util.IndentingPrintWriter; 90 import com.android.internal.util.Preconditions; 91 import com.android.internal.util.function.pooled.PooledLambda; 92 93 import java.io.Closeable; 94 import java.io.File; 95 import java.io.FileNotFoundException; 96 import java.io.IOException; 97 import java.io.InputStream; 98 import java.io.OutputStream; 99 import java.lang.annotation.Retention; 100 import java.lang.annotation.RetentionPolicy; 101 import java.security.MessageDigest; 102 import java.security.cert.Certificate; 103 import java.security.cert.CertificateEncodingException; 104 import java.security.cert.X509Certificate; 105 import java.util.ArrayList; 106 import java.util.Collection; 107 import java.util.Collections; 108 import java.util.Iterator; 109 import java.util.List; 110 import java.util.Objects; 111 import java.util.Set; 112 import java.util.concurrent.Executor; 113 import java.util.function.Consumer; 114 115 /** 116 * Offers the ability to install, upgrade, and remove applications on the 117 * device. This includes support for apps packaged either as a single 118 * "monolithic" APK, or apps packaged as multiple "split" APKs. 119 * <p> 120 * An app is delivered for installation through a 121 * {@link PackageInstaller.Session}, which any app can create. Once the session 122 * is created, the installer can stream one or more APKs into place until it 123 * decides to either commit or destroy the session. Committing may require user 124 * intervention to complete the installation, unless the caller falls into one of the 125 * following categories, in which case the installation will complete automatically. 126 * <ul> 127 * <li>the device owner 128 * <li>the affiliated profile owner 129 * </ul> 130 * <p> 131 * Sessions can install brand new apps, upgrade existing apps, or add new splits 132 * into an existing app. 133 * <p> 134 * Apps packaged as multiple split APKs always consist of a single "base" APK 135 * (with a {@code null} split name) and zero or more "split" APKs (with unique 136 * split names). Any subset of these APKs can be installed together, as long as 137 * the following constraints are met: 138 * <ul> 139 * <li>All APKs must have the exact same package name, version code, and signing 140 * certificates. 141 * <li>All APKs must have unique split names. 142 * <li>All installations must contain a single base APK. 143 * </ul> 144 * <p> 145 * The ApiDemos project contains examples of using this API: 146 * <code>ApiDemos/src/com/example/android/apis/content/InstallApk*.java</code>. 147 */ 148 public class PackageInstaller { 149 private static final String TAG = "PackageInstaller"; 150 151 /** {@hide} */ 152 public static final boolean ENABLE_REVOCABLE_FD = 153 SystemProperties.getBoolean("fw.revocable_fd", false); 154 155 /** 156 * Activity Action: Show details about a particular install session. This 157 * may surface actions such as pause, resume, or cancel. 158 * <p> 159 * This should always be scoped to the installer package that owns the 160 * session. Clients should use {@link SessionInfo#createDetailsIntent()} to 161 * build this intent correctly. 162 * <p> 163 * In some cases, a matching Activity may not exist, so ensure you safeguard 164 * against this. 165 * <p> 166 * The session to show details for is defined in {@link #EXTRA_SESSION_ID}. 167 */ 168 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 169 public static final String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS"; 170 171 /** 172 * Broadcast Action: Explicit broadcast sent to the last known default launcher when a session 173 * for a new install is committed. For managed profile, this is sent to the default launcher 174 * of the primary profile. 175 * <p> 176 * The associated session is defined in {@link #EXTRA_SESSION} and the user for which this 177 * session was created in {@link Intent#EXTRA_USER}. 178 */ 179 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 180 public static final String ACTION_SESSION_COMMITTED = 181 "android.content.pm.action.SESSION_COMMITTED"; 182 183 /** 184 * Broadcast Action: Send information about a staged install session when its state is updated. 185 * <p> 186 * The associated session information is defined in {@link #EXTRA_SESSION}. 187 */ 188 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 189 public static final String ACTION_SESSION_UPDATED = 190 "android.content.pm.action.SESSION_UPDATED"; 191 192 /** 193 * Intent action to indicate that user action is required for current install. This action can 194 * be used only by system apps. 195 * 196 * @hide 197 */ 198 @SystemApi 199 public static final String ACTION_CONFIRM_INSTALL = "android.content.pm.action.CONFIRM_INSTALL"; 200 201 /** 202 * Activity Action: Intent sent to the installer when a session for requesting 203 * user pre-approval, and user needs to confirm the installation. 204 * 205 * @hide 206 */ 207 @SystemApi 208 public static final String ACTION_CONFIRM_PRE_APPROVAL = 209 "android.content.pm.action.CONFIRM_PRE_APPROVAL"; 210 211 /** 212 * An integer session ID that an operation is working with. 213 * 214 * @see Intent#getIntExtra(String, int) 215 */ 216 public static final String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID"; 217 218 /** 219 * {@link SessionInfo} that an operation is working with. 220 * 221 * @see Intent#getParcelableExtra(String) 222 */ 223 public static final String EXTRA_SESSION = "android.content.pm.extra.SESSION"; 224 225 /** 226 * Package name that an operation is working with. 227 * 228 * @see Intent#getStringExtra(String) 229 */ 230 public static final String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME"; 231 232 /** 233 * Current status of an operation. Will be one of 234 * {@link #STATUS_PENDING_USER_ACTION}, {@link #STATUS_SUCCESS}, 235 * {@link #STATUS_FAILURE}, {@link #STATUS_FAILURE_ABORTED}, 236 * {@link #STATUS_FAILURE_BLOCKED}, {@link #STATUS_FAILURE_CONFLICT}, 237 * {@link #STATUS_FAILURE_INCOMPATIBLE}, {@link #STATUS_FAILURE_INVALID}, 238 * {@link #STATUS_FAILURE_STORAGE}, or {@link #STATUS_FAILURE_TIMEOUT}. 239 * <p> 240 * More information about a status may be available through additional 241 * extras; see the individual status documentation for details. 242 * 243 * @see Intent#getIntExtra(String, int) 244 */ 245 public static final String EXTRA_STATUS = "android.content.pm.extra.STATUS"; 246 247 /** 248 * Indicate if the status is for a pre-approval request. 249 * 250 * If callers use the same {@link IntentSender} for both 251 * {@link Session#requestUserPreapproval(PreapprovalDetails, IntentSender)} and 252 * {@link Session#commit(IntentSender)}, they can use this to differentiate between them. 253 * 254 * @see Intent#getBooleanExtra(String, boolean) 255 */ 256 public static final String EXTRA_PRE_APPROVAL = "android.content.pm.extra.PRE_APPROVAL"; 257 258 /** 259 * Detailed string representation of the status, including raw details that 260 * are useful for debugging. 261 * 262 * @see Intent#getStringExtra(String) 263 */ 264 public static final String EXTRA_STATUS_MESSAGE = "android.content.pm.extra.STATUS_MESSAGE"; 265 266 /** 267 * Another package name relevant to a status. This is typically the package 268 * responsible for causing an operation failure. 269 * 270 * @see Intent#getStringExtra(String) 271 */ 272 public static final String 273 EXTRA_OTHER_PACKAGE_NAME = "android.content.pm.extra.OTHER_PACKAGE_NAME"; 274 275 /** 276 * Storage path relevant to a status. 277 * 278 * @see Intent#getStringExtra(String) 279 */ 280 public static final String EXTRA_STORAGE_PATH = "android.content.pm.extra.STORAGE_PATH"; 281 282 /** 283 * The {@link InstallConstraints} object. 284 * 285 * @see Intent#getParcelableExtra(String, Class) 286 * @see #waitForInstallConstraints(List, InstallConstraints, IntentSender, long) 287 */ 288 public static final String EXTRA_INSTALL_CONSTRAINTS = 289 "android.content.pm.extra.INSTALL_CONSTRAINTS"; 290 291 /** 292 * The {@link InstallConstraintsResult} object. 293 * 294 * @see Intent#getParcelableExtra(String, Class) 295 * @see #waitForInstallConstraints(List, InstallConstraints, IntentSender, long) 296 */ 297 public static final String EXTRA_INSTALL_CONSTRAINTS_RESULT = 298 "android.content.pm.extra.INSTALL_CONSTRAINTS_RESULT"; 299 300 /** {@hide} */ 301 @Deprecated 302 public static final String EXTRA_PACKAGE_NAMES = "android.content.pm.extra.PACKAGE_NAMES"; 303 304 /** 305 * The status as used internally in the package manager. Refer to {@link PackageManager} for 306 * a list of all valid legacy statuses. 307 * 308 * @hide 309 */ 310 @SystemApi 311 public static final String EXTRA_LEGACY_STATUS = "android.content.pm.extra.LEGACY_STATUS"; 312 /** {@hide} */ 313 public static final String EXTRA_LEGACY_BUNDLE = "android.content.pm.extra.LEGACY_BUNDLE"; 314 /** 315 * The callback to execute once an uninstall is completed (used for both successful and 316 * unsuccessful uninstalls). 317 * 318 * @hide 319 */ 320 @SystemApi 321 public static final String EXTRA_CALLBACK = "android.content.pm.extra.CALLBACK"; 322 323 /** 324 * Type of DataLoader for this session. Will be one of 325 * {@link #DATA_LOADER_TYPE_NONE}, {@link #DATA_LOADER_TYPE_STREAMING}, 326 * {@link #DATA_LOADER_TYPE_INCREMENTAL}. 327 * <p> 328 * See the individual types documentation for details. 329 * 330 * @see Intent#getIntExtra(String, int) 331 * {@hide} 332 */ 333 @SystemApi 334 public static final String EXTRA_DATA_LOADER_TYPE = "android.content.pm.extra.DATA_LOADER_TYPE"; 335 336 /** 337 * Path to the validated base APK for this session, which may point at an 338 * APK inside the session (when the session defines the base), or it may 339 * point at the existing base APK (when adding splits to an existing app). 340 * 341 * @hide 342 */ 343 @SystemApi 344 public static final String EXTRA_RESOLVED_BASE_PATH = 345 "android.content.pm.extra.RESOLVED_BASE_PATH"; 346 347 /** 348 * Streaming installation pending. 349 * Caller should make sure DataLoader is able to prepare image and reinitiate the operation. 350 * 351 * @see #EXTRA_SESSION_ID 352 * {@hide} 353 */ 354 public static final int STATUS_PENDING_STREAMING = -2; 355 356 /** 357 * User action is currently required to proceed. You can launch the intent 358 * activity described by {@link Intent#EXTRA_INTENT} to involve the user and 359 * continue. 360 * <p> 361 * You may choose to immediately launch the intent if the user is actively 362 * using your app. Otherwise, you should use a notification to guide the 363 * user back into your app before launching. 364 * 365 * @see Intent#getParcelableExtra(String) 366 */ 367 public static final int STATUS_PENDING_USER_ACTION = -1; 368 369 /** 370 * The operation succeeded. 371 */ 372 public static final int STATUS_SUCCESS = 0; 373 374 /** 375 * The operation failed in a generic way. The system will always try to 376 * provide a more specific failure reason, but in some rare cases this may 377 * be delivered. 378 * 379 * @see #EXTRA_STATUS_MESSAGE 380 */ 381 public static final int STATUS_FAILURE = 1; 382 383 /** 384 * The operation failed because it was blocked. For example, a device policy 385 * may be blocking the operation, a package verifier may have blocked the 386 * operation, or the app may be required for core system operation. 387 * <p> 388 * The result may also contain {@link #EXTRA_OTHER_PACKAGE_NAME} with the 389 * specific package blocking the install. 390 * 391 * @see #EXTRA_STATUS_MESSAGE 392 * @see #EXTRA_OTHER_PACKAGE_NAME 393 */ 394 public static final int STATUS_FAILURE_BLOCKED = 2; 395 396 /** 397 * The operation failed because it was actively aborted. For example, the 398 * user actively declined requested permissions, or the session was 399 * abandoned. 400 * 401 * @see #EXTRA_STATUS_MESSAGE 402 */ 403 public static final int STATUS_FAILURE_ABORTED = 3; 404 405 /** 406 * The operation failed because one or more of the APKs was invalid. For 407 * example, they might be malformed, corrupt, incorrectly signed, 408 * mismatched, etc. 409 * 410 * @see #EXTRA_STATUS_MESSAGE 411 */ 412 public static final int STATUS_FAILURE_INVALID = 4; 413 414 /** 415 * The operation failed because it conflicts (or is inconsistent with) with 416 * another package already installed on the device. For example, an existing 417 * permission, incompatible certificates, etc. The user may be able to 418 * uninstall another app to fix the issue. 419 * <p> 420 * The result may also contain {@link #EXTRA_OTHER_PACKAGE_NAME} with the 421 * specific package identified as the cause of the conflict. 422 * 423 * @see #EXTRA_STATUS_MESSAGE 424 * @see #EXTRA_OTHER_PACKAGE_NAME 425 */ 426 public static final int STATUS_FAILURE_CONFLICT = 5; 427 428 /** 429 * The operation failed because of storage issues. For example, the device 430 * may be running low on space, or external media may be unavailable. The 431 * user may be able to help free space or insert different external media. 432 * <p> 433 * The result may also contain {@link #EXTRA_STORAGE_PATH} with the path to 434 * the storage device that caused the failure. 435 * 436 * @see #EXTRA_STATUS_MESSAGE 437 * @see #EXTRA_STORAGE_PATH 438 */ 439 public static final int STATUS_FAILURE_STORAGE = 6; 440 441 /** 442 * The operation failed because it is fundamentally incompatible with this 443 * device. For example, the app may require a hardware feature that doesn't 444 * exist, it may be missing native code for the ABIs supported by the 445 * device, or it requires a newer SDK version, etc. 446 * 447 * Starting in {@link Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, an app with only 32-bit native 448 * code can still be installed on a device that supports both 64-bit and 32-bit ABIs. 449 * However, a warning dialog will be displayed when the app is launched. 450 * 451 * @see #EXTRA_STATUS_MESSAGE 452 */ 453 public static final int STATUS_FAILURE_INCOMPATIBLE = 7; 454 455 /** 456 * The operation failed because it didn't complete within the specified timeout. 457 * 458 * @see #EXTRA_STATUS_MESSAGE 459 */ 460 public static final int STATUS_FAILURE_TIMEOUT = 8; 461 462 /** 463 * Default value, non-streaming installation session. 464 * 465 * @see #EXTRA_DATA_LOADER_TYPE 466 * {@hide} 467 */ 468 @SystemApi 469 public static final int DATA_LOADER_TYPE_NONE = DataLoaderType.NONE; 470 471 /** 472 * Streaming installation using data loader. 473 * 474 * @see #EXTRA_DATA_LOADER_TYPE 475 * {@hide} 476 */ 477 @SystemApi 478 public static final int DATA_LOADER_TYPE_STREAMING = DataLoaderType.STREAMING; 479 480 /** 481 * Streaming installation using Incremental FileSystem. 482 * 483 * @see #EXTRA_DATA_LOADER_TYPE 484 * {@hide} 485 */ 486 @SystemApi 487 public static final int DATA_LOADER_TYPE_INCREMENTAL = DataLoaderType.INCREMENTAL; 488 489 /** 490 * Target location for the file in installation session is /data/app/<packageName>-<id>. 491 * This is the intended location for APKs. 492 * Requires permission to install packages. 493 * {@hide} 494 */ 495 @SystemApi 496 public static final int LOCATION_DATA_APP = InstallationFileLocation.DATA_APP; 497 498 /** 499 * Target location for the file in installation session is 500 * /data/media/<userid>/Android/obb/<packageName>. This is the intended location for OBBs. 501 * {@hide} 502 */ 503 @SystemApi 504 public static final int LOCATION_MEDIA_OBB = InstallationFileLocation.MEDIA_OBB; 505 506 /** 507 * Target location for the file in installation session is 508 * /data/media/<userid>/Android/data/<packageName>. 509 * This is the intended location for application data. 510 * Can only be used by an app itself running under specific user. 511 * {@hide} 512 */ 513 @SystemApi 514 public static final int LOCATION_MEDIA_DATA = InstallationFileLocation.MEDIA_DATA; 515 516 /** @hide */ 517 @IntDef(prefix = { "LOCATION_" }, value = { 518 LOCATION_DATA_APP, 519 LOCATION_MEDIA_OBB, 520 LOCATION_MEDIA_DATA}) 521 @Retention(RetentionPolicy.SOURCE) 522 public @interface FileLocation{} 523 524 /** 525 * The installer did not call {@link PackageInstaller.SessionParams#setPackageSource(int)} to 526 * specify the package source. 527 */ 528 public static final int PACKAGE_SOURCE_UNSPECIFIED = 0; 529 530 /** 531 * Code indicating that the package being installed is from a source not reflected by any 532 * other package source constant. 533 */ 534 public static final int PACKAGE_SOURCE_OTHER = 1; 535 536 /** 537 * Code indicating that the package being installed is from a store. An app store that 538 * installs an app for the user would use this. 539 */ 540 public static final int PACKAGE_SOURCE_STORE = 2; 541 542 /** 543 * Code indicating that the package being installed comes from a local file on the device. A 544 * file manager that is facilitating the installation of an APK file would use this. 545 */ 546 public static final int PACKAGE_SOURCE_LOCAL_FILE = 3; 547 548 /** 549 * Code indicating that the package being installed comes from a file that was downloaded to 550 * the device by the user. For use in place of {@link #PACKAGE_SOURCE_LOCAL_FILE} when the 551 * installer knows the package was downloaded. 552 */ 553 public static final int PACKAGE_SOURCE_DOWNLOADED_FILE = 4; 554 555 /** @hide */ 556 @IntDef(prefix = { "PACKAGE_SOURCE_" }, value = { 557 PACKAGE_SOURCE_UNSPECIFIED, 558 PACKAGE_SOURCE_STORE, 559 PACKAGE_SOURCE_LOCAL_FILE, 560 PACKAGE_SOURCE_DOWNLOADED_FILE, 561 PACKAGE_SOURCE_OTHER 562 }) 563 @Retention(RetentionPolicy.SOURCE) 564 @interface PackageSourceType{} 565 566 /** 567 * Indicate the user intervention is required when the installer attempts to commit the session. 568 * This is the default case. 569 * 570 * @hide 571 */ 572 @SystemApi 573 public static final int REASON_CONFIRM_PACKAGE_CHANGE = 0; 574 575 /** 576 * Indicate the user intervention is required because the update ownership enforcement is 577 * enabled, and the update owner will change. 578 * 579 * @see PackageInstaller.SessionParams#setRequestUpdateOwnership 580 * @see InstallSourceInfo#getUpdateOwnerPackageName 581 * @hide 582 */ 583 @SystemApi 584 public static final int REASON_OWNERSHIP_CHANGED = 1; 585 586 /** 587 * Indicate the user intervention is required because the update ownership enforcement is 588 * enabled, and remind the update owner is a different package. 589 * 590 * @see PackageInstaller.SessionParams#setRequestUpdateOwnership 591 * @see InstallSourceInfo#getUpdateOwnerPackageName 592 * @hide 593 */ 594 @SystemApi 595 public static final int REASON_REMIND_OWNERSHIP = 2; 596 597 /** @hide */ 598 @IntDef(prefix = { "REASON_" }, value = { 599 REASON_CONFIRM_PACKAGE_CHANGE, 600 REASON_OWNERSHIP_CHANGED, 601 REASON_REMIND_OWNERSHIP, 602 }) 603 @Retention(RetentionPolicy.SOURCE) 604 public @interface UserActionReason {} 605 606 /** Default set of checksums - includes all available checksums. 607 * @see Session#requestChecksums */ 608 private static final int DEFAULT_CHECKSUMS = 609 TYPE_WHOLE_MERKLE_ROOT_4K_SHA256 | TYPE_WHOLE_MD5 | TYPE_WHOLE_SHA1 | TYPE_WHOLE_SHA256 610 | TYPE_WHOLE_SHA512 | TYPE_PARTIAL_MERKLE_ROOT_1M_SHA256 611 | TYPE_PARTIAL_MERKLE_ROOT_1M_SHA512; 612 613 private final IPackageInstaller mInstaller; 614 private final int mUserId; 615 private final String mInstallerPackageName; 616 private final String mAttributionTag; 617 618 private final ArrayList<SessionCallbackDelegate> mDelegates = new ArrayList<>(); 619 620 /** {@hide} */ PackageInstaller(IPackageInstaller installer, String installerPackageName, String installerAttributionTag, int userId)621 public PackageInstaller(IPackageInstaller installer, 622 String installerPackageName, String installerAttributionTag, int userId) { 623 Objects.requireNonNull(installer, "installer cannot be null"); 624 mInstaller = installer; 625 mInstallerPackageName = installerPackageName; 626 mAttributionTag = installerAttributionTag; 627 mUserId = userId; 628 } 629 630 /** 631 * Create a new session using the given parameters, returning a unique ID 632 * that represents the session. Once created, the session can be opened 633 * multiple times across multiple device boots. 634 * <p> 635 * The system may automatically destroy sessions that have not been 636 * finalized (either committed or abandoned) within a reasonable period of 637 * time, typically on the order of a day. 638 * 639 * @throws IOException if parameters were unsatisfiable, such as lack of 640 * disk space or unavailable media. 641 * @throws SecurityException when installation services are unavailable, 642 * such as when called from a restricted user. 643 * @throws IllegalArgumentException when {@link SessionParams} is invalid. 644 * @return positive, non-zero unique ID that represents the created session. 645 * This ID remains consistent across device reboots until the 646 * session is finalized. IDs are not reused during a given boot. 647 */ createSession(@onNull SessionParams params)648 public int createSession(@NonNull SessionParams params) throws IOException { 649 try { 650 return mInstaller.createSession(params, mInstallerPackageName, mAttributionTag, 651 mUserId); 652 } catch (RuntimeException e) { 653 ExceptionUtils.maybeUnwrapIOException(e); 654 throw e; 655 } catch (RemoteException e) { 656 throw e.rethrowFromSystemServer(); 657 } 658 } 659 660 /** 661 * Open an existing session to actively perform work. To succeed, the caller 662 * must be the owner of the install session. 663 * 664 * @throws IOException if parameters were unsatisfiable, such as lack of 665 * disk space or unavailable media. 666 * @throws SecurityException when the caller does not own the session, or 667 * the session is invalid. 668 */ openSession(int sessionId)669 public @NonNull Session openSession(int sessionId) throws IOException { 670 try { 671 try { 672 return new Session(mInstaller.openSession(sessionId)); 673 } catch (RemoteException e) { 674 throw e.rethrowFromSystemServer(); 675 } 676 } catch (RuntimeException e) { 677 ExceptionUtils.maybeUnwrapIOException(e); 678 throw e; 679 } 680 } 681 682 /** 683 * Update the icon representing the app being installed in a specific 684 * session. This should be roughly 685 * {@link ActivityManager#getLauncherLargeIconSize()} in both dimensions. 686 * 687 * @throws SecurityException when the caller does not own the session, or 688 * the session is invalid. 689 */ updateSessionAppIcon(int sessionId, @Nullable Bitmap appIcon)690 public void updateSessionAppIcon(int sessionId, @Nullable Bitmap appIcon) { 691 try { 692 mInstaller.updateSessionAppIcon(sessionId, appIcon); 693 } catch (RemoteException e) { 694 throw e.rethrowFromSystemServer(); 695 } 696 } 697 698 /** 699 * Update the label representing the app being installed in a specific 700 * session. 701 * 702 * @throws SecurityException when the caller does not own the session, or 703 * the session is invalid. 704 */ updateSessionAppLabel(int sessionId, @Nullable CharSequence appLabel)705 public void updateSessionAppLabel(int sessionId, @Nullable CharSequence appLabel) { 706 try { 707 final String val = (appLabel != null) ? appLabel.toString() : null; 708 mInstaller.updateSessionAppLabel(sessionId, val); 709 } catch (RemoteException e) { 710 throw e.rethrowFromSystemServer(); 711 } 712 } 713 714 /** 715 * Completely abandon the given session, destroying all staged data and 716 * rendering it invalid. Abandoned sessions will be reported to 717 * {@link SessionCallback} listeners as failures. This is equivalent to 718 * opening the session and calling {@link Session#abandon()}. 719 * 720 * @throws SecurityException when the caller does not own the session, or 721 * the session is invalid. 722 */ abandonSession(int sessionId)723 public void abandonSession(int sessionId) { 724 try { 725 mInstaller.abandonSession(sessionId); 726 } catch (RemoteException e) { 727 throw e.rethrowFromSystemServer(); 728 } 729 } 730 731 /** 732 * Return details for a specific session. Callers need to either declare <queries> 733 * element with the specific package name in the app's manifest, have the 734 * android.permission.QUERY_ALL_PACKAGES, or be the session owner to retrieve these details. 735 * 736 * @return details for the requested session, or {@code null} if the session 737 * does not exist. 738 */ getSessionInfo(int sessionId)739 public @Nullable SessionInfo getSessionInfo(int sessionId) { 740 try { 741 return mInstaller.getSessionInfo(sessionId); 742 } catch (RemoteException e) { 743 throw e.rethrowFromSystemServer(); 744 } 745 } 746 747 /** 748 * Return list of all known install sessions, regardless of the installer. Callers need to 749 * either declare <queries> element with the specific package name in the app's manifest, 750 * have the android.permission.QUERY_ALL_PACKAGES, or be the session owner to retrieve these 751 * details. 752 */ getAllSessions()753 public @NonNull List<SessionInfo> getAllSessions() { 754 try { 755 return mInstaller.getAllSessions(mUserId).getList(); 756 } catch (RemoteException e) { 757 throw e.rethrowFromSystemServer(); 758 } 759 } 760 761 /** 762 * Return list of all known install sessions owned by the calling app. 763 */ getMySessions()764 public @NonNull List<SessionInfo> getMySessions() { 765 try { 766 return mInstaller.getMySessions(mInstallerPackageName, mUserId).getList(); 767 } catch (RemoteException e) { 768 throw e.rethrowFromSystemServer(); 769 } 770 } 771 772 /** 773 * Return list of all staged install sessions. Callers need to either declare <queries> 774 * element with the specific package name in the app's manifest, have the 775 * android.permission.QUERY_ALL_PACKAGES, or be the session owner to retrieve these details. 776 */ getStagedSessions()777 public @NonNull List<SessionInfo> getStagedSessions() { 778 try { 779 // TODO: limit this to the mUserId? 780 return mInstaller.getStagedSessions().getList(); 781 } catch (RemoteException e) { 782 throw e.rethrowFromSystemServer(); 783 } 784 } 785 786 /** 787 * Returns first active staged session, or {@code null} if there is none. 788 * 789 * <p>For more information on what sessions are considered active see 790 * {@link SessionInfo#isStagedSessionActive()}. 791 * 792 * @deprecated Use {@link #getActiveStagedSessions} as there can be more than one active staged 793 * session 794 */ 795 @Deprecated getActiveStagedSession()796 public @Nullable SessionInfo getActiveStagedSession() { 797 List<SessionInfo> activeSessions = getActiveStagedSessions(); 798 return activeSessions.isEmpty() ? null : activeSessions.get(0); 799 } 800 801 /** 802 * Returns list of active staged sessions. Returns empty list if there is none. 803 * 804 * <p>For more information on what sessions are considered active see 805 * * {@link SessionInfo#isStagedSessionActive()}. 806 */ getActiveStagedSessions()807 public @NonNull List<SessionInfo> getActiveStagedSessions() { 808 final List<SessionInfo> activeStagedSessions = new ArrayList<>(); 809 final List<SessionInfo> stagedSessions = getStagedSessions(); 810 for (int i = 0; i < stagedSessions.size(); i++) { 811 final SessionInfo sessionInfo = stagedSessions.get(i); 812 if (sessionInfo.isStagedSessionActive()) { 813 activeStagedSessions.add(sessionInfo); 814 } 815 } 816 return activeStagedSessions; 817 } 818 819 /** 820 * Uninstall the given package, removing it completely from the device. This 821 * method is available to: 822 * <ul> 823 * <li>the current "installer of record" for the package 824 * <li>the device owner 825 * <li>the affiliated profile owner 826 * </ul> 827 * 828 * @param packageName The package to uninstall. 829 * @param statusReceiver Where to deliver the result of the operation indicated by the extra 830 * {@link #EXTRA_STATUS}. Refer to the individual status codes 831 * on how to handle them. 832 * 833 * @see android.app.admin.DevicePolicyManager 834 */ 835 @RequiresPermission(anyOf = { 836 Manifest.permission.DELETE_PACKAGES, 837 Manifest.permission.REQUEST_DELETE_PACKAGES}) uninstall(@onNull String packageName, @NonNull IntentSender statusReceiver)838 public void uninstall(@NonNull String packageName, @NonNull IntentSender statusReceiver) { 839 uninstall(packageName, 0 /*flags*/, statusReceiver); 840 } 841 842 /** 843 * Uninstall the given package, removing it completely from the device. This 844 * method is only available to the current "installer of record" for the 845 * package. 846 * 847 * @param packageName The package to uninstall. 848 * @param flags Flags for uninstall. 849 * @param statusReceiver Where to deliver the result of the operation indicated by the extra 850 * {@link #EXTRA_STATUS}. Refer to the individual status codes 851 * on how to handle them. 852 * 853 * @hide 854 */ uninstall(@onNull String packageName, @DeleteFlags int flags, @NonNull IntentSender statusReceiver)855 public void uninstall(@NonNull String packageName, @DeleteFlags int flags, 856 @NonNull IntentSender statusReceiver) { 857 uninstall(new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST), 858 flags, statusReceiver); 859 } 860 861 /** 862 * Uninstall the given package with a specific version code, removing it 863 * completely from the device. If the version code of the package 864 * does not match the one passed in the versioned package argument this 865 * method is a no-op. Use {@link PackageManager#VERSION_CODE_HIGHEST} to 866 * uninstall the latest version of the package. 867 * <p> 868 * This method is available to: 869 * <ul> 870 * <li>the current "installer of record" for the package 871 * <li>the device owner 872 * <li>the affiliated profile owner 873 * </ul> 874 * 875 * @param versionedPackage The versioned package to uninstall. 876 * @param statusReceiver Where to deliver the result of the operation indicated by the extra 877 * {@link #EXTRA_STATUS}. Refer to the individual status codes 878 * on how to handle them. 879 * 880 * @see android.app.admin.DevicePolicyManager 881 */ 882 @RequiresPermission(anyOf = { 883 Manifest.permission.DELETE_PACKAGES, 884 Manifest.permission.REQUEST_DELETE_PACKAGES}) uninstall(@onNull VersionedPackage versionedPackage, @NonNull IntentSender statusReceiver)885 public void uninstall(@NonNull VersionedPackage versionedPackage, 886 @NonNull IntentSender statusReceiver) { 887 uninstall(versionedPackage, 0 /*flags*/, statusReceiver); 888 } 889 890 /** 891 * Uninstall the given package with a specific version code, removing it 892 * completely from the device. This method is only available to the current 893 * "installer of record" for the package. If the version code of the package 894 * does not match the one passed in the versioned package argument this 895 * method is a no-op. Use {@link PackageManager#VERSION_CODE_HIGHEST} to 896 * uninstall the latest version of the package. 897 * 898 * @param versionedPackage The versioned package to uninstall. 899 * @param flags Flags for uninstall. 900 * @param statusReceiver Where to deliver the result of the operation indicated by the extra 901 * {@link #EXTRA_STATUS}. Refer to the individual status codes 902 * on how to handle them. 903 */ 904 @RequiresPermission(anyOf = { 905 Manifest.permission.DELETE_PACKAGES, 906 Manifest.permission.REQUEST_DELETE_PACKAGES}) uninstall(@onNull VersionedPackage versionedPackage, @DeleteFlags int flags, @NonNull IntentSender statusReceiver)907 public void uninstall(@NonNull VersionedPackage versionedPackage, @DeleteFlags int flags, 908 @NonNull IntentSender statusReceiver) { 909 Objects.requireNonNull(versionedPackage, "versionedPackage cannot be null"); 910 try { 911 mInstaller.uninstall(versionedPackage, mInstallerPackageName, 912 flags, statusReceiver, mUserId); 913 } catch (RemoteException e) { 914 throw e.rethrowFromSystemServer(); 915 } 916 } 917 918 /** 919 * Install the given package, which already exists on the device, for the user for which this 920 * installer was created. 921 * 922 * <p>This will 923 * {@link PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set) allowlist 924 * all restricted permissions}. 925 * 926 * @param packageName The package to install. 927 * @param installReason Reason for install. 928 * @param statusReceiver Where to deliver the result of the operation indicated by the extra 929 * {@link #EXTRA_STATUS}. Refer to the individual status codes 930 * on how to handle them. 931 */ 932 @RequiresPermission(allOf = { 933 Manifest.permission.INSTALL_PACKAGES, 934 Manifest.permission.INSTALL_EXISTING_PACKAGES}) installExistingPackage(@onNull String packageName, @InstallReason int installReason, @Nullable IntentSender statusReceiver)935 public void installExistingPackage(@NonNull String packageName, 936 @InstallReason int installReason, 937 @Nullable IntentSender statusReceiver) { 938 Objects.requireNonNull(packageName, "packageName cannot be null"); 939 try { 940 mInstaller.installExistingPackage(packageName, 941 PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS, installReason, 942 statusReceiver, mUserId, null); 943 } catch (RemoteException e) { 944 throw e.rethrowFromSystemServer(); 945 } 946 } 947 948 /** 949 * Uninstall the given package for the user for which this installer was created if the package 950 * will still exist for other users on the device. 951 * 952 * @param packageName The package to uninstall. 953 * @param statusReceiver Where to deliver the result of the operation indicated by the extra 954 * {@link #EXTRA_STATUS}. Refer to the individual status codes 955 * on how to handle them. 956 */ 957 @RequiresPermission(Manifest.permission.DELETE_PACKAGES) uninstallExistingPackage(@onNull String packageName, @Nullable IntentSender statusReceiver)958 public void uninstallExistingPackage(@NonNull String packageName, 959 @Nullable IntentSender statusReceiver) { 960 Objects.requireNonNull(packageName, "packageName cannot be null"); 961 try { 962 mInstaller.uninstallExistingPackage( 963 new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST), 964 mInstallerPackageName, statusReceiver, mUserId); 965 } catch (RemoteException e) { 966 throw e.rethrowFromSystemServer(); 967 } 968 } 969 970 /** {@hide} */ 971 @SystemApi 972 @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) setPermissionsResult(int sessionId, boolean accepted)973 public void setPermissionsResult(int sessionId, boolean accepted) { 974 try { 975 mInstaller.setPermissionsResult(sessionId, accepted); 976 } catch (RemoteException e) { 977 throw e.rethrowFromSystemServer(); 978 } 979 } 980 981 /** 982 * Check if install constraints are satisfied for the given packages. 983 * 984 * Note this query result is just a hint and subject to race because system states could 985 * change anytime in-between this query and committing the session. 986 * 987 * The result is returned by a callback because some constraints might take a long time 988 * to evaluate. 989 * 990 * @param packageNames a list of package names to check the constraints for installation 991 * @param constraints the constraints for installation. 992 * @param executor the {@link Executor} on which to invoke the callback 993 * @param callback called when the {@link InstallConstraintsResult} is ready 994 * 995 * @throws SecurityException if the given packages' installer of record doesn't match the 996 * caller's own package name or the installerPackageName set by the caller doesn't 997 * match the caller's own package name. 998 */ checkInstallConstraints(@onNull List<String> packageNames, @NonNull InstallConstraints constraints, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<InstallConstraintsResult> callback)999 public void checkInstallConstraints(@NonNull List<String> packageNames, 1000 @NonNull InstallConstraints constraints, 1001 @NonNull @CallbackExecutor Executor executor, 1002 @NonNull Consumer<InstallConstraintsResult> callback) { 1003 Objects.requireNonNull(executor); 1004 Objects.requireNonNull(callback); 1005 try { 1006 var remoteCallback = new RemoteCallback(b -> { 1007 executor.execute(() -> { 1008 callback.accept(b.getParcelable("result", InstallConstraintsResult.class)); 1009 }); 1010 }); 1011 mInstaller.checkInstallConstraints( 1012 mInstallerPackageName, packageNames, constraints, remoteCallback); 1013 } catch (RemoteException e) { 1014 throw e.rethrowFromSystemServer(); 1015 } 1016 } 1017 1018 /** 1019 * Similar to {@link #checkInstallConstraints(List, InstallConstraints, Executor, Consumer)}, 1020 * but the callback is invoked only when the constraints are satisfied or after timeout. 1021 * <p> 1022 * Note: the device idle constraint might take a long time to evaluate. The system will 1023 * ensure the constraint is evaluated completely before handling timeout. 1024 * 1025 * @param packageNames a list of package names to check the constraints for installation 1026 * @param constraints the constraints for installation. 1027 * @param callback Called when the constraints are satisfied or after timeout. 1028 * Intents sent to this callback contain: 1029 * {@link Intent#EXTRA_PACKAGES} for the input package names, 1030 * {@link #EXTRA_INSTALL_CONSTRAINTS} for the input constraints, 1031 * {@link #EXTRA_INSTALL_CONSTRAINTS_RESULT} for the result. 1032 * @param timeoutMillis The maximum time to wait, in milliseconds until the constraints are 1033 * satisfied. Valid range is from 0 to one week. {@code 0} means the 1034 * callback will be invoked immediately no matter constraints are 1035 * satisfied or not. 1036 * @throws SecurityException if the given packages' installer of record doesn't match the 1037 * caller's own package name or the installerPackageName set by the caller doesn't 1038 * match the caller's own package name. 1039 */ waitForInstallConstraints(@onNull List<String> packageNames, @NonNull InstallConstraints constraints, @NonNull IntentSender callback, @DurationMillisLong long timeoutMillis)1040 public void waitForInstallConstraints(@NonNull List<String> packageNames, 1041 @NonNull InstallConstraints constraints, 1042 @NonNull IntentSender callback, 1043 @DurationMillisLong long timeoutMillis) { 1044 try { 1045 mInstaller.waitForInstallConstraints( 1046 mInstallerPackageName, packageNames, constraints, callback, timeoutMillis); 1047 } catch (RemoteException e) { 1048 throw e.rethrowFromSystemServer(); 1049 } 1050 } 1051 1052 /** 1053 * Commit the session when all constraints are satisfied. This is a convenient method to 1054 * combine {@link #waitForInstallConstraints(List, InstallConstraints, IntentSender, long)} 1055 * and {@link Session#commit(IntentSender)}. 1056 * <p> 1057 * Once this method is called, the session is sealed and no additional mutations 1058 * may be performed on the session. In the case of timeout, you may commit the 1059 * session again using this method or {@link Session#commit(IntentSender)} for retries. 1060 * 1061 * @param sessionId the session ID to commit when all constraints are satisfied. 1062 * @param statusReceiver Called when the state of the session changes. Intents 1063 * sent to this receiver contain {@link #EXTRA_STATUS}. 1064 * Refer to the individual status codes on how to handle them. 1065 * @param constraints The requirements to satisfy before committing the session. 1066 * @param timeoutMillis The maximum time to wait, in milliseconds until the 1067 * constraints are satisfied. The caller will be notified via 1068 * {@code statusReceiver} if timeout happens before commit. 1069 */ commitSessionAfterInstallConstraintsAreMet(int sessionId, @NonNull IntentSender statusReceiver, @NonNull InstallConstraints constraints, @DurationMillisLong long timeoutMillis)1070 public void commitSessionAfterInstallConstraintsAreMet(int sessionId, 1071 @NonNull IntentSender statusReceiver, @NonNull InstallConstraints constraints, 1072 @DurationMillisLong long timeoutMillis) { 1073 try { 1074 var session = mInstaller.openSession(sessionId); 1075 session.seal(); 1076 var packageNames = session.fetchPackageNames(); 1077 var intentSender = new IntentSender((IIntentSender) new IIntentSender.Stub() { 1078 @Override 1079 public void send(int code, Intent intent, String resolvedType, 1080 IBinder allowlistToken, IIntentReceiver finishedReceiver, 1081 String requiredPermission, Bundle options) { 1082 var result = intent.getParcelableExtra( 1083 PackageInstaller.EXTRA_INSTALL_CONSTRAINTS_RESULT, 1084 InstallConstraintsResult.class); 1085 try { 1086 if (result.areAllConstraintsSatisfied()) { 1087 session.commit(statusReceiver, false); 1088 } else { 1089 // timeout 1090 final Intent fillIn = new Intent(); 1091 fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId); 1092 fillIn.putExtra(PackageInstaller.EXTRA_STATUS, STATUS_FAILURE_TIMEOUT); 1093 fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, 1094 "Install constraints not satisfied within timeout"); 1095 statusReceiver.sendIntent( 1096 ActivityThread.currentApplication(), 0, fillIn, null, null); 1097 } 1098 } catch (Exception ignore) { 1099 } 1100 } 1101 }); 1102 waitForInstallConstraints(packageNames, constraints, intentSender, timeoutMillis); 1103 } catch (RemoteException e) { 1104 throw e.rethrowFromSystemServer(); 1105 } 1106 } 1107 1108 /** 1109 * Events for observing session lifecycle. 1110 * <p> 1111 * A typical session lifecycle looks like this: 1112 * <ul> 1113 * <li>An installer creates a session to indicate pending app delivery. All 1114 * install details are available at this point. 1115 * <li>The installer opens the session to deliver APK data. Note that a 1116 * session may be opened and closed multiple times as network connectivity 1117 * changes. The installer may deliver periodic progress updates. 1118 * <li>The installer commits or abandons the session, resulting in the 1119 * session being finished. 1120 * </ul> 1121 */ 1122 public static abstract class SessionCallback { 1123 /** 1124 * New session has been created. Details about the session can be 1125 * obtained from {@link PackageInstaller#getSessionInfo(int)}. 1126 */ onCreated(int sessionId)1127 public abstract void onCreated(int sessionId); 1128 1129 /** 1130 * Badging details for an existing session has changed. For example, the 1131 * app icon or label has been updated. 1132 */ onBadgingChanged(int sessionId)1133 public abstract void onBadgingChanged(int sessionId); 1134 1135 /** 1136 * Active state for session has been changed. 1137 * <p> 1138 * A session is considered active whenever there is ongoing forward 1139 * progress being made, such as the installer holding an open 1140 * {@link Session} instance while streaming data into place, or the 1141 * system optimizing code as the result of 1142 * {@link Session#commit(IntentSender)}. 1143 * <p> 1144 * If the installer closes the {@link Session} without committing, the 1145 * session is considered inactive until the installer opens the session 1146 * again. 1147 */ onActiveChanged(int sessionId, boolean active)1148 public abstract void onActiveChanged(int sessionId, boolean active); 1149 1150 /** 1151 * Progress for given session has been updated. 1152 * <p> 1153 * Note that this progress may not directly correspond to the value 1154 * reported by 1155 * {@link PackageInstaller.Session#setStagingProgress(float)}, as the 1156 * system may carve out a portion of the overall progress to represent 1157 * its own internal installation work. 1158 */ onProgressChanged(int sessionId, float progress)1159 public abstract void onProgressChanged(int sessionId, float progress); 1160 1161 /** 1162 * Session has completely finished, either with success or failure. 1163 */ onFinished(int sessionId, boolean success)1164 public abstract void onFinished(int sessionId, boolean success); 1165 } 1166 1167 /** {@hide} */ 1168 static class SessionCallbackDelegate extends IPackageInstallerCallback.Stub { 1169 private static final int MSG_SESSION_CREATED = 1; 1170 private static final int MSG_SESSION_BADGING_CHANGED = 2; 1171 private static final int MSG_SESSION_ACTIVE_CHANGED = 3; 1172 private static final int MSG_SESSION_PROGRESS_CHANGED = 4; 1173 private static final int MSG_SESSION_FINISHED = 5; 1174 1175 final SessionCallback mCallback; 1176 final Executor mExecutor; 1177 SessionCallbackDelegate(SessionCallback callback, Executor executor)1178 SessionCallbackDelegate(SessionCallback callback, Executor executor) { 1179 mCallback = callback; 1180 mExecutor = executor; 1181 } 1182 1183 @Override onSessionCreated(int sessionId)1184 public void onSessionCreated(int sessionId) { 1185 mExecutor.execute(PooledLambda.obtainRunnable(SessionCallback::onCreated, mCallback, 1186 sessionId).recycleOnUse()); 1187 } 1188 1189 @Override onSessionBadgingChanged(int sessionId)1190 public void onSessionBadgingChanged(int sessionId) { 1191 mExecutor.execute(PooledLambda.obtainRunnable(SessionCallback::onBadgingChanged, 1192 mCallback, sessionId).recycleOnUse()); 1193 } 1194 1195 @Override onSessionActiveChanged(int sessionId, boolean active)1196 public void onSessionActiveChanged(int sessionId, boolean active) { 1197 mExecutor.execute(PooledLambda.obtainRunnable(SessionCallback::onActiveChanged, 1198 mCallback, sessionId, active).recycleOnUse()); 1199 } 1200 1201 @Override onSessionProgressChanged(int sessionId, float progress)1202 public void onSessionProgressChanged(int sessionId, float progress) { 1203 mExecutor.execute(PooledLambda.obtainRunnable(SessionCallback::onProgressChanged, 1204 mCallback, sessionId, progress).recycleOnUse()); 1205 } 1206 1207 @Override onSessionFinished(int sessionId, boolean success)1208 public void onSessionFinished(int sessionId, boolean success) { 1209 mExecutor.execute(PooledLambda.obtainRunnable(SessionCallback::onFinished, 1210 mCallback, sessionId, success).recycleOnUse()); 1211 } 1212 } 1213 1214 /** {@hide} */ 1215 @Deprecated addSessionCallback(@onNull SessionCallback callback)1216 public void addSessionCallback(@NonNull SessionCallback callback) { 1217 registerSessionCallback(callback); 1218 } 1219 1220 /** 1221 * Register to watch for session lifecycle events. The callers need to be the session 1222 * owner or have the android.permission.QUERY_ALL_PACKAGES to watch for these events. 1223 */ registerSessionCallback(@onNull SessionCallback callback)1224 public void registerSessionCallback(@NonNull SessionCallback callback) { 1225 registerSessionCallback(callback, new Handler()); 1226 } 1227 1228 /** {@hide} */ 1229 @Deprecated addSessionCallback(@onNull SessionCallback callback, @NonNull Handler handler)1230 public void addSessionCallback(@NonNull SessionCallback callback, @NonNull Handler handler) { 1231 registerSessionCallback(callback, handler); 1232 } 1233 1234 /** 1235 * Register to watch for session lifecycle events. No special permissions 1236 * are required to watch for these events. 1237 * 1238 * @param handler to dispatch callback events through, otherwise uses 1239 * calling thread. 1240 */ registerSessionCallback(@onNull SessionCallback callback, @NonNull Handler handler)1241 public void registerSessionCallback(@NonNull SessionCallback callback, @NonNull Handler handler) { 1242 synchronized (mDelegates) { 1243 final SessionCallbackDelegate delegate = new SessionCallbackDelegate(callback, 1244 new HandlerExecutor(handler)); 1245 try { 1246 mInstaller.registerCallback(delegate, mUserId); 1247 } catch (RemoteException e) { 1248 throw e.rethrowFromSystemServer(); 1249 } 1250 mDelegates.add(delegate); 1251 } 1252 } 1253 1254 /** {@hide} */ 1255 @Deprecated removeSessionCallback(@onNull SessionCallback callback)1256 public void removeSessionCallback(@NonNull SessionCallback callback) { 1257 unregisterSessionCallback(callback); 1258 } 1259 1260 /** 1261 * Unregister a previously registered callback. 1262 */ unregisterSessionCallback(@onNull SessionCallback callback)1263 public void unregisterSessionCallback(@NonNull SessionCallback callback) { 1264 synchronized (mDelegates) { 1265 for (Iterator<SessionCallbackDelegate> i = mDelegates.iterator(); i.hasNext();) { 1266 final SessionCallbackDelegate delegate = i.next(); 1267 if (delegate.mCallback == callback) { 1268 try { 1269 mInstaller.unregisterCallback(delegate); 1270 } catch (RemoteException e) { 1271 throw e.rethrowFromSystemServer(); 1272 } 1273 i.remove(); 1274 } 1275 } 1276 } 1277 } 1278 1279 /** 1280 * An installation that is being actively staged. For an install to succeed, 1281 * all existing and new packages must have identical package names, version 1282 * codes, and signing certificates. 1283 * <p> 1284 * A session may contain any number of split packages. If the application 1285 * does not yet exist, this session must include a base package. 1286 * <p> 1287 * If an APK included in this session is already defined by the existing 1288 * installation (for example, the same split name), the APK in this session 1289 * will replace the existing APK. 1290 * <p> 1291 * In such a case that multiple packages need to be committed simultaneously, 1292 * multiple sessions can be referenced by a single multi-package session. 1293 * This session is created with no package name and calling 1294 * {@link SessionParams#setMultiPackage()}. The individual session IDs can be 1295 * added with {@link #addChildSessionId(int)} and commit of the multi-package 1296 * session will result in all child sessions being committed atomically. 1297 */ 1298 public static class Session implements Closeable { 1299 /** {@hide} */ 1300 protected final IPackageInstallerSession mSession; 1301 1302 /** {@hide} */ Session(IPackageInstallerSession session)1303 public Session(IPackageInstallerSession session) { 1304 mSession = session; 1305 } 1306 1307 /** {@hide} */ 1308 @Deprecated setProgress(float progress)1309 public void setProgress(float progress) { 1310 setStagingProgress(progress); 1311 } 1312 1313 /** 1314 * Set current progress of staging this session. Valid values are 1315 * anywhere between 0 and 1. 1316 * <p> 1317 * Note that this progress may not directly correspond to the value 1318 * reported by {@link SessionCallback#onProgressChanged(int, float)}, as 1319 * the system may carve out a portion of the overall progress to 1320 * represent its own internal installation work. 1321 */ setStagingProgress(float progress)1322 public void setStagingProgress(float progress) { 1323 try { 1324 mSession.setClientProgress(progress); 1325 } catch (RemoteException e) { 1326 throw e.rethrowFromSystemServer(); 1327 } 1328 } 1329 1330 /** {@hide} */ 1331 @UnsupportedAppUsage addProgress(float progress)1332 public void addProgress(float progress) { 1333 try { 1334 mSession.addClientProgress(progress); 1335 } catch (RemoteException e) { 1336 throw e.rethrowFromSystemServer(); 1337 } 1338 } 1339 1340 /** 1341 * Open a stream to write an APK file into the session. 1342 * <p> 1343 * The returned stream will start writing data at the requested offset 1344 * in the underlying file, which can be used to resume a partially 1345 * written file. If a valid file length is specified, the system will 1346 * preallocate the underlying disk space to optimize placement on disk. 1347 * It's strongly recommended to provide a valid file length when known. 1348 * <p> 1349 * You can write data into the returned stream, optionally call 1350 * {@link #fsync(OutputStream)} as needed to ensure bytes have been 1351 * persisted to disk, and then close when finished. All streams must be 1352 * closed before calling {@link #commit(IntentSender)}. 1353 * 1354 * @param name arbitrary, unique name of your choosing to identify the 1355 * APK being written. You can open a file again for 1356 * additional writes (such as after a reboot) by using the 1357 * same name. This name is only meaningful within the context 1358 * of a single install session. 1359 * @param offsetBytes offset into the file to begin writing at, or 0 to 1360 * start at the beginning of the file. 1361 * @param lengthBytes total size of the file being written, used to 1362 * preallocate the underlying disk space, or -1 if unknown. 1363 * The system may clear various caches as needed to allocate 1364 * this space. 1365 * @throws IOException if trouble opening the file for writing, such as 1366 * lack of disk space or unavailable media. 1367 * @throws SecurityException if called after the session has been 1368 * sealed or abandoned 1369 */ openWrite(@onNull String name, long offsetBytes, long lengthBytes)1370 public @NonNull OutputStream openWrite(@NonNull String name, long offsetBytes, 1371 long lengthBytes) throws IOException { 1372 try { 1373 if (ENABLE_REVOCABLE_FD) { 1374 return new ParcelFileDescriptor.AutoCloseOutputStream( 1375 mSession.openWrite(name, offsetBytes, lengthBytes)); 1376 } else { 1377 final ParcelFileDescriptor clientSocket = mSession.openWrite(name, 1378 offsetBytes, lengthBytes); 1379 return new FileBridge.FileBridgeOutputStream(clientSocket); 1380 } 1381 } catch (RuntimeException e) { 1382 ExceptionUtils.maybeUnwrapIOException(e); 1383 throw e; 1384 } catch (RemoteException e) { 1385 throw e.rethrowFromSystemServer(); 1386 } 1387 } 1388 1389 /** {@hide} */ write(@onNull String name, long offsetBytes, long lengthBytes, @NonNull ParcelFileDescriptor fd)1390 public void write(@NonNull String name, long offsetBytes, long lengthBytes, 1391 @NonNull ParcelFileDescriptor fd) throws IOException { 1392 try { 1393 mSession.write(name, offsetBytes, lengthBytes, fd); 1394 } catch (RuntimeException e) { 1395 ExceptionUtils.maybeUnwrapIOException(e); 1396 throw e; 1397 } catch (RemoteException e) { 1398 throw e.rethrowFromSystemServer(); 1399 } 1400 } 1401 1402 /** 1403 * Populate an APK file by creating a hard link to avoid the need to copy. 1404 * <p> 1405 * Note this API is used by RollbackManager only and can only be called from system_server. 1406 * {@code target} will be relabeled if link is created successfully. RollbackManager has 1407 * to delete {@code target} when the session is committed successfully to avoid SELinux 1408 * label conflicts. 1409 * <p> 1410 * Note No more bytes should be written to the file once the link is created successfully. 1411 * 1412 * @param target the path of the link target 1413 * 1414 * @hide 1415 */ stageViaHardLink(String target)1416 public void stageViaHardLink(String target) throws IOException { 1417 try { 1418 mSession.stageViaHardLink(target); 1419 } catch (RuntimeException e) { 1420 ExceptionUtils.maybeUnwrapIOException(e); 1421 throw e; 1422 } catch (RemoteException e) { 1423 throw e.rethrowFromSystemServer(); 1424 } 1425 } 1426 1427 /** 1428 * Ensure that any outstanding data for given stream has been committed 1429 * to disk. This is only valid for streams returned from 1430 * {@link #openWrite(String, long, long)}. 1431 */ fsync(@onNull OutputStream out)1432 public void fsync(@NonNull OutputStream out) throws IOException { 1433 if (ENABLE_REVOCABLE_FD) { 1434 if (out instanceof ParcelFileDescriptor.AutoCloseOutputStream) { 1435 try { 1436 Os.fsync(((ParcelFileDescriptor.AutoCloseOutputStream) out).getFD()); 1437 } catch (ErrnoException e) { 1438 throw e.rethrowAsIOException(); 1439 } 1440 } else { 1441 throw new IllegalArgumentException("Unrecognized stream"); 1442 } 1443 } else { 1444 if (out instanceof FileBridge.FileBridgeOutputStream) { 1445 ((FileBridge.FileBridgeOutputStream) out).fsync(); 1446 } else { 1447 throw new IllegalArgumentException("Unrecognized stream"); 1448 } 1449 } 1450 } 1451 1452 /** 1453 * Return all APK names contained in this session. 1454 * <p> 1455 * This returns all names which have been previously written through 1456 * {@link #openWrite(String, long, long)} as part of this session. 1457 * 1458 * @throws SecurityException if called after the session has been 1459 * committed or abandoned. 1460 */ getNames()1461 public @NonNull String[] getNames() throws IOException { 1462 try { 1463 return mSession.getNames(); 1464 } catch (RuntimeException e) { 1465 ExceptionUtils.maybeUnwrapIOException(e); 1466 throw e; 1467 } catch (RemoteException e) { 1468 throw e.rethrowFromSystemServer(); 1469 } 1470 } 1471 1472 /** 1473 * Open a stream to read an APK file from the session. 1474 * <p> 1475 * This is only valid for names which have been previously written 1476 * through {@link #openWrite(String, long, long)} as part of this 1477 * session. For example, this stream may be used to calculate a 1478 * {@link MessageDigest} of a written APK before committing. 1479 * 1480 * @throws SecurityException if called after the session has been 1481 * committed or abandoned. 1482 */ openRead(@onNull String name)1483 public @NonNull InputStream openRead(@NonNull String name) throws IOException { 1484 try { 1485 final ParcelFileDescriptor pfd = mSession.openRead(name); 1486 return new ParcelFileDescriptor.AutoCloseInputStream(pfd); 1487 } catch (RuntimeException e) { 1488 ExceptionUtils.maybeUnwrapIOException(e); 1489 throw e; 1490 } catch (RemoteException e) { 1491 throw e.rethrowFromSystemServer(); 1492 } 1493 } 1494 1495 /** 1496 * Removes a split. 1497 * <p> 1498 * Split removals occur prior to adding new APKs. If upgrading a feature 1499 * split, it is not expected nor desirable to remove the split prior to 1500 * upgrading. 1501 * <p> 1502 * When split removal is bundled with new APKs, the packageName must be 1503 * identical. 1504 */ removeSplit(@onNull String splitName)1505 public void removeSplit(@NonNull String splitName) throws IOException { 1506 try { 1507 mSession.removeSplit(splitName); 1508 } catch (RuntimeException e) { 1509 ExceptionUtils.maybeUnwrapIOException(e); 1510 throw e; 1511 } catch (RemoteException e) { 1512 throw e.rethrowFromSystemServer(); 1513 } 1514 } 1515 1516 /** 1517 * @return data loader params or null if the session is not using one. 1518 * {@hide} 1519 */ 1520 @SystemApi 1521 @RequiresPermission(android.Manifest.permission.USE_INSTALLER_V2) getDataLoaderParams()1522 public @Nullable DataLoaderParams getDataLoaderParams() { 1523 try { 1524 DataLoaderParamsParcel data = mSession.getDataLoaderParams(); 1525 if (data == null) { 1526 return null; 1527 } 1528 return new DataLoaderParams(data); 1529 } catch (RemoteException e) { 1530 throw e.rethrowFromSystemServer(); 1531 } 1532 } 1533 1534 /** 1535 * Adds a file to session. On commit this file will be pulled from DataLoader {@code 1536 * android.service.dataloader.DataLoaderService.DataLoader}. 1537 * 1538 * @param location target location for the file. Possible values: 1539 * {@link #LOCATION_DATA_APP}, 1540 * {@link #LOCATION_MEDIA_OBB}, 1541 * {@link #LOCATION_MEDIA_DATA}. 1542 * @param name arbitrary, unique name of your choosing to identify the 1543 * APK being written. You can open a file again for 1544 * additional writes (such as after a reboot) by using the 1545 * same name. This name is only meaningful within the context 1546 * of a single install session. 1547 * @param lengthBytes total size of the file being written. 1548 * The system may clear various caches as needed to allocate 1549 * this space. 1550 * @param metadata additional info use by DataLoader to pull data for the file. 1551 * @param signature additional file signature, e.g. 1552 * <a href="https://source.android.com/security/apksigning/v4.html">APK Signature Scheme v4</a> 1553 * @throws SecurityException if called after the session has been 1554 * sealed or abandoned 1555 * @throws IllegalStateException if called for non-streaming session 1556 * 1557 * @see android.content.pm.InstallationFile 1558 * 1559 * {@hide} 1560 */ 1561 @SystemApi 1562 @RequiresPermission(android.Manifest.permission.USE_INSTALLER_V2) addFile(@ileLocation int location, @NonNull String name, long lengthBytes, @NonNull byte[] metadata, @Nullable byte[] signature)1563 public void addFile(@FileLocation int location, @NonNull String name, long lengthBytes, 1564 @NonNull byte[] metadata, @Nullable byte[] signature) { 1565 try { 1566 mSession.addFile(location, name, lengthBytes, metadata, signature); 1567 } catch (RemoteException e) { 1568 throw e.rethrowFromSystemServer(); 1569 } 1570 } 1571 1572 /** 1573 * Removes a file. 1574 * 1575 * @param location target location for the file. Possible values: 1576 * {@link #LOCATION_DATA_APP}, 1577 * {@link #LOCATION_MEDIA_OBB}, 1578 * {@link #LOCATION_MEDIA_DATA}. 1579 * @param name name of a file, e.g. split. 1580 * @throws SecurityException if called after the session has been 1581 * sealed or abandoned 1582 * @throws IllegalStateException if called for non-DataLoader session 1583 * {@hide} 1584 */ 1585 @SystemApi 1586 @RequiresPermission(android.Manifest.permission.USE_INSTALLER_V2) removeFile(@ileLocation int location, @NonNull String name)1587 public void removeFile(@FileLocation int location, @NonNull String name) { 1588 try { 1589 mSession.removeFile(location, name); 1590 } catch (RemoteException e) { 1591 throw e.rethrowFromSystemServer(); 1592 } 1593 } 1594 1595 /** 1596 * Sets installer-provided checksums for the APK file in session. 1597 * 1598 * @param name previously written as part of this session. 1599 * {@link #openWrite} 1600 * @param checksums installer intends to make available via 1601 * {@link PackageManager#requestChecksums} or {@link #requestChecksums}. 1602 * @param signature DER PKCS#7 detached signature bytes over binary serialized checksums 1603 * to enable integrity checking for the checksums or null for no integrity 1604 * checking. {@link PackageManager#requestChecksums} will return 1605 * the certificate used to create signature. 1606 * Binary format for checksums: 1607 * <pre>{@code DataOutputStream dos; 1608 * dos.writeInt(checksum.getType()); 1609 * dos.writeInt(checksum.getValue().length); 1610 * dos.write(checksum.getValue());}</pre> 1611 * If using <b>openssl cms</b>, make sure to specify -binary -nosmimecap. 1612 * @see <a href="https://www.openssl.org/docs/man1.0.2/man1/cms.html">openssl cms</a> 1613 * @throws SecurityException if called after the session has been 1614 * committed or abandoned. 1615 * @throws IllegalStateException if checksums for this file have already been added. 1616 * @deprecated do not use installer-provided checksums, 1617 * use platform-enforced checksums 1618 * e.g. {@link Checksum#TYPE_WHOLE_MERKLE_ROOT_4K_SHA256} 1619 * in {@link PackageManager#requestChecksums}. 1620 */ 1621 @Deprecated setChecksums(@onNull String name, @NonNull List<Checksum> checksums, @Nullable byte[] signature)1622 public void setChecksums(@NonNull String name, @NonNull List<Checksum> checksums, 1623 @Nullable byte[] signature) throws IOException { 1624 Objects.requireNonNull(name); 1625 Objects.requireNonNull(checksums); 1626 1627 try { 1628 mSession.setChecksums(name, checksums.toArray(new Checksum[checksums.size()]), 1629 signature); 1630 } catch (RuntimeException e) { 1631 ExceptionUtils.maybeUnwrapIOException(e); 1632 throw e; 1633 } catch (RemoteException e) { 1634 throw e.rethrowFromSystemServer(); 1635 } 1636 } 1637 encodeCertificates(List<Certificate> certs)1638 private static List<byte[]> encodeCertificates(List<Certificate> certs) throws 1639 CertificateEncodingException { 1640 if (certs == null) { 1641 return null; 1642 } 1643 List<byte[]> result = new ArrayList<>(certs.size()); 1644 for (Certificate cert : certs) { 1645 if (!(cert instanceof X509Certificate)) { 1646 throw new CertificateEncodingException("Only X509 certificates supported."); 1647 } 1648 result.add(cert.getEncoded()); 1649 } 1650 return result; 1651 } 1652 1653 /** 1654 * Requests checksums for the APK file in session. 1655 * <p> 1656 * A possible use case is replying to {@link Intent#ACTION_PACKAGE_NEEDS_VERIFICATION} 1657 * broadcast. 1658 * The checksums will be returned asynchronously via onChecksumsReadyListener. 1659 * <p> 1660 * By default returns all readily available checksums: 1661 * <ul> 1662 * <li>enforced by platform, 1663 * <li>enforced by the installer. 1664 * </ul> 1665 * If the caller needs a specific checksum type, they can specify it as required. 1666 * <p> 1667 * <b>Caution: Android can not verify installer-provided checksums. Make sure you specify 1668 * trusted installers.</b> 1669 * <p> 1670 * @param name previously written as part of this session. 1671 * {@link #openWrite} 1672 * @param required to explicitly request the checksum types. Will incur significant 1673 * CPU/memory/disk usage. 1674 * @param trustedInstallers for checksums enforced by installer, which installers are to be 1675 * trusted. 1676 * {@link PackageManager#TRUST_ALL} will return checksums from any 1677 * installer, 1678 * {@link PackageManager#TRUST_NONE} disables optimized 1679 * installer-enforced checksums, otherwise the list has to be 1680 * a non-empty list of certificates. 1681 * @param executor the {@link Executor} on which to invoke the callback 1682 * @param onChecksumsReadyListener called once when the results are available. 1683 * @throws CertificateEncodingException if an encoding error occurs for trustedInstallers. 1684 * @throws FileNotFoundException if the file does not exist. 1685 * @throws IllegalArgumentException if the list of trusted installer certificates is empty. 1686 */ requestChecksums(@onNull String name, @Checksum.TypeMask int required, @NonNull List<Certificate> trustedInstallers, @NonNull @CallbackExecutor Executor executor, @NonNull PackageManager.OnChecksumsReadyListener onChecksumsReadyListener)1687 public void requestChecksums(@NonNull String name, @Checksum.TypeMask int required, 1688 @NonNull List<Certificate> trustedInstallers, 1689 @NonNull @CallbackExecutor Executor executor, 1690 @NonNull PackageManager.OnChecksumsReadyListener onChecksumsReadyListener) 1691 throws CertificateEncodingException, FileNotFoundException { 1692 Objects.requireNonNull(name); 1693 Objects.requireNonNull(trustedInstallers); 1694 Objects.requireNonNull(executor); 1695 Objects.requireNonNull(onChecksumsReadyListener); 1696 if (trustedInstallers == PackageManager.TRUST_ALL) { 1697 trustedInstallers = null; 1698 } else if (trustedInstallers == PackageManager.TRUST_NONE) { 1699 trustedInstallers = Collections.emptyList(); 1700 } else if (trustedInstallers.isEmpty()) { 1701 throw new IllegalArgumentException( 1702 "trustedInstallers has to be one of TRUST_ALL/TRUST_NONE or a non-empty " 1703 + "list of certificates."); 1704 } 1705 try { 1706 IOnChecksumsReadyListener onChecksumsReadyListenerDelegate = 1707 new IOnChecksumsReadyListener.Stub() { 1708 @Override 1709 public void onChecksumsReady(List<ApkChecksum> checksums) 1710 throws RemoteException { 1711 executor.execute( 1712 () -> onChecksumsReadyListener.onChecksumsReady(checksums)); 1713 } 1714 }; 1715 mSession.requestChecksums(name, DEFAULT_CHECKSUMS, required, 1716 encodeCertificates(trustedInstallers), onChecksumsReadyListenerDelegate); 1717 } catch (ParcelableException e) { 1718 e.maybeRethrow(FileNotFoundException.class); 1719 throw new RuntimeException(e); 1720 } catch (RemoteException e) { 1721 throw e.rethrowFromSystemServer(); 1722 } 1723 } 1724 1725 /** 1726 * Attempt to commit everything staged in this session. This may require 1727 * user intervention, and so it may not happen immediately. The final 1728 * result of the commit will be reported through the given callback. 1729 * <p> 1730 * Once this method is called, the session is sealed and no additional mutations may be 1731 * performed on the session. In case of device reboot or data loader transient failure 1732 * before the session has been finalized, you may commit the session again. 1733 * <p> 1734 * If the installer is the device owner, the affiliated profile owner, or has received 1735 * user pre-approval of this session, there will be no user intervention. 1736 * 1737 * @param statusReceiver Called when the state of the session changes. Intents 1738 * sent to this receiver contain {@link #EXTRA_STATUS}. Refer to the 1739 * individual status codes on how to handle them. 1740 * 1741 * @throws SecurityException if streams opened through 1742 * {@link #openWrite(String, long, long)} are still open. 1743 * 1744 * @see android.app.admin.DevicePolicyManager 1745 * @see #requestUserPreapproval 1746 */ commit(@onNull IntentSender statusReceiver)1747 public void commit(@NonNull IntentSender statusReceiver) { 1748 try { 1749 mSession.commit(statusReceiver, false); 1750 } catch (RemoteException e) { 1751 throw e.rethrowFromSystemServer(); 1752 } 1753 } 1754 1755 /** 1756 * Attempt to commit a session that has been {@link #transfer(String) transferred}. 1757 * 1758 * <p>If the device reboots before the session has been finalized, you may commit the 1759 * session again. 1760 * 1761 * <p>The caller of this method is responsible to ensure the safety of the session. As the 1762 * session was created by another - usually less trusted - app, it is paramount that before 1763 * committing <u>all</u> public and system {@link SessionInfo properties of the session} 1764 * and <u>all</u> {@link #openRead(String) APKs} are verified by the caller. It might happen 1765 * that new properties are added to the session with a new API revision. In this case the 1766 * callers need to be updated. 1767 * 1768 * @param statusReceiver Called when the state of the session changes. Intents 1769 * sent to this receiver contain {@link #EXTRA_STATUS}. Refer to the 1770 * individual status codes on how to handle them. 1771 * 1772 * @hide 1773 */ 1774 @SystemApi 1775 @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) commitTransferred(@onNull IntentSender statusReceiver)1776 public void commitTransferred(@NonNull IntentSender statusReceiver) { 1777 try { 1778 mSession.commit(statusReceiver, true); 1779 } catch (RemoteException e) { 1780 throw e.rethrowFromSystemServer(); 1781 } 1782 } 1783 1784 /** 1785 * Transfer the session to a new owner. 1786 * <p> 1787 * Only sessions that update the installing app can be transferred. 1788 * <p> 1789 * After the transfer to a package with a different uid all method calls on the session 1790 * will cause {@link SecurityException}s. 1791 * <p> 1792 * Once this method is called, the session is sealed and no additional mutations beside 1793 * committing it may be performed on the session. 1794 * 1795 * @param packageName The package of the new owner. Needs to hold the INSTALL_PACKAGES 1796 * permission. 1797 * 1798 * @throws PackageManager.NameNotFoundException if the new owner could not be found. 1799 * @throws SecurityException if called after the session has been committed or abandoned. 1800 * @throws IllegalStateException if streams opened through 1801 * {@link #openWrite(String, long, long) are still open. 1802 * @throws IllegalArgumentException if {@code packageName} is invalid. 1803 */ transfer(@onNull String packageName)1804 public void transfer(@NonNull String packageName) 1805 throws PackageManager.NameNotFoundException { 1806 Preconditions.checkArgument(!TextUtils.isEmpty(packageName)); 1807 1808 try { 1809 mSession.transfer(packageName); 1810 } catch (ParcelableException e) { 1811 e.maybeRethrow(PackageManager.NameNotFoundException.class); 1812 throw new RuntimeException(e); 1813 } catch (RemoteException e) { 1814 throw e.rethrowFromSystemServer(); 1815 } 1816 } 1817 1818 /** 1819 * Release this session object. You can open the session again if it 1820 * hasn't been finalized. 1821 */ 1822 @Override close()1823 public void close() { 1824 try { 1825 mSession.close(); 1826 } catch (RemoteException e) { 1827 throw e.rethrowFromSystemServer(); 1828 } 1829 } 1830 1831 /** 1832 * Completely abandon this session, destroying all staged data and 1833 * rendering it invalid. Abandoned sessions will be reported to 1834 * {@link SessionCallback} listeners as failures. This is equivalent to 1835 * {@link #abandonSession(int)}. 1836 * <p>If the parent is abandoned, all children will also be abandoned. Any written data 1837 * would be destroyed and the created {@link Session} information will be discarded.</p> 1838 */ abandon()1839 public void abandon() { 1840 try { 1841 mSession.abandon(); 1842 } catch (RemoteException e) { 1843 throw e.rethrowFromSystemServer(); 1844 } 1845 } 1846 1847 /** 1848 * @return {@code true} if this session will commit more than one package when it is 1849 * committed. 1850 */ isMultiPackage()1851 public boolean isMultiPackage() { 1852 try { 1853 return mSession.isMultiPackage(); 1854 } catch (RemoteException e) { 1855 throw e.rethrowFromSystemServer(); 1856 } 1857 } 1858 1859 /** 1860 * @return {@code true} if this session will be staged and applied at next reboot. 1861 */ isStaged()1862 public boolean isStaged() { 1863 try { 1864 return mSession.isStaged(); 1865 } catch (RemoteException e) { 1866 throw e.rethrowFromSystemServer(); 1867 } 1868 } 1869 1870 /** 1871 * @return Session's {@link SessionParams#installFlags}. 1872 * @hide 1873 */ getInstallFlags()1874 public int getInstallFlags() { 1875 try { 1876 return mSession.getInstallFlags(); 1877 } catch (RemoteException e) { 1878 throw e.rethrowFromSystemServer(); 1879 } 1880 } 1881 1882 /** 1883 * @return the session ID of the multi-package session that this belongs to or 1884 * {@link SessionInfo#INVALID_ID} if it does not belong to a multi-package session. 1885 */ getParentSessionId()1886 public int getParentSessionId() { 1887 try { 1888 return mSession.getParentSessionId(); 1889 } catch (RemoteException e) { 1890 throw e.rethrowFromSystemServer(); 1891 } 1892 } 1893 1894 /** 1895 * @return the set of session IDs that will be committed atomically when this session is 1896 * committed if this is a multi-package session or null if none exist. 1897 */ 1898 @NonNull getChildSessionIds()1899 public int[] getChildSessionIds() { 1900 try { 1901 return mSession.getChildSessionIds(); 1902 } catch (RemoteException e) { 1903 throw e.rethrowFromSystemServer(); 1904 } 1905 } 1906 1907 /** 1908 * Adds a session ID to the set of sessions that will be committed atomically 1909 * when this session is committed. 1910 * 1911 * <p>If the parent is staged or has rollback enabled, all children must have 1912 * the same properties.</p> 1913 * <p>If the parent is abandoned, all children will also be abandoned.</p> 1914 * 1915 * @param sessionId the session ID to add to this multi-package session. 1916 */ addChildSessionId(int sessionId)1917 public void addChildSessionId(int sessionId) { 1918 try { 1919 mSession.addChildSessionId(sessionId); 1920 } catch (RemoteException e) { 1921 e.rethrowFromSystemServer(); 1922 } 1923 } 1924 1925 /** 1926 * Removes a session ID from the set of sessions that will be committed 1927 * atomically when this session is committed. 1928 * 1929 * @param sessionId the session ID to remove from this multi-package session. 1930 */ removeChildSessionId(int sessionId)1931 public void removeChildSessionId(int sessionId) { 1932 try { 1933 mSession.removeChildSessionId(sessionId); 1934 } catch (RemoteException e) { 1935 e.rethrowFromSystemServer(); 1936 } 1937 } 1938 1939 /** 1940 * @return A PersistableBundle containing the app metadata set with 1941 * {@link Session#setAppMetadata(PersistableBundle)}. In the case where this data does not 1942 * exist, an empty PersistableBundle is returned. 1943 */ 1944 @NonNull getAppMetadata()1945 public PersistableBundle getAppMetadata() { 1946 PersistableBundle data = null; 1947 try { 1948 ParcelFileDescriptor pfd = mSession.getAppMetadataFd(); 1949 if (pfd != null) { 1950 try (InputStream inputStream = 1951 new ParcelFileDescriptor.AutoCloseInputStream(pfd)) { 1952 data = PersistableBundle.readFromStream(inputStream); 1953 } 1954 } 1955 } catch (RemoteException e) { 1956 e.rethrowFromSystemServer(); 1957 } catch (IOException e) { 1958 throw new RuntimeException(e); 1959 } 1960 return data != null ? data : new PersistableBundle(); 1961 } 1962 openWriteAppMetadata()1963 private OutputStream openWriteAppMetadata() throws IOException { 1964 try { 1965 if (ENABLE_REVOCABLE_FD) { 1966 return new ParcelFileDescriptor.AutoCloseOutputStream( 1967 mSession.openWriteAppMetadata()); 1968 } else { 1969 final ParcelFileDescriptor clientSocket = mSession.openWriteAppMetadata(); 1970 return new FileBridge.FileBridgeOutputStream(clientSocket); 1971 } 1972 } catch (RuntimeException e) { 1973 ExceptionUtils.maybeUnwrapIOException(e); 1974 throw e; 1975 } catch (RemoteException e) { 1976 throw e.rethrowFromSystemServer(); 1977 } 1978 } 1979 1980 /** 1981 * Optionally set the app metadata. The size of this data cannot exceed the maximum allowed. 1982 * Any existing data from the previous install will not be retained even if no data is set 1983 * for the current install session. Setting data to null or an empty PersistableBundle will 1984 * remove any metadata that has previously been set in the same session. 1985 * 1986 * @param data a PersistableBundle containing the app metadata. 1987 * @throws IOException if writing the data fails. 1988 */ setAppMetadata(@ullable PersistableBundle data)1989 public void setAppMetadata(@Nullable PersistableBundle data) throws IOException { 1990 if (data == null || data.isEmpty()) { 1991 try { 1992 mSession.removeAppMetadata(); 1993 } catch (RemoteException e) { 1994 throw e.rethrowFromSystemServer(); 1995 } 1996 return; 1997 } 1998 Objects.requireNonNull(data); 1999 try (OutputStream outputStream = openWriteAppMetadata()) { 2000 data.writeToStream(outputStream); 2001 } 2002 } 2003 2004 /** 2005 * Attempt to request the approval before committing this session. 2006 * 2007 * For installers that have been granted the 2008 * {@link android.Manifest.permission#REQUEST_INSTALL_PACKAGES REQUEST_INSTALL_PACKAGES} 2009 * permission, they can request the approval from users before 2010 * {@link Session#commit(IntentSender)} is called. This may require user intervention as 2011 * well. When user intervention is required, installers will receive a 2012 * {@link #STATUS_PENDING_USER_ACTION} callback, and {@link #STATUS_SUCCESS} otherwise. 2013 * In case that requesting user pre-approval is not available, installers will receive 2014 * {@link #STATUS_FAILURE_BLOCKED} instead. Note that if the users decline the request, 2015 * this session will be abandoned. 2016 * 2017 * If user intervention is required but never resolved, or requesting user 2018 * pre-approval is not available, you may still call {@link Session#commit(IntentSender)} 2019 * as the typical installation. 2020 * 2021 * @param details the adequate context to this session for requesting the approval from 2022 * users prior to commit. 2023 * @param statusReceiver called when the state of the session changes. 2024 * Intents sent to this receiver contain {@link #EXTRA_STATUS} 2025 * and the {@link #EXTRA_PRE_APPROVAL} would be {@code true}. 2026 * Refer to the individual status codes on how to handle them. 2027 * 2028 * @throws IllegalArgumentException when {@link PreapprovalDetails} is {@code null}. 2029 * @throws IllegalArgumentException if {@link IntentSender} is {@code null}. 2030 * @throws IllegalStateException if called on a multi-package session (no matter 2031 * the parent session or any of the children sessions). 2032 * @throws IllegalStateException if called again after this method has been called on 2033 * this session. 2034 * @throws SecurityException when the caller does not own this session. 2035 * @throws SecurityException if called after the session has been committed or abandoned. 2036 */ requestUserPreapproval(@onNull PreapprovalDetails details, @NonNull IntentSender statusReceiver)2037 public void requestUserPreapproval(@NonNull PreapprovalDetails details, 2038 @NonNull IntentSender statusReceiver) { 2039 Preconditions.checkArgument(details != null, "preapprovalDetails cannot be null."); 2040 Preconditions.checkArgument(statusReceiver != null, "statusReceiver cannot be null."); 2041 try { 2042 mSession.requestUserPreapproval(details, statusReceiver); 2043 } catch (RemoteException e) { 2044 e.rethrowFromSystemServer(); 2045 } 2046 } 2047 2048 /** 2049 * @return {@code true} if this session will keep the existing application enabled setting 2050 * after installation. 2051 */ isApplicationEnabledSettingPersistent()2052 public boolean isApplicationEnabledSettingPersistent() { 2053 try { 2054 return mSession.isApplicationEnabledSettingPersistent(); 2055 } catch (RemoteException e) { 2056 throw e.rethrowFromSystemServer(); 2057 } 2058 } 2059 2060 /** 2061 * @return {@code true} if the installer requested the update ownership enforcement 2062 * for the packages in this session. 2063 * 2064 * @see PackageInstaller.SessionParams#setRequestUpdateOwnership 2065 */ isRequestUpdateOwnership()2066 public boolean isRequestUpdateOwnership() { 2067 try { 2068 return mSession.isRequestUpdateOwnership(); 2069 } catch (RemoteException e) { 2070 throw e.rethrowFromSystemServer(); 2071 } 2072 } 2073 } 2074 2075 /** 2076 * Parse a single APK or a directory of APKs to get install relevant information about 2077 * the package wrapped in {@link InstallInfo}. 2078 * @throws PackageParsingException if the package source file(s) provided is(are) not valid, 2079 * or the parser isn't able to parse the supplied source(s). 2080 * @hide 2081 */ 2082 @SystemApi 2083 @NonNull readInstallInfo(@onNull File file, int flags)2084 public InstallInfo readInstallInfo(@NonNull File file, int flags) 2085 throws PackageParsingException { 2086 final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); 2087 final ParseResult<PackageLite> result = ApkLiteParseUtils.parsePackageLite( 2088 input.reset(), file, flags); 2089 if (result.isError()) { 2090 throw new PackageParsingException(result.getErrorCode(), result.getErrorMessage()); 2091 } 2092 return new InstallInfo(result); 2093 } 2094 2095 /** 2096 * Parse a single APK file passed as an FD to get install relevant information about 2097 * the package wrapped in {@link InstallInfo}. 2098 * @throws PackageParsingException if the package source file(s) provided is(are) not valid, 2099 * or the parser isn't able to parse the supplied source(s). 2100 * @hide 2101 */ 2102 @NonNull readInstallInfo(@onNull ParcelFileDescriptor pfd, @Nullable String debugPathName, int flags)2103 public InstallInfo readInstallInfo(@NonNull ParcelFileDescriptor pfd, 2104 @Nullable String debugPathName, int flags) throws PackageParsingException { 2105 final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); 2106 final ParseResult<PackageLite> result = ApkLiteParseUtils.parseMonolithicPackageLite(input, 2107 pfd.getFileDescriptor(), debugPathName, flags); 2108 if (result.isError()) { 2109 throw new PackageParsingException(result.getErrorCode(), result.getErrorMessage()); 2110 } 2111 return new InstallInfo(result); 2112 } 2113 2114 // (b/239722738) This class serves as a bridge between the PackageLite class, which 2115 // is a hidden class, and the consumers of this class. (e.g. InstallInstalling.java) 2116 // This is a part of an effort to remove dependency on hidden APIs and use SystemAPIs or 2117 // public APIs. 2118 /** 2119 * Install related details from an APK or a folder of APK(s). 2120 * 2121 * @hide 2122 */ 2123 @SystemApi 2124 public static class InstallInfo { 2125 2126 /** @hide */ 2127 @IntDef(prefix = { "INSTALL_LOCATION_" }, value = { 2128 INSTALL_LOCATION_AUTO, 2129 INSTALL_LOCATION_INTERNAL_ONLY, 2130 INSTALL_LOCATION_PREFER_EXTERNAL 2131 }) 2132 @Retention(RetentionPolicy.SOURCE) 2133 public @interface InstallLocation{} 2134 2135 private PackageLite mPkg; 2136 InstallInfo(ParseResult<PackageLite> result)2137 InstallInfo(ParseResult<PackageLite> result) { 2138 mPkg = result.getResult(); 2139 } 2140 2141 /** 2142 * See {@link PackageLite#getPackageName()} 2143 */ 2144 @NonNull getPackageName()2145 public String getPackageName() { 2146 return mPkg.getPackageName(); 2147 } 2148 2149 /** 2150 * @return The default install location defined by an application in 2151 * {@link android.R.attr#installLocation} attribute. 2152 */ getInstallLocation()2153 public @InstallLocation int getInstallLocation() { 2154 return mPkg.getInstallLocation(); 2155 } 2156 2157 /** 2158 * @param params {@link SessionParams} of the installation 2159 * @return Total disk space occupied by an application after installation. 2160 * Includes the size of the raw APKs, possibly unpacked resources, raw dex metadata files, 2161 * and all relevant native code. 2162 * @throws IOException when size of native binaries cannot be calculated. 2163 */ calculateInstalledSize(@onNull SessionParams params)2164 public long calculateInstalledSize(@NonNull SessionParams params) throws IOException { 2165 return InstallLocationUtils.calculateInstalledSize(mPkg, params.abiOverride); 2166 } 2167 2168 /** 2169 * @param params {@link SessionParams} of the installation 2170 * @param pfd of an APK opened for read 2171 * @return Total disk space occupied by an application after installation. 2172 * Includes the size of the raw APKs, possibly unpacked resources, raw dex metadata files, 2173 * and all relevant native code. 2174 * @throws IOException when size of native binaries cannot be calculated. 2175 * @hide 2176 */ calculateInstalledSize(@onNull SessionParams params, @NonNull ParcelFileDescriptor pfd)2177 public long calculateInstalledSize(@NonNull SessionParams params, 2178 @NonNull ParcelFileDescriptor pfd) throws IOException { 2179 return InstallLocationUtils.calculateInstalledSize(mPkg, params.abiOverride, 2180 pfd.getFileDescriptor()); 2181 } 2182 } 2183 2184 /** 2185 * Generic exception class for using with parsing operations. 2186 * 2187 * @hide 2188 */ 2189 @SystemApi 2190 public static class PackageParsingException extends Exception { 2191 private final int mErrorCode; 2192 2193 /** {@hide} */ PackageParsingException(int errorCode, @Nullable String detailedMessage)2194 public PackageParsingException(int errorCode, @Nullable String detailedMessage) { 2195 super(detailedMessage); 2196 mErrorCode = errorCode; 2197 } 2198 getErrorCode()2199 public int getErrorCode() { 2200 return mErrorCode; 2201 } 2202 } 2203 2204 /** 2205 * Parameters for creating a new {@link PackageInstaller.Session}. 2206 */ 2207 public static class SessionParams implements Parcelable { 2208 2209 /** {@hide} */ 2210 public static final int MODE_INVALID = -1; 2211 2212 /** 2213 * Mode for an install session whose staged APKs should fully replace any 2214 * existing APKs for the target app. 2215 */ 2216 public static final int MODE_FULL_INSTALL = 1; 2217 2218 /** 2219 * Mode for an install session that should inherit any existing APKs for the 2220 * target app, unless they have been explicitly overridden (based on split 2221 * name) by the session. For example, this can be used to add one or more 2222 * split APKs to an existing installation. 2223 * <p> 2224 * If there are no existing APKs for the target app, this behaves like 2225 * {@link #MODE_FULL_INSTALL}. 2226 */ 2227 public static final int MODE_INHERIT_EXISTING = 2; 2228 2229 /** 2230 * Special constant to refer to all restricted permissions. 2231 */ 2232 public static final @NonNull Set<String> RESTRICTED_PERMISSIONS_ALL = new ArraySet<>(); 2233 2234 /** {@hide} */ 2235 public static final int UID_UNKNOWN = -1; 2236 2237 /** 2238 * This value is derived from the maximum file name length. No package above this limit 2239 * can ever be successfully installed on the device. 2240 * @hide 2241 */ 2242 public static final int MAX_PACKAGE_NAME_LENGTH = 255; 2243 2244 /** @hide */ 2245 @IntDef(prefix = {"USER_ACTION_"}, value = { 2246 USER_ACTION_UNSPECIFIED, 2247 USER_ACTION_REQUIRED, 2248 USER_ACTION_NOT_REQUIRED 2249 }) 2250 @Retention(RetentionPolicy.SOURCE) 2251 public @interface UserActionRequirement {} 2252 2253 /** 2254 * This value is passed by the installer to {@link SessionParams#setRequireUserAction(int)} 2255 * to indicate that user action is unspecified for this install. 2256 * {@code requireUserAction} also defaults to this value unless modified by 2257 * {@link SessionParams#setRequireUserAction(int)} 2258 */ 2259 public static final int USER_ACTION_UNSPECIFIED = 0; 2260 2261 /** 2262 * This value is passed by the installer to {@link SessionParams#setRequireUserAction(int)} 2263 * to indicate that user action is required for this install. 2264 */ 2265 public static final int USER_ACTION_REQUIRED = 1; 2266 2267 /** 2268 * This value is passed by the installer to {@link SessionParams#setRequireUserAction(int)} 2269 * to indicate that user action is not required for this install. 2270 */ 2271 public static final int USER_ACTION_NOT_REQUIRED = 2; 2272 2273 /** @hide */ 2274 @IntDef(prefix = {"PERMISSION_STATE_"}, value = { 2275 PERMISSION_STATE_DEFAULT, 2276 PERMISSION_STATE_GRANTED, 2277 PERMISSION_STATE_DENIED, 2278 }) 2279 @Retention(RetentionPolicy.SOURCE) 2280 public @interface PermissionState {} 2281 2282 /** 2283 * Value is passed by the installer to {@link #setPermissionState(String, int)} to set 2284 * the state of a permission. This indicates no preference by the installer, relying on 2285 * the device's default policy to set the grant state of the permission. 2286 */ 2287 public static final int PERMISSION_STATE_DEFAULT = 0; 2288 2289 /** 2290 * Value is passed by the installer to {@link #setPermissionState(String, int)} to set 2291 * the state of a permission. This indicates the installers wants to automatically grant 2292 * the permission to the package being installed. The user and other actors in the system 2293 * may still be able to deny the permission after installation. 2294 */ 2295 public static final int PERMISSION_STATE_GRANTED = 1; 2296 2297 /** 2298 * Value is passed by the installer to {@link #setPermissionState(String, int)} to set 2299 * the state of a permission. This indicates the installers wants to deny the permission 2300 * by default to the package being installed. The user and other actors in the system may 2301 * still be able to grant the permission after installation. 2302 */ 2303 public static final int PERMISSION_STATE_DENIED = 2; 2304 2305 /** {@hide} */ 2306 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 2307 public int mode = MODE_INVALID; 2308 /** {@hide} */ 2309 @UnsupportedAppUsage 2310 public int installFlags = PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS; 2311 /** {@hide} */ 2312 public int installLocation = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY; 2313 /** {@hide} */ 2314 public @InstallReason int installReason = PackageManager.INSTALL_REASON_UNKNOWN; 2315 /** 2316 * {@hide} 2317 * 2318 * This flag indicates which installation scenario best describes this session. The system 2319 * may use this value when making decisions about how to handle the installation, such as 2320 * prioritizing system health or user experience. 2321 */ 2322 public @InstallScenario int installScenario = PackageManager.INSTALL_SCENARIO_DEFAULT; 2323 /** {@hide} */ 2324 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 2325 public long sizeBytes = -1; 2326 /** {@hide} */ 2327 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 2328 public String appPackageName; 2329 /** {@hide} */ 2330 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 2331 public Bitmap appIcon; 2332 /** {@hide} */ 2333 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 2334 public String appLabel; 2335 /** {@hide} */ 2336 public long appIconLastModified = -1; 2337 /** {@hide} */ 2338 public Uri originatingUri; 2339 /** {@hide} */ 2340 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 2341 public int originatingUid = UID_UNKNOWN; 2342 /** {@hide} */ 2343 public Uri referrerUri; 2344 /** {@hide} */ 2345 public String abiOverride; 2346 /** {@hide} */ 2347 public String volumeUuid; 2348 /** {@hide} */ 2349 public List<String> whitelistedRestrictedPermissions; 2350 /** {@hide} */ 2351 public int autoRevokePermissionsMode = MODE_DEFAULT; 2352 /** {@hide} */ 2353 public String installerPackageName; 2354 /** {@hide} */ 2355 public boolean isMultiPackage; 2356 /** {@hide} */ 2357 public int packageSource = PACKAGE_SOURCE_UNSPECIFIED; 2358 /** {@hide} */ 2359 public boolean isStaged; 2360 /** {@hide} */ 2361 public long requiredInstalledVersionCode = PackageManager.VERSION_CODE_HIGHEST; 2362 /** {@hide} */ 2363 public DataLoaderParams dataLoaderParams; 2364 /** {@hide} */ 2365 public int rollbackDataPolicy = PackageManager.ROLLBACK_DATA_POLICY_RESTORE; 2366 /** {@hide} */ 2367 public boolean forceQueryableOverride; 2368 /** {@hide} */ 2369 public int requireUserAction = USER_ACTION_UNSPECIFIED; 2370 /** {@hide} */ 2371 public boolean applicationEnabledSettingPersistent = false; 2372 2373 private final ArrayMap<String, Integer> mPermissionStates; 2374 2375 /** 2376 * Construct parameters for a new package install session. 2377 * 2378 * @param mode one of {@link #MODE_FULL_INSTALL} or 2379 * {@link #MODE_INHERIT_EXISTING} describing how the session 2380 * should interact with an existing app. 2381 */ SessionParams(int mode)2382 public SessionParams(int mode) { 2383 this.mode = mode; 2384 mPermissionStates = new ArrayMap<>(); 2385 } 2386 2387 /** {@hide} */ SessionParams(Parcel source)2388 public SessionParams(Parcel source) { 2389 mode = source.readInt(); 2390 installFlags = source.readInt(); 2391 installLocation = source.readInt(); 2392 installReason = source.readInt(); 2393 installScenario = source.readInt(); 2394 sizeBytes = source.readLong(); 2395 appPackageName = source.readString(); 2396 appIcon = source.readParcelable(null, android.graphics.Bitmap.class); 2397 appLabel = source.readString(); 2398 originatingUri = source.readParcelable(null, android.net.Uri.class); 2399 originatingUid = source.readInt(); 2400 referrerUri = source.readParcelable(null, android.net.Uri.class); 2401 abiOverride = source.readString(); 2402 volumeUuid = source.readString(); 2403 mPermissionStates = new ArrayMap<>(); 2404 source.readMap(mPermissionStates, null, String.class, Integer.class); 2405 whitelistedRestrictedPermissions = source.createStringArrayList(); 2406 autoRevokePermissionsMode = source.readInt(); 2407 installerPackageName = source.readString(); 2408 isMultiPackage = source.readBoolean(); 2409 isStaged = source.readBoolean(); 2410 forceQueryableOverride = source.readBoolean(); 2411 requiredInstalledVersionCode = source.readLong(); 2412 DataLoaderParamsParcel dataLoaderParamsParcel = source.readParcelable( 2413 DataLoaderParamsParcel.class.getClassLoader(), android.content.pm.DataLoaderParamsParcel.class); 2414 if (dataLoaderParamsParcel != null) { 2415 dataLoaderParams = new DataLoaderParams(dataLoaderParamsParcel); 2416 } 2417 rollbackDataPolicy = source.readInt(); 2418 requireUserAction = source.readInt(); 2419 packageSource = source.readInt(); 2420 applicationEnabledSettingPersistent = source.readBoolean(); 2421 } 2422 2423 /** {@hide} */ copy()2424 public SessionParams copy() { 2425 SessionParams ret = new SessionParams(mode); 2426 ret.installFlags = installFlags; 2427 ret.installLocation = installLocation; 2428 ret.installReason = installReason; 2429 ret.installScenario = installScenario; 2430 ret.sizeBytes = sizeBytes; 2431 ret.appPackageName = appPackageName; 2432 ret.appIcon = appIcon; // not a copy. 2433 ret.appLabel = appLabel; 2434 ret.originatingUri = originatingUri; // not a copy, but immutable. 2435 ret.originatingUid = originatingUid; 2436 ret.referrerUri = referrerUri; // not a copy, but immutable. 2437 ret.abiOverride = abiOverride; 2438 ret.volumeUuid = volumeUuid; 2439 ret.mPermissionStates.putAll(mPermissionStates); 2440 ret.whitelistedRestrictedPermissions = whitelistedRestrictedPermissions; 2441 ret.autoRevokePermissionsMode = autoRevokePermissionsMode; 2442 ret.installerPackageName = installerPackageName; 2443 ret.isMultiPackage = isMultiPackage; 2444 ret.isStaged = isStaged; 2445 ret.forceQueryableOverride = forceQueryableOverride; 2446 ret.requiredInstalledVersionCode = requiredInstalledVersionCode; 2447 ret.dataLoaderParams = dataLoaderParams; 2448 ret.rollbackDataPolicy = rollbackDataPolicy; 2449 ret.requireUserAction = requireUserAction; 2450 ret.packageSource = packageSource; 2451 ret.applicationEnabledSettingPersistent = applicationEnabledSettingPersistent; 2452 return ret; 2453 } 2454 2455 /** 2456 * Check if there are hidden options set. 2457 * 2458 * <p>Hidden options are those options that cannot be verified via public or system-api 2459 * methods on {@link SessionInfo}. 2460 * 2461 * @return {@code true} if any hidden option is set. 2462 * 2463 * @hide 2464 */ areHiddenOptionsSet()2465 public boolean areHiddenOptionsSet() { 2466 return (installFlags & (PackageManager.INSTALL_REQUEST_DOWNGRADE 2467 | PackageManager.INSTALL_ALLOW_DOWNGRADE 2468 | PackageManager.INSTALL_DONT_KILL_APP 2469 | PackageManager.INSTALL_INSTANT_APP 2470 | PackageManager.INSTALL_FULL_APP 2471 | PackageManager.INSTALL_VIRTUAL_PRELOAD 2472 | PackageManager.INSTALL_ALLOCATE_AGGRESSIVE)) != installFlags 2473 || abiOverride != null || volumeUuid != null; 2474 } 2475 2476 /** 2477 * Provide value of {@link PackageInfo#installLocation}, which may be used 2478 * to determine where the app will be staged. Defaults to 2479 * {@link PackageInfo#INSTALL_LOCATION_INTERNAL_ONLY}. 2480 */ setInstallLocation(int installLocation)2481 public void setInstallLocation(int installLocation) { 2482 this.installLocation = installLocation; 2483 } 2484 2485 /** 2486 * Optionally indicate the total size (in bytes) of all APKs that will be 2487 * delivered in this session. The system may use this to ensure enough disk 2488 * space exists before proceeding, or to estimate container size for 2489 * installations living on external storage. 2490 * 2491 * @see PackageInfo#INSTALL_LOCATION_AUTO 2492 * @see PackageInfo#INSTALL_LOCATION_PREFER_EXTERNAL 2493 */ setSize(long sizeBytes)2494 public void setSize(long sizeBytes) { 2495 this.sizeBytes = sizeBytes; 2496 } 2497 2498 /** 2499 * Optionally set the package name of the app being installed. It's strongly 2500 * recommended that you provide this value when known, so that observers can 2501 * communicate installing apps to users. 2502 * <p> 2503 * If the APKs staged in the session aren't consistent with this package 2504 * name, the install will fail. Regardless of this value, all APKs in the 2505 * app must have the same package name. 2506 */ setAppPackageName(@ullable String appPackageName)2507 public void setAppPackageName(@Nullable String appPackageName) { 2508 this.appPackageName = appPackageName; 2509 } 2510 2511 /** 2512 * Optionally set an icon representing the app being installed. This should 2513 * be roughly {@link ActivityManager#getLauncherLargeIconSize()} in both 2514 * dimensions. 2515 */ setAppIcon(@ullable Bitmap appIcon)2516 public void setAppIcon(@Nullable Bitmap appIcon) { 2517 this.appIcon = appIcon; 2518 } 2519 2520 /** 2521 * Optionally set a label representing the app being installed. 2522 * 2523 * This value will be trimmed to the first 1000 characters. 2524 */ setAppLabel(@ullable CharSequence appLabel)2525 public void setAppLabel(@Nullable CharSequence appLabel) { 2526 this.appLabel = (appLabel != null) ? appLabel.toString() : null; 2527 } 2528 2529 /** 2530 * Optionally set the URI where this package was downloaded from. This is 2531 * informational and may be used as a signal for anti-malware purposes. 2532 * 2533 * @see Intent#EXTRA_ORIGINATING_URI 2534 */ setOriginatingUri(@ullable Uri originatingUri)2535 public void setOriginatingUri(@Nullable Uri originatingUri) { 2536 this.originatingUri = originatingUri; 2537 } 2538 2539 /** 2540 * Sets the UID that initiated the package installation. This is informational 2541 * and may be used as a signal for anti-malware purposes. 2542 */ setOriginatingUid(int originatingUid)2543 public void setOriginatingUid(int originatingUid) { 2544 this.originatingUid = originatingUid; 2545 } 2546 2547 /** 2548 * Optionally set the URI that referred you to install this package. This is 2549 * informational and may be used as a signal for anti-malware purposes. 2550 * 2551 * @see Intent#EXTRA_REFERRER 2552 */ setReferrerUri(@ullable Uri referrerUri)2553 public void setReferrerUri(@Nullable Uri referrerUri) { 2554 this.referrerUri = referrerUri; 2555 } 2556 2557 /** 2558 * Sets which runtime permissions to be granted to the package at installation. 2559 * 2560 * @param permissions The permissions to grant or null to grant all runtime 2561 * permissions. 2562 * 2563 * @deprecated Prefer {@link #setPermissionState(String, int)} instead starting in 2564 * {@link Build.VERSION_CODES#UPSIDE_DOWN_CAKE}. 2565 * @hide 2566 */ 2567 @Deprecated 2568 @SystemApi 2569 @RequiresPermission(android.Manifest.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS) setGrantedRuntimePermissions(String[] permissions)2570 public void setGrantedRuntimePermissions(String[] permissions) { 2571 if (permissions == null) { 2572 // The new API has no mechanism to grant all requested permissions 2573 installFlags |= PackageManager.INSTALL_GRANT_ALL_REQUESTED_PERMISSIONS; 2574 mPermissionStates.clear(); 2575 } else { 2576 installFlags &= ~PackageManager.INSTALL_GRANT_ALL_REQUESTED_PERMISSIONS; 2577 // Otherwise call the new API to grant the permissions specified 2578 for (String permission : permissions) { 2579 setPermissionState(permission, PERMISSION_STATE_GRANTED); 2580 } 2581 } 2582 } 2583 2584 /** 2585 * Sets the state of permissions for the package at installation. 2586 * <p/> 2587 * Granting any runtime permissions require the 2588 * {@link android.Manifest.permission#INSTALL_GRANT_RUNTIME_PERMISSIONS 2589 * INSTALL_GRANT_RUNTIME_PERMISSIONS} permission to be held by the caller. Revoking runtime 2590 * permissions is not allowed, even during app update sessions. 2591 * <p/> 2592 * Holders without the permission are allowed to change the following special permissions: 2593 * <p/> 2594 * On platform {@link Build.VERSION_CODES#UPSIDE_DOWN_CAKE UPSIDE_DOWN_CAKE}: 2595 * <ul> 2596 * <li>{@link Manifest.permission#USE_FULL_SCREEN_INTENT}</li> 2597 * </ul> 2598 * Install time permissions, which cannot be revoked by the user, cannot be changed by the 2599 * installer. 2600 * <p/> 2601 * See <a href="https://developer.android.com/guide/topics/permissions/overview"> 2602 * Permissions on Android</a> for more information. 2603 * 2604 * @param permissionName The permission to change state for. 2605 * @param state Either {@link #PERMISSION_STATE_DEFAULT}, 2606 * {@link #PERMISSION_STATE_GRANTED}, 2607 * or {@link #PERMISSION_STATE_DENIED} to set the permission to. 2608 * 2609 * @return This object for easier chaining. 2610 */ 2611 @RequiresPermission(value = android.Manifest.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS, 2612 conditional = true) 2613 @NonNull setPermissionState(@onNull String permissionName, @PermissionState int state)2614 public SessionParams setPermissionState(@NonNull String permissionName, 2615 @PermissionState int state) { 2616 if (TextUtils.isEmpty(permissionName)) { 2617 throw new IllegalArgumentException("Provided permissionName cannot be " 2618 + (permissionName == null ? "null" : "empty")); 2619 } 2620 2621 switch (state) { 2622 case PERMISSION_STATE_DEFAULT: 2623 mPermissionStates.remove(permissionName); 2624 break; 2625 case PERMISSION_STATE_GRANTED: 2626 case PERMISSION_STATE_DENIED: 2627 mPermissionStates.put(permissionName, state); 2628 break; 2629 default: 2630 throw new IllegalArgumentException("Unexpected permission state int: " + state); 2631 } 2632 2633 return this; 2634 } 2635 2636 /** @hide */ setPermissionStates(Collection<String> grantPermissions, Collection<String> denyPermissions)2637 public void setPermissionStates(Collection<String> grantPermissions, 2638 Collection<String> denyPermissions) { 2639 for (String grantPermission : grantPermissions) { 2640 mPermissionStates.put(grantPermission, PERMISSION_STATE_GRANTED); 2641 } 2642 for (String denyPermission : denyPermissions) { 2643 mPermissionStates.put(denyPermission, PERMISSION_STATE_DENIED); 2644 } 2645 } 2646 2647 /** 2648 * Optionally indicate the package source of the app being installed. This is 2649 * informational and may be used as a signal by the system. 2650 * 2651 * An installer should specify {@link #PACKAGE_SOURCE_OTHER} if no other package source 2652 * constant adequately reflects the source for this session. 2653 * 2654 * The default value is {@link #PACKAGE_SOURCE_UNSPECIFIED}. 2655 */ setPackageSource(@ackageSourceType int packageSource)2656 public void setPackageSource(@PackageSourceType int packageSource) { 2657 this.packageSource = packageSource; 2658 } 2659 2660 /** 2661 * Sets which restricted permissions to be allowlisted for the app. Allowlisting 2662 * is not granting the permissions, rather it allows the app to hold permissions 2663 * which are otherwise restricted. Allowlisting a non restricted permission has 2664 * no effect. 2665 * 2666 * <p> Permissions can be hard restricted which means that the app cannot hold 2667 * them or soft restricted where the app can hold the permission but in a weaker 2668 * form. Whether a permission is {@link PermissionInfo#FLAG_HARD_RESTRICTED hard 2669 * restricted} or {@link PermissionInfo#FLAG_SOFT_RESTRICTED soft restricted} 2670 * depends on the permission declaration. Allowlisting a hard restricted permission 2671 * allows the app to hold that permission and allowlisting a soft restricted 2672 * permission allows the app to hold the permission in its full, unrestricted form. 2673 * 2674 * <p> Permissions can also be immutably restricted which means that the allowlist 2675 * state of the permission can be determined only at install time and cannot be 2676 * changed on updated or at a later point via the package manager APIs. 2677 * 2678 * <p>Initially, all restricted permissions are allowlisted but you can change 2679 * which ones are allowlisted by calling this method or the corresponding ones 2680 * on the {@link PackageManager}. Only soft or hard restricted permissions on the current 2681 * Android version are supported and any invalid entries will be removed. 2682 * 2683 * @see PackageManager#addWhitelistedRestrictedPermission(String, String, int) 2684 * @see PackageManager#removeWhitelistedRestrictedPermission(String, String, int) 2685 */ setWhitelistedRestrictedPermissions(@ullable Set<String> permissions)2686 public void setWhitelistedRestrictedPermissions(@Nullable Set<String> permissions) { 2687 if (permissions == RESTRICTED_PERMISSIONS_ALL) { 2688 installFlags |= PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS; 2689 whitelistedRestrictedPermissions = null; 2690 } else { 2691 installFlags &= ~PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS; 2692 whitelistedRestrictedPermissions = (permissions != null) 2693 ? new ArrayList<>(permissions) : null; 2694 } 2695 } 2696 2697 /** 2698 * Sets whether permissions should be auto-revoked if this package is unused for an 2699 * extended periodd of time. 2700 * 2701 * It's disabled by default but generally the installer should enable it for most packages, 2702 * excluding only those where doing so might cause breakage that cannot be easily addressed 2703 * by simply re-requesting the permission(s). 2704 * 2705 * If user explicitly enabled or disabled it via settings, this call is ignored. 2706 * 2707 * @param shouldAutoRevoke whether permissions should be auto-revoked. 2708 * 2709 * @deprecated No longer used 2710 */ 2711 @Deprecated setAutoRevokePermissionsMode(boolean shouldAutoRevoke)2712 public void setAutoRevokePermissionsMode(boolean shouldAutoRevoke) { 2713 autoRevokePermissionsMode = shouldAutoRevoke ? MODE_ALLOWED : MODE_IGNORED; 2714 } 2715 2716 /** 2717 * Request that rollbacks be enabled or disabled for the given upgrade with rollback data 2718 * policy set to RESTORE. 2719 * 2720 * <p>If the parent session is staged or has rollback enabled, all children sessions 2721 * must have the same properties. 2722 * 2723 * @param enable set to {@code true} to enable, {@code false} to disable 2724 * @see SessionParams#setEnableRollback(boolean, int) 2725 * @hide 2726 */ 2727 @SystemApi setEnableRollback(boolean enable)2728 public void setEnableRollback(boolean enable) { 2729 if (enable) { 2730 installFlags |= PackageManager.INSTALL_ENABLE_ROLLBACK; 2731 } else { 2732 installFlags &= ~PackageManager.INSTALL_ENABLE_ROLLBACK; 2733 } 2734 rollbackDataPolicy = PackageManager.ROLLBACK_DATA_POLICY_RESTORE; 2735 } 2736 2737 /** 2738 * Request that rollbacks be enabled or disabled for the given upgrade. 2739 * 2740 * <p>If the parent session is staged or has rollback enabled, all children sessions 2741 * must have the same properties. 2742 * 2743 * <p> For a multi-package install, this method must be called on each child session to 2744 * specify rollback data policies explicitly. Note each child session is allowed to have 2745 * different policies. 2746 * 2747 * @param enable set to {@code true} to enable, {@code false} to disable 2748 * @param dataPolicy the rollback data policy for this session 2749 * @hide 2750 */ 2751 @SystemApi setEnableRollback(boolean enable, @PackageManager.RollbackDataPolicy int dataPolicy)2752 public void setEnableRollback(boolean enable, 2753 @PackageManager.RollbackDataPolicy int dataPolicy) { 2754 if (enable) { 2755 installFlags |= PackageManager.INSTALL_ENABLE_ROLLBACK; 2756 } else { 2757 installFlags &= ~PackageManager.INSTALL_ENABLE_ROLLBACK; 2758 } 2759 rollbackDataPolicy = dataPolicy; 2760 } 2761 2762 2763 /** 2764 * @deprecated use {@link #setRequestDowngrade(boolean)}. 2765 * {@hide} 2766 */ 2767 @SystemApi 2768 @Deprecated setAllowDowngrade(boolean allowDowngrade)2769 public void setAllowDowngrade(boolean allowDowngrade) { 2770 setRequestDowngrade(allowDowngrade); 2771 } 2772 2773 /** {@hide} */ 2774 @SystemApi setRequestDowngrade(boolean requestDowngrade)2775 public void setRequestDowngrade(boolean requestDowngrade) { 2776 if (requestDowngrade) { 2777 installFlags |= PackageManager.INSTALL_REQUEST_DOWNGRADE; 2778 } else { 2779 installFlags &= ~PackageManager.INSTALL_REQUEST_DOWNGRADE; 2780 } 2781 } 2782 2783 /** 2784 * Require the given version of the package be installed. 2785 * The install will only be allowed if the existing version code of 2786 * the package installed on the device matches the given version code. 2787 * Use {@link * PackageManager#VERSION_CODE_HIGHEST} to allow 2788 * installation regardless of the currently installed package version. 2789 * 2790 * @hide 2791 */ setRequiredInstalledVersionCode(long versionCode)2792 public void setRequiredInstalledVersionCode(long versionCode) { 2793 requiredInstalledVersionCode = versionCode; 2794 } 2795 2796 /** {@hide} */ setInstallFlagsForcePermissionPrompt()2797 public void setInstallFlagsForcePermissionPrompt() { 2798 installFlags |= PackageManager.INSTALL_FORCE_PERMISSION_PROMPT; 2799 } 2800 2801 /** 2802 * Requests that the system not kill any of the package's running 2803 * processes as part of a {@link SessionParams#MODE_INHERIT_EXISTING} 2804 * session in which splits being added. By default, all installs will 2805 * result in the package's running processes being killed before the 2806 * install completes. 2807 * 2808 * @param dontKillApp set to {@code true} to request that the processes 2809 * belonging to the package not be killed as part of 2810 * this install. 2811 */ setDontKillApp(boolean dontKillApp)2812 public void setDontKillApp(boolean dontKillApp) { 2813 if (dontKillApp) { 2814 installFlags |= PackageManager.INSTALL_DONT_KILL_APP; 2815 } else { 2816 installFlags &= ~PackageManager.INSTALL_DONT_KILL_APP; 2817 } 2818 } 2819 2820 /** {@hide} */ 2821 @SystemApi setInstallAsInstantApp(boolean isInstantApp)2822 public void setInstallAsInstantApp(boolean isInstantApp) { 2823 if (isInstantApp) { 2824 installFlags |= PackageManager.INSTALL_INSTANT_APP; 2825 installFlags &= ~PackageManager.INSTALL_FULL_APP; 2826 } else { 2827 installFlags &= ~PackageManager.INSTALL_INSTANT_APP; 2828 installFlags |= PackageManager.INSTALL_FULL_APP; 2829 } 2830 } 2831 2832 /** 2833 * Sets the install as a virtual preload. Will only have effect when called 2834 * by the verifier. 2835 * {@hide} 2836 */ 2837 @SystemApi setInstallAsVirtualPreload()2838 public void setInstallAsVirtualPreload() { 2839 installFlags |= PackageManager.INSTALL_VIRTUAL_PRELOAD; 2840 } 2841 2842 /** 2843 * Set the reason for installing this package. 2844 * <p> 2845 * The install reason should be a pre-defined integer. The behavior is 2846 * undefined if other values are used. 2847 * 2848 * @see PackageManager#INSTALL_REASON_UNKNOWN 2849 * @see PackageManager#INSTALL_REASON_POLICY 2850 * @see PackageManager#INSTALL_REASON_DEVICE_RESTORE 2851 * @see PackageManager#INSTALL_REASON_DEVICE_SETUP 2852 * @see PackageManager#INSTALL_REASON_USER 2853 */ setInstallReason(@nstallReason int installReason)2854 public void setInstallReason(@InstallReason int installReason) { 2855 this.installReason = installReason; 2856 } 2857 2858 /** {@hide} */ 2859 @SystemApi 2860 @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE) setAllocateAggressive(boolean allocateAggressive)2861 public void setAllocateAggressive(boolean allocateAggressive) { 2862 if (allocateAggressive) { 2863 installFlags |= PackageManager.INSTALL_ALLOCATE_AGGRESSIVE; 2864 } else { 2865 installFlags &= ~PackageManager.INSTALL_ALLOCATE_AGGRESSIVE; 2866 } 2867 } 2868 2869 /** 2870 * @hide 2871 */ 2872 @TestApi setInstallFlagAllowTest()2873 public void setInstallFlagAllowTest() { 2874 installFlags |= PackageManager.INSTALL_ALLOW_TEST; 2875 } 2876 2877 /** 2878 * Set the installer package for the app. 2879 * 2880 * By default this is the app that created the {@link PackageInstaller} object. 2881 * 2882 * @param installerPackageName name of the installer package 2883 */ setInstallerPackageName(@ullable String installerPackageName)2884 public void setInstallerPackageName(@Nullable String installerPackageName) { 2885 this.installerPackageName = installerPackageName; 2886 } 2887 2888 /** 2889 * Set this session to be the parent of a multi-package install. 2890 * 2891 * A multi-package install session contains no APKs and only references other install 2892 * sessions via ID. When a multi-package session is committed, all of its children 2893 * are committed to the system in an atomic manner. If any children fail to install, 2894 * all of them do, including the multi-package session. 2895 */ setMultiPackage()2896 public void setMultiPackage() { 2897 this.isMultiPackage = true; 2898 } 2899 2900 /** 2901 * Set this session to be staged to be installed at reboot. 2902 * 2903 * Staged sessions are scheduled to be installed at next reboot. Staged sessions can also be 2904 * multi-package. In that case, if any of the children sessions fail to install at reboot, 2905 * all the other children sessions are aborted as well. 2906 * 2907 * <p>If the parent session is staged or has rollback enabled, all children sessions 2908 * must have the same properties. 2909 * 2910 * {@hide} 2911 */ 2912 @SystemApi 2913 @RequiresPermission(Manifest.permission.INSTALL_PACKAGES) setStaged()2914 public void setStaged() { 2915 this.isStaged = true; 2916 } 2917 2918 /** 2919 * Set this session to be installing an APEX package. 2920 * 2921 * {@hide} 2922 */ 2923 @SystemApi 2924 @RequiresPermission(Manifest.permission.INSTALL_PACKAGES) setInstallAsApex()2925 public void setInstallAsApex() { 2926 installFlags |= PackageManager.INSTALL_APEX; 2927 } 2928 2929 /** @hide */ getEnableRollback()2930 public boolean getEnableRollback() { 2931 return (installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0; 2932 } 2933 2934 /** 2935 * Set the data loader params for the session. 2936 * This also switches installation into data loading mode and disallow direct writes into 2937 * staging folder. 2938 * 2939 * @see android.service.dataloader.DataLoaderService.DataLoader 2940 * 2941 * {@hide} 2942 */ 2943 @SystemApi 2944 @RequiresPermission(allOf = { 2945 Manifest.permission.INSTALL_PACKAGES, 2946 Manifest.permission.USE_INSTALLER_V2}) setDataLoaderParams(@onNull DataLoaderParams dataLoaderParams)2947 public void setDataLoaderParams(@NonNull DataLoaderParams dataLoaderParams) { 2948 this.dataLoaderParams = dataLoaderParams; 2949 } 2950 2951 /** 2952 * 2953 * {@hide} 2954 */ setForceQueryable()2955 public void setForceQueryable() { 2956 this.forceQueryableOverride = true; 2957 } 2958 2959 /** 2960 * Optionally indicate whether user action should be required when the session is 2961 * committed. 2962 * <p> 2963 * Defaults to {@link #USER_ACTION_UNSPECIFIED} unless otherwise set. When unspecified for 2964 * installers using the 2965 * {@link android.Manifest.permission#REQUEST_INSTALL_PACKAGES REQUEST_INSTALL_PACKAGES} 2966 * permission will behave as if set to {@link #USER_ACTION_REQUIRED}, and 2967 * {@link #USER_ACTION_NOT_REQUIRED} otherwise. When {@code requireUserAction} is set to 2968 * {@link #USER_ACTION_REQUIRED}, installers will receive a 2969 * {@link #STATUS_PENDING_USER_ACTION} callback once the session is committed, indicating 2970 * that user action is required for the install to proceed. 2971 * <p> 2972 * For installers that have been granted the 2973 * {@link android.Manifest.permission#REQUEST_INSTALL_PACKAGES REQUEST_INSTALL_PACKAGES} 2974 * permission, user action will not be required when all of the following conditions are 2975 * met: 2976 * 2977 * <ul> 2978 * <li>{@code requireUserAction} is set to {@link #USER_ACTION_NOT_REQUIRED}.</li> 2979 * <li>The app being installed targets: 2980 * <ul> 2981 * <li>{@link android.os.Build.VERSION_CODES#Q API 29} or higher on 2982 * Android S ({@link android.os.Build.VERSION_CODES#S API 31})</li> 2983 * <li>{@link android.os.Build.VERSION_CODES#R API 30} or higher on 2984 * Android T ({@link android.os.Build.VERSION_CODES#TIRAMISU API 33})</li> 2985 * <li>{@link android.os.Build.VERSION_CODES#S API 31} or higher <b>after</b> 2986 * Android T ({@link android.os.Build.VERSION_CODES#TIRAMISU API 33})</li> 2987 * </ul> 2988 * </li> 2989 * <li>The installer is: 2990 * <ul> 2991 * <li>The {@link InstallSourceInfo#getUpdateOwnerPackageName() update owner} 2992 * of an existing version of the app (in other words, this install session is 2993 * an app update) if the update ownership enforcement is enabled.</li> 2994 * <li>The 2995 * {@link InstallSourceInfo#getInstallingPackageName() installer of record} 2996 * of an existing version of the app (in other words, this install 2997 * session is an app update) if the update ownership enforcement isn't 2998 * enabled.</li> 2999 * <li>Updating itself.</li> 3000 * </ul> 3001 * </li> 3002 * <li>The installer declares the 3003 * {@link android.Manifest.permission#UPDATE_PACKAGES_WITHOUT_USER_ACTION 3004 * UPDATE_PACKAGES_WITHOUT_USER_ACTION} permission.</li> 3005 * </ul> 3006 * <p> 3007 * Note: The target API level requirement will advance in future Android versions. 3008 * Session owners should always be prepared to handle {@link #STATUS_PENDING_USER_ACTION}. 3009 * 3010 * @param requireUserAction whether user action should be required. 3011 */ setRequireUserAction( @essionParams.UserActionRequirement int requireUserAction)3012 public void setRequireUserAction( 3013 @SessionParams.UserActionRequirement int requireUserAction) { 3014 if (requireUserAction != USER_ACTION_UNSPECIFIED 3015 && requireUserAction != USER_ACTION_REQUIRED 3016 && requireUserAction != USER_ACTION_NOT_REQUIRED) { 3017 throw new IllegalArgumentException("requireUserAction set as invalid value of " 3018 + requireUserAction + ", but must be one of [" 3019 + "USER_ACTION_UNSPECIFIED, USER_ACTION_REQUIRED, USER_ACTION_NOT_REQUIRED" 3020 + "]"); 3021 } 3022 this.requireUserAction = requireUserAction; 3023 } 3024 3025 /** 3026 * Sets the install scenario for this session, which describes the expected user journey. 3027 */ setInstallScenario(@nstallScenario int installScenario)3028 public void setInstallScenario(@InstallScenario int installScenario) { 3029 this.installScenario = installScenario; 3030 } 3031 3032 /** 3033 * Request to keep the original application enabled setting. This will prevent the 3034 * application from being enabled if it was previously in a disabled state. 3035 */ setApplicationEnabledSettingPersistent()3036 public void setApplicationEnabledSettingPersistent() { 3037 this.applicationEnabledSettingPersistent = true; 3038 } 3039 3040 /** 3041 * Optionally indicate whether the package being installed needs the update ownership 3042 * enforcement. Once the update ownership enforcement is enabled, the other installers 3043 * will need the user action to update the package even if the installers have been 3044 * granted the {@link android.Manifest.permission#INSTALL_PACKAGES INSTALL_PACKAGES} 3045 * permission. Default to {@code false}. 3046 * 3047 * The update ownership enforcement can only be enabled on initial installation. Set 3048 * this to {@code true} on package update is a no-op. 3049 * 3050 * Note: To enable the update ownership enforcement, the installer must have the 3051 * {@link android.Manifest.permission#ENFORCE_UPDATE_OWNERSHIP ENFORCE_UPDATE_OWNERSHIP} 3052 * permission. 3053 */ 3054 @RequiresPermission(Manifest.permission.ENFORCE_UPDATE_OWNERSHIP) setRequestUpdateOwnership(boolean enable)3055 public void setRequestUpdateOwnership(boolean enable) { 3056 if (enable) { 3057 this.installFlags |= PackageManager.INSTALL_REQUEST_UPDATE_OWNERSHIP; 3058 } else { 3059 this.installFlags &= ~PackageManager.INSTALL_REQUEST_UPDATE_OWNERSHIP; 3060 } 3061 } 3062 3063 /** @hide */ 3064 @NonNull getPermissionStates()3065 public ArrayMap<String, Integer> getPermissionStates() { 3066 return mPermissionStates; 3067 } 3068 3069 /** @hide */ 3070 @Nullable getLegacyGrantedRuntimePermissions()3071 public String[] getLegacyGrantedRuntimePermissions() { 3072 if ((installFlags & PackageManager.INSTALL_GRANT_ALL_REQUESTED_PERMISSIONS) != 0) { 3073 return null; 3074 } 3075 3076 var grantedPermissions = new ArrayList<String>(); 3077 for (int index = 0; index < mPermissionStates.size(); index++) { 3078 var permissionName = mPermissionStates.keyAt(index); 3079 var state = mPermissionStates.valueAt(index); 3080 if (state == PERMISSION_STATE_GRANTED) { 3081 grantedPermissions.add(permissionName); 3082 } 3083 } 3084 3085 return grantedPermissions.toArray(ArrayUtils.emptyArray(String.class)); 3086 } 3087 3088 /** {@hide} */ dump(IndentingPrintWriter pw)3089 public void dump(IndentingPrintWriter pw) { 3090 pw.printPair("mode", mode); 3091 pw.printHexPair("installFlags", installFlags); 3092 pw.printPair("installLocation", installLocation); 3093 pw.printPair("installReason", installReason); 3094 pw.printPair("installScenario", installScenario); 3095 pw.printPair("sizeBytes", sizeBytes); 3096 pw.printPair("appPackageName", appPackageName); 3097 pw.printPair("appIcon", (appIcon != null)); 3098 pw.printPair("appLabel", appLabel); 3099 pw.printPair("originatingUri", originatingUri); 3100 pw.printPair("originatingUid", originatingUid); 3101 pw.printPair("referrerUri", referrerUri); 3102 pw.printPair("abiOverride", abiOverride); 3103 pw.printPair("volumeUuid", volumeUuid); 3104 pw.printPair("mPermissionStates", mPermissionStates); 3105 pw.printPair("packageSource", packageSource); 3106 pw.printPair("whitelistedRestrictedPermissions", whitelistedRestrictedPermissions); 3107 pw.printPair("autoRevokePermissions", autoRevokePermissionsMode); 3108 pw.printPair("installerPackageName", installerPackageName); 3109 pw.printPair("isMultiPackage", isMultiPackage); 3110 pw.printPair("isStaged", isStaged); 3111 pw.printPair("forceQueryable", forceQueryableOverride); 3112 pw.printPair("requireUserAction", SessionInfo.userActionToString(requireUserAction)); 3113 pw.printPair("requiredInstalledVersionCode", requiredInstalledVersionCode); 3114 pw.printPair("dataLoaderParams", dataLoaderParams); 3115 pw.printPair("rollbackDataPolicy", rollbackDataPolicy); 3116 pw.printPair("applicationEnabledSettingPersistent", 3117 applicationEnabledSettingPersistent); 3118 pw.println(); 3119 } 3120 3121 @Override describeContents()3122 public int describeContents() { 3123 return 0; 3124 } 3125 3126 @Override writeToParcel(Parcel dest, int flags)3127 public void writeToParcel(Parcel dest, int flags) { 3128 dest.writeInt(mode); 3129 dest.writeInt(installFlags); 3130 dest.writeInt(installLocation); 3131 dest.writeInt(installReason); 3132 dest.writeInt(installScenario); 3133 dest.writeLong(sizeBytes); 3134 dest.writeString(appPackageName); 3135 dest.writeParcelable(appIcon, flags); 3136 dest.writeString(appLabel); 3137 dest.writeParcelable(originatingUri, flags); 3138 dest.writeInt(originatingUid); 3139 dest.writeParcelable(referrerUri, flags); 3140 dest.writeString(abiOverride); 3141 dest.writeString(volumeUuid); 3142 dest.writeMap(mPermissionStates); 3143 dest.writeStringList(whitelistedRestrictedPermissions); 3144 dest.writeInt(autoRevokePermissionsMode); 3145 dest.writeString(installerPackageName); 3146 dest.writeBoolean(isMultiPackage); 3147 dest.writeBoolean(isStaged); 3148 dest.writeBoolean(forceQueryableOverride); 3149 dest.writeLong(requiredInstalledVersionCode); 3150 if (dataLoaderParams != null) { 3151 dest.writeParcelable(dataLoaderParams.getData(), flags); 3152 } else { 3153 dest.writeParcelable(null, flags); 3154 } 3155 dest.writeInt(rollbackDataPolicy); 3156 dest.writeInt(requireUserAction); 3157 dest.writeInt(packageSource); 3158 dest.writeBoolean(applicationEnabledSettingPersistent); 3159 } 3160 3161 public static final Parcelable.Creator<SessionParams> 3162 CREATOR = new Parcelable.Creator<SessionParams>() { 3163 @Override 3164 public SessionParams createFromParcel(Parcel p) { 3165 return new SessionParams(p); 3166 } 3167 3168 @Override 3169 public SessionParams[] newArray(int size) { 3170 return new SessionParams[size]; 3171 } 3172 }; 3173 } 3174 3175 /** 3176 * Details for an active install session. 3177 */ 3178 public static class SessionInfo implements Parcelable { 3179 3180 /** 3181 * A session ID that does not exist or is invalid. 3182 */ 3183 public static final int INVALID_ID = -1; 3184 /** {@hide} */ 3185 private static final int[] NO_SESSIONS = {}; 3186 3187 /** 3188 * @deprecated use {@link #SESSION_NO_ERROR}. 3189 */ 3190 @Deprecated 3191 public static final int STAGED_SESSION_NO_ERROR = 0; 3192 3193 /** 3194 * @deprecated use {@link #SESSION_VERIFICATION_FAILED}. 3195 */ 3196 @Deprecated 3197 public static final int STAGED_SESSION_VERIFICATION_FAILED = 1; 3198 3199 /** 3200 * @deprecated use {@link #SESSION_ACTIVATION_FAILED}. 3201 */ 3202 @Deprecated 3203 public static final int STAGED_SESSION_ACTIVATION_FAILED = 2; 3204 3205 /** 3206 * @deprecated use {@link #SESSION_UNKNOWN_ERROR}. 3207 */ 3208 @Deprecated 3209 public static final int STAGED_SESSION_UNKNOWN = 3; 3210 3211 /** 3212 * @deprecated use {@link #SESSION_CONFLICT}. 3213 */ 3214 @Deprecated 3215 public static final int STAGED_SESSION_CONFLICT = 4; 3216 3217 /** 3218 * Constant indicating that no error occurred during the preparation or the activation of 3219 * this session. 3220 */ 3221 public static final int SESSION_NO_ERROR = 0; 3222 3223 /** 3224 * Constant indicating that an error occurred during the verification phase of 3225 * this session. 3226 */ 3227 public static final int SESSION_VERIFICATION_FAILED = 1; 3228 3229 /** 3230 * Constant indicating that an error occurred during the activation phase of 3231 * this session. 3232 */ 3233 public static final int SESSION_ACTIVATION_FAILED = 2; 3234 3235 /** 3236 * Constant indicating that an unknown error occurred while processing this session. 3237 */ 3238 public static final int SESSION_UNKNOWN_ERROR = 3; 3239 3240 /** 3241 * Constant indicating that the session was in conflict with another session and had 3242 * to be sacrificed for resolution. 3243 */ 3244 public static final int SESSION_CONFLICT = 4; 3245 userActionToString(int requireUserAction)3246 private static String userActionToString(int requireUserAction) { 3247 switch(requireUserAction) { 3248 case SessionParams.USER_ACTION_REQUIRED: 3249 return "REQUIRED"; 3250 case SessionParams.USER_ACTION_NOT_REQUIRED: 3251 return "NOT_REQUIRED"; 3252 default: 3253 return "UNSPECIFIED"; 3254 } 3255 } 3256 3257 /** {@hide} */ 3258 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 3259 public int sessionId; 3260 /** {@hide} */ 3261 public int userId; 3262 /** {@hide} */ 3263 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 3264 public String installerPackageName; 3265 /** {@hide} */ 3266 public String installerAttributionTag; 3267 /** {@hide} */ 3268 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 3269 public String resolvedBaseCodePath; 3270 /** {@hide} */ 3271 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 3272 public float progress; 3273 /** {@hide} */ 3274 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 3275 public boolean sealed; 3276 /** {@hide} */ 3277 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 3278 public boolean active; 3279 3280 /** {@hide} */ 3281 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 3282 public int mode; 3283 /** {@hide} */ 3284 public @InstallReason int installReason; 3285 /** {@hide} */ 3286 public @InstallScenario int installScenario; 3287 /** {@hide} */ 3288 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 3289 public long sizeBytes; 3290 /** {@hide} */ 3291 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 3292 public String appPackageName; 3293 /** {@hide} */ 3294 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 3295 public Bitmap appIcon; 3296 /** {@hide} */ 3297 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 3298 public CharSequence appLabel; 3299 3300 /** {@hide} */ 3301 public int installLocation; 3302 /** {@hide} */ 3303 public Uri originatingUri; 3304 /** {@hide} */ 3305 public int originatingUid; 3306 /** {@hide} */ 3307 public Uri referrerUri; 3308 /** {@hide} */ 3309 public String[] grantedRuntimePermissions; 3310 /** {@hide}*/ 3311 public List<String> whitelistedRestrictedPermissions; 3312 /** {@hide}*/ 3313 public int autoRevokePermissionsMode = MODE_DEFAULT; 3314 /** {@hide} */ 3315 public int installFlags; 3316 /** {@hide} */ 3317 public boolean isMultiPackage; 3318 /** {@hide} */ 3319 public boolean isStaged; 3320 /** {@hide} */ 3321 public boolean forceQueryable; 3322 /** {@hide} */ 3323 public int parentSessionId = INVALID_ID; 3324 /** {@hide} */ 3325 public int[] childSessionIds = NO_SESSIONS; 3326 3327 /** {@hide} */ 3328 public boolean isSessionApplied; 3329 /** {@hide} */ 3330 public boolean isSessionReady; 3331 /** {@hide} */ 3332 public boolean isSessionFailed; 3333 private int mSessionErrorCode; 3334 private String mSessionErrorMessage; 3335 3336 /** {@hide} */ 3337 public boolean isCommitted; 3338 3339 /** {@hide} */ 3340 public long createdMillis; 3341 3342 /** {@hide} */ 3343 public long updatedMillis; 3344 3345 /** {@hide} */ 3346 public int rollbackDataPolicy; 3347 3348 /** {@hide} */ 3349 public int requireUserAction; 3350 3351 /** {@hide} */ 3352 public int packageSource = PACKAGE_SOURCE_UNSPECIFIED; 3353 3354 /** {@hide} */ 3355 public int installerUid; 3356 3357 /** @hide */ 3358 public boolean isPreapprovalRequested; 3359 3360 /** @hide */ 3361 public boolean applicationEnabledSettingPersistent; 3362 3363 /** @hide */ 3364 public int pendingUserActionReason; 3365 3366 /** {@hide} */ 3367 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) SessionInfo()3368 public SessionInfo() { 3369 } 3370 3371 /** {@hide} */ SessionInfo(Parcel source)3372 public SessionInfo(Parcel source) { 3373 sessionId = source.readInt(); 3374 userId = source.readInt(); 3375 installerPackageName = source.readString(); 3376 installerAttributionTag = source.readString(); 3377 resolvedBaseCodePath = source.readString(); 3378 progress = source.readFloat(); 3379 sealed = source.readInt() != 0; 3380 active = source.readInt() != 0; 3381 3382 mode = source.readInt(); 3383 installReason = source.readInt(); 3384 installScenario = source.readInt(); 3385 sizeBytes = source.readLong(); 3386 appPackageName = source.readString(); 3387 appIcon = source.readParcelable(null, android.graphics.Bitmap.class); 3388 appLabel = source.readString(); 3389 3390 installLocation = source.readInt(); 3391 originatingUri = source.readParcelable(null, android.net.Uri.class); 3392 originatingUid = source.readInt(); 3393 referrerUri = source.readParcelable(null, android.net.Uri.class); 3394 grantedRuntimePermissions = source.readStringArray(); 3395 whitelistedRestrictedPermissions = source.createStringArrayList(); 3396 autoRevokePermissionsMode = source.readInt(); 3397 3398 installFlags = source.readInt(); 3399 isMultiPackage = source.readBoolean(); 3400 isStaged = source.readBoolean(); 3401 forceQueryable = source.readBoolean(); 3402 parentSessionId = source.readInt(); 3403 childSessionIds = source.createIntArray(); 3404 if (childSessionIds == null) { 3405 childSessionIds = NO_SESSIONS; 3406 } 3407 isSessionApplied = source.readBoolean(); 3408 isSessionReady = source.readBoolean(); 3409 isSessionFailed = source.readBoolean(); 3410 mSessionErrorCode = source.readInt(); 3411 mSessionErrorMessage = source.readString(); 3412 isCommitted = source.readBoolean(); 3413 isPreapprovalRequested = source.readBoolean(); 3414 rollbackDataPolicy = source.readInt(); 3415 createdMillis = source.readLong(); 3416 requireUserAction = source.readInt(); 3417 installerUid = source.readInt(); 3418 packageSource = source.readInt(); 3419 applicationEnabledSettingPersistent = source.readBoolean(); 3420 pendingUserActionReason = source.readInt(); 3421 } 3422 3423 /** 3424 * Return the ID for this session. 3425 */ getSessionId()3426 public int getSessionId() { 3427 return sessionId; 3428 } 3429 3430 /** 3431 * Return the user associated with this session. 3432 */ getUser()3433 public @NonNull UserHandle getUser() { 3434 return new UserHandle(userId); 3435 } 3436 3437 /** 3438 * Return the package name of the app that owns this session. 3439 */ getInstallerPackageName()3440 public @Nullable String getInstallerPackageName() { 3441 return installerPackageName; 3442 } 3443 3444 /** 3445 * @return {@link android.content.Context#getAttributionTag attribution tag} of the context 3446 * that created this session 3447 */ getInstallerAttributionTag()3448 public @Nullable String getInstallerAttributionTag() { 3449 return installerAttributionTag; 3450 } 3451 3452 /** 3453 * Return current overall progress of this session, between 0 and 1. 3454 * <p> 3455 * Note that this progress may not directly correspond to the value 3456 * reported by 3457 * {@link PackageInstaller.Session#setStagingProgress(float)}, as the 3458 * system may carve out a portion of the overall progress to represent 3459 * its own internal installation work. 3460 */ getProgress()3461 public float getProgress() { 3462 return progress; 3463 } 3464 3465 /** 3466 * Return if this session is currently active. 3467 * <p> 3468 * A session is considered active whenever there is ongoing forward 3469 * progress being made, such as the installer holding an open 3470 * {@link Session} instance while streaming data into place, or the 3471 * system optimizing code as the result of 3472 * {@link Session#commit(IntentSender)}. 3473 * <p> 3474 * If the installer closes the {@link Session} without committing, the 3475 * session is considered inactive until the installer opens the session 3476 * again. 3477 */ isActive()3478 public boolean isActive() { 3479 return active; 3480 } 3481 3482 /** 3483 * Return if this session is sealed. 3484 * <p> 3485 * Once sealed, no further changes may be made to the session. A session 3486 * is sealed the moment {@link Session#commit(IntentSender)} is called. 3487 */ isSealed()3488 public boolean isSealed() { 3489 return sealed; 3490 } 3491 3492 /** 3493 * Return the reason for installing this package. 3494 * 3495 * @return The install reason. 3496 */ getInstallReason()3497 public @InstallReason int getInstallReason() { 3498 return installReason; 3499 } 3500 3501 /** {@hide} */ 3502 @Deprecated isOpen()3503 public boolean isOpen() { 3504 return isActive(); 3505 } 3506 3507 /** 3508 * Return the package name this session is working with. May be {@code null} 3509 * if unknown. 3510 */ getAppPackageName()3511 public @Nullable String getAppPackageName() { 3512 return appPackageName; 3513 } 3514 3515 /** 3516 * Return an icon representing the app being installed. May be {@code null} 3517 * if unavailable. 3518 */ getAppIcon()3519 public @Nullable Bitmap getAppIcon() { 3520 if (appIcon == null) { 3521 // Icon may have been omitted for calls that return bulk session 3522 // lists, so try fetching the specific icon. 3523 try { 3524 final SessionInfo info = AppGlobals.getPackageManager().getPackageInstaller() 3525 .getSessionInfo(sessionId); 3526 appIcon = (info != null) ? info.appIcon : null; 3527 } catch (RemoteException e) { 3528 throw e.rethrowFromSystemServer(); 3529 } 3530 } 3531 return appIcon; 3532 } 3533 3534 /** 3535 * Return a label representing the app being installed. May be {@code null} 3536 * if unavailable. 3537 */ getAppLabel()3538 public @Nullable CharSequence getAppLabel() { 3539 return appLabel; 3540 } 3541 3542 /** 3543 * Return an Intent that can be started to view details about this install 3544 * session. This may surface actions such as pause, resume, or cancel. 3545 * <p> 3546 * In some cases, a matching Activity may not exist, so ensure you safeguard 3547 * against this. 3548 * 3549 * @see PackageInstaller#ACTION_SESSION_DETAILS 3550 */ createDetailsIntent()3551 public @Nullable Intent createDetailsIntent() { 3552 final Intent intent = new Intent(PackageInstaller.ACTION_SESSION_DETAILS); 3553 intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId); 3554 intent.setPackage(installerPackageName); 3555 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 3556 return intent; 3557 } 3558 3559 /** 3560 * Get the mode of the session as set in the constructor of the {@link SessionParams}. 3561 * 3562 * @return One of {@link SessionParams#MODE_FULL_INSTALL} 3563 * or {@link SessionParams#MODE_INHERIT_EXISTING} 3564 */ getMode()3565 public int getMode() { 3566 return mode; 3567 } 3568 3569 /** 3570 * Get the value set in {@link SessionParams#setInstallLocation(int)}. 3571 */ getInstallLocation()3572 public int getInstallLocation() { 3573 return installLocation; 3574 } 3575 3576 /** 3577 * Get the value as set in {@link SessionParams#setSize(long)}. 3578 * 3579 * <p>The value is a hint and does not have to match the actual size. 3580 */ getSize()3581 public long getSize() { 3582 return sizeBytes; 3583 } 3584 3585 /** 3586 * Get the value set in {@link SessionParams#setOriginatingUri(Uri)}. 3587 * Note: This value will only be non-null for the owner of the session. 3588 */ getOriginatingUri()3589 public @Nullable Uri getOriginatingUri() { 3590 return originatingUri; 3591 } 3592 3593 /** 3594 * Get the value set in {@link SessionParams#setOriginatingUid(int)}. 3595 */ getOriginatingUid()3596 public int getOriginatingUid() { 3597 return originatingUid; 3598 } 3599 3600 /** 3601 * Get the value set in {@link SessionParams#setReferrerUri(Uri)} 3602 * Note: This value will only be non-null for the owner of the session. 3603 */ getReferrerUri()3604 public @Nullable Uri getReferrerUri() { 3605 return referrerUri; 3606 } 3607 3608 /** 3609 * @return the path to the validated base APK for this session, which may point at an 3610 * APK inside the session (when the session defines the base), or it may 3611 * point at the existing base APK (when adding splits to an existing app). 3612 * 3613 * @hide 3614 */ 3615 @RequiresPermission(Manifest.permission.READ_INSTALLED_SESSION_PATHS) getResolvedBaseApkPath()3616 public @Nullable String getResolvedBaseApkPath() { 3617 return resolvedBaseCodePath; 3618 } 3619 3620 /** 3621 * Get the value set in {@link SessionParams#setGrantedRuntimePermissions(String[])}. 3622 * 3623 * @hide 3624 */ 3625 @SystemApi getGrantedRuntimePermissions()3626 public @Nullable String[] getGrantedRuntimePermissions() { 3627 return grantedRuntimePermissions; 3628 } 3629 3630 /** 3631 * Get the value set in {@link SessionParams#setWhitelistedRestrictedPermissions(Set)}. 3632 * Note that if all permissions are allowlisted this method returns {@link 3633 * SessionParams#RESTRICTED_PERMISSIONS_ALL}. 3634 * 3635 * @hide 3636 */ 3637 @SystemApi getWhitelistedRestrictedPermissions()3638 public @NonNull Set<String> getWhitelistedRestrictedPermissions() { 3639 if ((installFlags & PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS) != 0) { 3640 return SessionParams.RESTRICTED_PERMISSIONS_ALL; 3641 } 3642 if (whitelistedRestrictedPermissions != null) { 3643 return new ArraySet<>(whitelistedRestrictedPermissions); 3644 } 3645 return Collections.emptySet(); 3646 } 3647 3648 /** 3649 * Get the status of whether permission auto-revocation should be allowed, ignored, or 3650 * deferred to manifest data. 3651 * 3652 * @see android.app.AppOpsManager#MODE_ALLOWED 3653 * @see android.app.AppOpsManager#MODE_IGNORED 3654 * @see android.app.AppOpsManager#MODE_DEFAULT 3655 * 3656 * @return the status of auto-revoke for this package 3657 * 3658 * @hide 3659 */ 3660 @SystemApi getAutoRevokePermissionsMode()3661 public int getAutoRevokePermissionsMode() { 3662 return autoRevokePermissionsMode; 3663 } 3664 3665 /** 3666 * Get the value set in {@link SessionParams#setAllowDowngrade(boolean)}. 3667 * 3668 * @deprecated use {@link #getRequestDowngrade()}. 3669 * @hide 3670 */ 3671 @SystemApi 3672 @Deprecated getAllowDowngrade()3673 public boolean getAllowDowngrade() { 3674 return getRequestDowngrade(); 3675 } 3676 3677 /** 3678 * Get the value set in {@link SessionParams#setRequestDowngrade(boolean)}. 3679 * 3680 * @hide 3681 */ 3682 @SystemApi getRequestDowngrade()3683 public boolean getRequestDowngrade() { 3684 return (installFlags & PackageManager.INSTALL_REQUEST_DOWNGRADE) != 0; 3685 } 3686 3687 /** 3688 * Get the value set in {@link SessionParams#setDontKillApp(boolean)}. 3689 */ getDontKillApp()3690 public boolean getDontKillApp() { 3691 return (installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0; 3692 } 3693 3694 /** 3695 * Get if this session is to be installed as Instant Apps. 3696 * 3697 * @param isInstantApp an unused parameter and is ignored. 3698 * @return {@code true} if {@link SessionParams#setInstallAsInstantApp(boolean)} was called 3699 * with {@code true}; {@code false} if it was called with {@code false} or if it was not 3700 * called. 3701 * 3702 * @see #getInstallAsFullApp 3703 * 3704 * @hide 3705 */ 3706 @SystemApi getInstallAsInstantApp(boolean isInstantApp)3707 public boolean getInstallAsInstantApp(boolean isInstantApp) { 3708 return (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0; 3709 } 3710 3711 /** 3712 * Get if this session is to be installed as full apps. 3713 * 3714 * @param isInstantApp an unused parameter and is ignored. 3715 * @return {@code true} if {@link SessionParams#setInstallAsInstantApp(boolean)} was called 3716 * with {@code false}; {code false} if it was called with {@code true} or if it was not 3717 * called. 3718 * 3719 * @see #getInstallAsInstantApp 3720 * 3721 * @hide 3722 */ 3723 @SystemApi getInstallAsFullApp(boolean isInstantApp)3724 public boolean getInstallAsFullApp(boolean isInstantApp) { 3725 return (installFlags & PackageManager.INSTALL_FULL_APP) != 0; 3726 } 3727 3728 /** 3729 * Get if {@link SessionParams#setInstallAsVirtualPreload()} was called. 3730 * 3731 * @hide 3732 */ 3733 @SystemApi getInstallAsVirtualPreload()3734 public boolean getInstallAsVirtualPreload() { 3735 return (installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0; 3736 } 3737 3738 /** 3739 * Return whether rollback is enabled or disabled for the given upgrade. 3740 * 3741 * @hide 3742 */ 3743 @SystemApi getEnableRollback()3744 public boolean getEnableRollback() { 3745 return (installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0; 3746 } 3747 3748 /** 3749 * Get the value set in {@link SessionParams#setAllocateAggressive(boolean)}. 3750 * 3751 * @hide 3752 */ 3753 @SystemApi getAllocateAggressive()3754 public boolean getAllocateAggressive() { 3755 return (installFlags & PackageManager.INSTALL_ALLOCATE_AGGRESSIVE) != 0; 3756 } 3757 3758 3759 /** {@hide} */ 3760 @Deprecated getDetailsIntent()3761 public @Nullable Intent getDetailsIntent() { 3762 return createDetailsIntent(); 3763 } 3764 3765 /** 3766 * Get the package source that was set in 3767 * {@link PackageInstaller.SessionParams#setPackageSource(int)}. 3768 */ getPackageSource()3769 public @PackageSourceType int getPackageSource() { 3770 return packageSource; 3771 } 3772 3773 /** 3774 * Returns true if this session is a multi-package session containing references to other 3775 * sessions. 3776 */ isMultiPackage()3777 public boolean isMultiPackage() { 3778 return isMultiPackage; 3779 } 3780 3781 /** 3782 * Returns true if this session is a staged session. 3783 */ isStaged()3784 public boolean isStaged() { 3785 return isStaged; 3786 } 3787 3788 /** 3789 * Return the data policy associated with the rollback for the given upgrade. 3790 * 3791 * @hide 3792 */ 3793 @SystemApi 3794 @PackageManager.RollbackDataPolicy getRollbackDataPolicy()3795 public int getRollbackDataPolicy() { 3796 return rollbackDataPolicy; 3797 } 3798 3799 /** 3800 * Returns true if this session is marked as forceQueryable 3801 * {@hide} 3802 */ isForceQueryable()3803 public boolean isForceQueryable() { 3804 return forceQueryable; 3805 } 3806 3807 /** 3808 * Returns {@code true} if this session is an active staged session. 3809 * 3810 * We consider a session active if it has been committed and it is either pending 3811 * verification, or will be applied at next reboot. 3812 * 3813 * <p>Staged session is active iff: 3814 * <ul> 3815 * <li>It is committed, i.e. {@link SessionInfo#isCommitted()} is {@code true}, and 3816 * <li>it is not applied, i.e. {@link SessionInfo#isStagedSessionApplied()} is {@code 3817 * false}, and 3818 * <li>it is not failed, i.e. {@link SessionInfo#isStagedSessionFailed()} is 3819 * {@code false}. 3820 * </ul> 3821 * 3822 * <p>In case of a multi-package session, reasoning above is applied to the parent session, 3823 * since that is the one that should have been {@link Session#commit committed}. 3824 */ isStagedSessionActive()3825 public boolean isStagedSessionActive() { 3826 return isStaged && isCommitted && !isSessionApplied && !isSessionFailed 3827 && !hasParentSessionId(); 3828 } 3829 3830 /** 3831 * Returns the parent multi-package session ID if this session belongs to one, 3832 * {@link #INVALID_ID} otherwise. 3833 */ getParentSessionId()3834 public int getParentSessionId() { 3835 return parentSessionId; 3836 } 3837 3838 /** 3839 * Returns true if session has a valid parent session, otherwise false. 3840 */ hasParentSessionId()3841 public boolean hasParentSessionId() { 3842 return parentSessionId != INVALID_ID; 3843 } 3844 3845 /** 3846 * Returns the set of session IDs that will be committed when this session is committed if 3847 * this session is a multi-package session. 3848 */ 3849 @NonNull getChildSessionIds()3850 public int[] getChildSessionIds() { 3851 return childSessionIds; 3852 } 3853 checkSessionIsStaged()3854 private void checkSessionIsStaged() { 3855 if (!isStaged) { 3856 throw new IllegalStateException("Session is not marked as staged."); 3857 } 3858 } 3859 3860 /** 3861 * Whether the staged session has been applied successfully, meaning that all of its 3862 * packages have been activated and no further action is required. 3863 * Only meaningful if {@code isStaged} is true. 3864 */ isStagedSessionApplied()3865 public boolean isStagedSessionApplied() { 3866 checkSessionIsStaged(); 3867 return isSessionApplied; 3868 } 3869 3870 /** 3871 * Whether the staged session is ready to be applied at next reboot. Only meaningful if 3872 * {@code isStaged} is true. 3873 */ isStagedSessionReady()3874 public boolean isStagedSessionReady() { 3875 checkSessionIsStaged(); 3876 return isSessionReady; 3877 } 3878 3879 /** 3880 * Whether something went wrong and the staged session is declared as failed, meaning that 3881 * it will be ignored at next reboot. Only meaningful if {@code isStaged} is true. 3882 */ isStagedSessionFailed()3883 public boolean isStagedSessionFailed() { 3884 checkSessionIsStaged(); 3885 return isSessionFailed; 3886 } 3887 3888 /** 3889 * If something went wrong with a staged session, clients can check this error code to 3890 * understand which kind of failure happened. Only meaningful if {@code isStaged} is true. 3891 */ getStagedSessionErrorCode()3892 public int getStagedSessionErrorCode() { 3893 checkSessionIsStaged(); 3894 return mSessionErrorCode; 3895 } 3896 3897 /** 3898 * Text description of the error code returned by {@code getStagedSessionErrorCode}, or 3899 * empty string if no error was encountered. 3900 */ getStagedSessionErrorMessage()3901 public @NonNull String getStagedSessionErrorMessage() { 3902 checkSessionIsStaged(); 3903 return mSessionErrorMessage; 3904 } 3905 3906 /** {@hide} */ setSessionErrorCode(int errorCode, String errorMessage)3907 public void setSessionErrorCode(int errorCode, String errorMessage) { 3908 mSessionErrorCode = errorCode; 3909 mSessionErrorMessage = errorMessage; 3910 } 3911 3912 /** 3913 * Returns {@code true} if {@link Session#commit(IntentSender)}} was called for this 3914 * session. 3915 */ isCommitted()3916 public boolean isCommitted() { 3917 return isCommitted; 3918 } 3919 3920 /** 3921 * The timestamp of the initial creation of the session. 3922 */ getCreatedMillis()3923 public long getCreatedMillis() { 3924 return createdMillis; 3925 } 3926 3927 /** 3928 * The timestamp of the last update that occurred to the session, including changing of 3929 * states in case of staged sessions. 3930 */ 3931 @CurrentTimeMillisLong getUpdatedMillis()3932 public long getUpdatedMillis() { 3933 return updatedMillis; 3934 } 3935 3936 /** 3937 * Whether user action was required by the installer. 3938 * 3939 * <p> 3940 * Note: a return value of {@code USER_ACTION_NOT_REQUIRED} does not guarantee that the 3941 * install will not result in user action. 3942 * 3943 * @return {@link SessionParams#USER_ACTION_NOT_REQUIRED}, 3944 * {@link SessionParams#USER_ACTION_REQUIRED} or 3945 * {@link SessionParams#USER_ACTION_UNSPECIFIED} 3946 */ 3947 @SessionParams.UserActionRequirement getRequireUserAction()3948 public int getRequireUserAction() { 3949 return requireUserAction; 3950 } 3951 3952 /** 3953 * Returns the Uid of the owner of the session. 3954 */ getInstallerUid()3955 public int getInstallerUid() { 3956 return installerUid; 3957 } 3958 3959 /** 3960 * Returns {@code true} if this session will keep the existing application enabled setting 3961 * after installation. 3962 */ isApplicationEnabledSettingPersistent()3963 public boolean isApplicationEnabledSettingPersistent() { 3964 return applicationEnabledSettingPersistent; 3965 } 3966 3967 /** 3968 * Returns whether this session has requested user pre-approval. 3969 */ isPreApprovalRequested()3970 public boolean isPreApprovalRequested() { 3971 return isPreapprovalRequested; 3972 } 3973 3974 /** 3975 * @return {@code true} if the installer requested the update ownership enforcement 3976 * for the packages in this session. 3977 * 3978 * @see PackageInstaller.SessionParams#setRequestUpdateOwnership 3979 */ isRequestUpdateOwnership()3980 public boolean isRequestUpdateOwnership() { 3981 return (installFlags & PackageManager.INSTALL_REQUEST_UPDATE_OWNERSHIP) != 0; 3982 } 3983 3984 /** 3985 * Return the reason for requiring the user action. 3986 * @hide 3987 */ 3988 @SystemApi getPendingUserActionReason()3989 public @UserActionReason int getPendingUserActionReason() { 3990 return pendingUserActionReason; 3991 } 3992 3993 @Override describeContents()3994 public int describeContents() { 3995 return 0; 3996 } 3997 3998 @Override writeToParcel(Parcel dest, int flags)3999 public void writeToParcel(Parcel dest, int flags) { 4000 dest.writeInt(sessionId); 4001 dest.writeInt(userId); 4002 dest.writeString(installerPackageName); 4003 dest.writeString(installerAttributionTag); 4004 dest.writeString(resolvedBaseCodePath); 4005 dest.writeFloat(progress); 4006 dest.writeInt(sealed ? 1 : 0); 4007 dest.writeInt(active ? 1 : 0); 4008 4009 dest.writeInt(mode); 4010 dest.writeInt(installReason); 4011 dest.writeInt(installScenario); 4012 dest.writeLong(sizeBytes); 4013 dest.writeString(appPackageName); 4014 dest.writeParcelable(appIcon, flags); 4015 dest.writeString(appLabel != null ? appLabel.toString() : null); 4016 4017 dest.writeInt(installLocation); 4018 dest.writeParcelable(originatingUri, flags); 4019 dest.writeInt(originatingUid); 4020 dest.writeParcelable(referrerUri, flags); 4021 dest.writeStringArray(grantedRuntimePermissions); 4022 dest.writeStringList(whitelistedRestrictedPermissions); 4023 dest.writeInt(autoRevokePermissionsMode); 4024 dest.writeInt(installFlags); 4025 dest.writeBoolean(isMultiPackage); 4026 dest.writeBoolean(isStaged); 4027 dest.writeBoolean(forceQueryable); 4028 dest.writeInt(parentSessionId); 4029 dest.writeIntArray(childSessionIds); 4030 dest.writeBoolean(isSessionApplied); 4031 dest.writeBoolean(isSessionReady); 4032 dest.writeBoolean(isSessionFailed); 4033 dest.writeInt(mSessionErrorCode); 4034 dest.writeString(mSessionErrorMessage); 4035 dest.writeBoolean(isCommitted); 4036 dest.writeBoolean(isPreapprovalRequested); 4037 dest.writeInt(rollbackDataPolicy); 4038 dest.writeLong(createdMillis); 4039 dest.writeInt(requireUserAction); 4040 dest.writeInt(installerUid); 4041 dest.writeInt(packageSource); 4042 dest.writeBoolean(applicationEnabledSettingPersistent); 4043 dest.writeInt(pendingUserActionReason); 4044 } 4045 4046 public static final Parcelable.Creator<SessionInfo> 4047 CREATOR = new Parcelable.Creator<SessionInfo>() { 4048 @Override 4049 public SessionInfo createFromParcel(Parcel p) { 4050 return new SessionInfo(p); 4051 } 4052 4053 @Override 4054 public SessionInfo[] newArray(int size) { 4055 return new SessionInfo[size]; 4056 } 4057 }; 4058 } 4059 4060 /** 4061 * Details for requesting the pre-commit install approval. 4062 */ 4063 @DataClass(genConstructor = false, genToString = true) 4064 public static final class PreapprovalDetails implements Parcelable { 4065 /** 4066 * The icon representing the app to be installed. 4067 */ 4068 private final @Nullable Bitmap mIcon; 4069 /** 4070 * The label representing the app to be installed. 4071 */ 4072 private final @NonNull CharSequence mLabel; 4073 /** 4074 * The locale of the app label being used. 4075 */ 4076 private final @NonNull ULocale mLocale; 4077 /** 4078 * The package name of the app to be installed. 4079 */ 4080 private final @NonNull String mPackageName; 4081 4082 /** 4083 * Creates a new PreapprovalDetails. 4084 * 4085 * @param icon 4086 * The icon representing the app to be installed. 4087 * @param label 4088 * The label representing the app to be installed. 4089 * @param locale 4090 * The locale of the app label being used. 4091 * @param packageName 4092 * The package name of the app to be installed. 4093 * @hide 4094 */ PreapprovalDetails( @ullable Bitmap icon, @NonNull CharSequence label, @NonNull ULocale locale, @NonNull String packageName)4095 public PreapprovalDetails( 4096 @Nullable Bitmap icon, 4097 @NonNull CharSequence label, 4098 @NonNull ULocale locale, 4099 @NonNull String packageName) { 4100 mIcon = icon; 4101 mLabel = label; 4102 Preconditions.checkArgument(!TextUtils.isEmpty(mLabel), 4103 "App label cannot be empty."); 4104 mLocale = locale; 4105 Preconditions.checkArgument(!Objects.isNull(mLocale), 4106 "Locale cannot be null."); 4107 mPackageName = packageName; 4108 Preconditions.checkArgument(!TextUtils.isEmpty(mPackageName), 4109 "Package name cannot be empty."); 4110 } 4111 4112 @Override writeToParcel(@onNull Parcel dest, int flags)4113 public void writeToParcel(@NonNull Parcel dest, int flags) { 4114 byte flg = 0; 4115 if (mIcon != null) flg |= 0x1; 4116 dest.writeByte(flg); 4117 if (mIcon != null) mIcon.writeToParcel(dest, flags); 4118 dest.writeCharSequence(mLabel); 4119 dest.writeString8(mLocale.toString()); 4120 dest.writeString8(mPackageName); 4121 } 4122 4123 @Override describeContents()4124 public int describeContents() { return 0; } 4125 4126 /** @hide */ PreapprovalDetails(@onNull Parcel in)4127 /* package-private */ PreapprovalDetails(@NonNull Parcel in) { 4128 byte flg = in.readByte(); 4129 final Bitmap icon = (flg & 0x1) == 0 ? null : Bitmap.CREATOR.createFromParcel(in); 4130 final CharSequence label = in.readCharSequence(); 4131 final ULocale locale = new ULocale(in.readString8()); 4132 final String packageName = in.readString8(); 4133 4134 mIcon = icon; 4135 mLabel = label; 4136 Preconditions.checkArgument(!TextUtils.isEmpty(mLabel), 4137 "App label cannot be empty."); 4138 mLocale = locale; 4139 Preconditions.checkArgument(!Objects.isNull(mLocale), 4140 "Locale cannot be null."); 4141 mPackageName = packageName; 4142 Preconditions.checkArgument(!TextUtils.isEmpty(mPackageName), 4143 "Package name cannot be empty."); 4144 } 4145 4146 public static final @NonNull Parcelable.Creator<PreapprovalDetails> CREATOR 4147 = new Parcelable.Creator<PreapprovalDetails>() { 4148 @Override 4149 public PreapprovalDetails[] newArray(int size) { 4150 return new PreapprovalDetails[size]; 4151 } 4152 4153 @Override 4154 public PreapprovalDetails createFromParcel(@NonNull Parcel in) { 4155 return new PreapprovalDetails(in); 4156 } 4157 }; 4158 4159 /** 4160 * A builder for {@link PreapprovalDetails} 4161 */ 4162 public static final class Builder { 4163 4164 private @Nullable Bitmap mIcon; 4165 private @NonNull CharSequence mLabel; 4166 private @NonNull ULocale mLocale; 4167 private @NonNull String mPackageName; 4168 4169 private long mBuilderFieldsSet = 0L; 4170 4171 /** 4172 * Creates a new Builder. 4173 */ Builder()4174 public Builder() {} 4175 4176 /** 4177 * The icon representing the app to be installed. 4178 */ setIcon(@onNull Bitmap value)4179 public @NonNull Builder setIcon(@NonNull Bitmap value) { 4180 checkNotUsed(); 4181 mBuilderFieldsSet |= 0x1; 4182 mIcon = value; 4183 return this; 4184 } 4185 4186 /** 4187 * The label representing the app to be installed. 4188 */ setLabel(@onNull CharSequence value)4189 public @NonNull Builder setLabel(@NonNull CharSequence value) { 4190 checkNotUsed(); 4191 mBuilderFieldsSet |= 0x2; 4192 mLabel = value; 4193 return this; 4194 } 4195 4196 /** 4197 * The locale of the app label being used. 4198 */ setLocale(@onNull ULocale value)4199 public @NonNull Builder setLocale(@NonNull ULocale value) { 4200 checkNotUsed(); 4201 mBuilderFieldsSet |= 0x4; 4202 mLocale = value; 4203 return this; 4204 } 4205 4206 /** 4207 * The package name of the app to be installed. 4208 */ setPackageName(@onNull String value)4209 public @NonNull Builder setPackageName(@NonNull String value) { 4210 checkNotUsed(); 4211 mBuilderFieldsSet |= 0x8; 4212 mPackageName = value; 4213 return this; 4214 } 4215 4216 /** Builds the instance. This builder should not be touched after calling this! */ build()4217 public @NonNull PreapprovalDetails build() { 4218 checkNotUsed(); 4219 mBuilderFieldsSet |= 0x10; // Mark builder used 4220 4221 PreapprovalDetails o = new PreapprovalDetails( 4222 mIcon, 4223 mLabel, 4224 mLocale, 4225 mPackageName); 4226 return o; 4227 } 4228 checkNotUsed()4229 private void checkNotUsed() { 4230 if ((mBuilderFieldsSet & 0x10) != 0) { 4231 throw new IllegalStateException("This Builder should not be reused. " 4232 + "Use a new Builder instance instead"); 4233 } 4234 } 4235 } 4236 4237 4238 4239 4240 // Code below generated by codegen v1.0.23. 4241 // 4242 // DO NOT MODIFY! 4243 // CHECKSTYLE:OFF Generated code 4244 // 4245 // To regenerate run: 4246 // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/PackageInstaller.java 4247 // 4248 // To exclude the generated code from IntelliJ auto-formatting enable (one-time): 4249 // Settings > Editor > Code Style > Formatter Control 4250 //@formatter:off 4251 4252 4253 /** 4254 * The icon representing the app to be installed. 4255 */ 4256 @DataClass.Generated.Member getIcon()4257 public @Nullable Bitmap getIcon() { 4258 return mIcon; 4259 } 4260 4261 /** 4262 * The label representing the app to be installed. 4263 */ 4264 @DataClass.Generated.Member getLabel()4265 public @NonNull CharSequence getLabel() { 4266 return mLabel; 4267 } 4268 4269 /** 4270 * The locale of the app label being used. 4271 */ 4272 @DataClass.Generated.Member getLocale()4273 public @NonNull ULocale getLocale() { 4274 return mLocale; 4275 } 4276 4277 /** 4278 * The package name of the app to be installed. 4279 */ 4280 @DataClass.Generated.Member getPackageName()4281 public @NonNull String getPackageName() { 4282 return mPackageName; 4283 } 4284 4285 @Override 4286 @DataClass.Generated.Member toString()4287 public String toString() { 4288 // You can override field toString logic by defining methods like: 4289 // String fieldNameToString() { ... } 4290 4291 return "PreapprovalDetails { " + 4292 "icon = " + mIcon + ", " + 4293 "label = " + mLabel + ", " + 4294 "locale = " + mLocale + ", " + 4295 "packageName = " + mPackageName + 4296 " }"; 4297 } 4298 4299 @DataClass.Generated( 4300 time = 1676970504308L, 4301 codegenVersion = "1.0.23", 4302 sourceFile = "frameworks/base/core/java/android/content/pm/PackageInstaller.java", 4303 inputSignatures = "private final @android.annotation.Nullable android.graphics.Bitmap mIcon\nprivate final @android.annotation.NonNull java.lang.CharSequence mLabel\nprivate final @android.annotation.NonNull android.icu.util.ULocale mLocale\nprivate final @android.annotation.NonNull java.lang.String mPackageName\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<android.content.pm.PackageInstaller.PreapprovalDetails> CREATOR\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\npublic @java.lang.Override int describeContents()\nclass PreapprovalDetails extends java.lang.Object implements [android.os.Parcelable]\nprivate @android.annotation.Nullable android.graphics.Bitmap mIcon\nprivate @android.annotation.NonNull java.lang.CharSequence mLabel\nprivate @android.annotation.NonNull android.icu.util.ULocale mLocale\nprivate @android.annotation.NonNull java.lang.String mPackageName\nprivate long mBuilderFieldsSet\npublic @android.annotation.NonNull android.content.pm.PackageInstaller.PreapprovalDetails.Builder setIcon(android.graphics.Bitmap)\npublic @android.annotation.NonNull android.content.pm.PackageInstaller.PreapprovalDetails.Builder setLabel(java.lang.CharSequence)\npublic @android.annotation.NonNull android.content.pm.PackageInstaller.PreapprovalDetails.Builder setLocale(android.icu.util.ULocale)\npublic @android.annotation.NonNull android.content.pm.PackageInstaller.PreapprovalDetails.Builder setPackageName(java.lang.String)\npublic @android.annotation.NonNull android.content.pm.PackageInstaller.PreapprovalDetails build()\nprivate void checkNotUsed()\nclass Builder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genToString=true)") 4304 @Deprecated __metadata()4305 private void __metadata() {} 4306 4307 4308 //@formatter:on 4309 // End of generated code 4310 4311 } 4312 4313 /** 4314 * The callback result of {@link #checkInstallConstraints(List, InstallConstraints, Executor, Consumer)}. 4315 */ 4316 @DataClass(genParcelable = true, genHiddenConstructor = true) 4317 @DataClass.Suppress("isAllConstraintsSatisfied") 4318 public static final class InstallConstraintsResult implements Parcelable { 4319 /** 4320 * True if all constraints are satisfied. 4321 */ 4322 private boolean mAllConstraintsSatisfied; 4323 4324 /** 4325 * True if all constraints are satisfied. 4326 */ areAllConstraintsSatisfied()4327 public boolean areAllConstraintsSatisfied() { 4328 return mAllConstraintsSatisfied; 4329 } 4330 4331 4332 4333 // Code below generated by codegen v1.0.23. 4334 // 4335 // DO NOT MODIFY! 4336 // CHECKSTYLE:OFF Generated code 4337 // 4338 // To regenerate run: 4339 // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/PackageInstaller.java 4340 // 4341 // To exclude the generated code from IntelliJ auto-formatting enable (one-time): 4342 // Settings > Editor > Code Style > Formatter Control 4343 //@formatter:off 4344 4345 4346 /** 4347 * Creates a new InstallConstraintsResult. 4348 * 4349 * @param allConstraintsSatisfied 4350 * True if all constraints are satisfied. 4351 * @hide 4352 */ 4353 @DataClass.Generated.Member InstallConstraintsResult( boolean allConstraintsSatisfied)4354 public InstallConstraintsResult( 4355 boolean allConstraintsSatisfied) { 4356 this.mAllConstraintsSatisfied = allConstraintsSatisfied; 4357 4358 // onConstructed(); // You can define this method to get a callback 4359 } 4360 4361 @Override 4362 @DataClass.Generated.Member writeToParcel(@onNull Parcel dest, int flags)4363 public void writeToParcel(@NonNull Parcel dest, int flags) { 4364 // You can override field parcelling by defining methods like: 4365 // void parcelFieldName(Parcel dest, int flags) { ... } 4366 4367 byte flg = 0; 4368 if (mAllConstraintsSatisfied) flg |= 0x1; 4369 dest.writeByte(flg); 4370 } 4371 4372 @Override 4373 @DataClass.Generated.Member describeContents()4374 public int describeContents() { return 0; } 4375 4376 /** @hide */ 4377 @SuppressWarnings({"unchecked", "RedundantCast"}) 4378 @DataClass.Generated.Member InstallConstraintsResult(@onNull Parcel in)4379 /* package-private */ InstallConstraintsResult(@NonNull Parcel in) { 4380 // You can override field unparcelling by defining methods like: 4381 // static FieldType unparcelFieldName(Parcel in) { ... } 4382 4383 byte flg = in.readByte(); 4384 boolean allConstraintsSatisfied = (flg & 0x1) != 0; 4385 4386 this.mAllConstraintsSatisfied = allConstraintsSatisfied; 4387 4388 // onConstructed(); // You can define this method to get a callback 4389 } 4390 4391 @DataClass.Generated.Member 4392 public static final @NonNull Parcelable.Creator<InstallConstraintsResult> CREATOR 4393 = new Parcelable.Creator<InstallConstraintsResult>() { 4394 @Override 4395 public InstallConstraintsResult[] newArray(int size) { 4396 return new InstallConstraintsResult[size]; 4397 } 4398 4399 @Override 4400 public InstallConstraintsResult createFromParcel(@NonNull Parcel in) { 4401 return new InstallConstraintsResult(in); 4402 } 4403 }; 4404 4405 @DataClass.Generated( 4406 time = 1676970504336L, 4407 codegenVersion = "1.0.23", 4408 sourceFile = "frameworks/base/core/java/android/content/pm/PackageInstaller.java", 4409 inputSignatures = "private boolean mAllConstraintsSatisfied\npublic boolean areAllConstraintsSatisfied()\nclass InstallConstraintsResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genHiddenConstructor=true)") 4410 @Deprecated __metadata()4411 private void __metadata() {} 4412 4413 4414 //@formatter:on 4415 // End of generated code 4416 4417 } 4418 4419 /** 4420 * A class to encapsulate constraints for installation. 4421 * 4422 * When used with {@link #checkInstallConstraints(List, InstallConstraints, Executor, Consumer)}, it 4423 * specifies the conditions to check against for the packages in question. This can be used 4424 * by app stores to deliver auto updates without disrupting the user experience (referred as 4425 * gentle update) - for example, an app store might hold off updates when it find out the 4426 * app to update is interacting with the user. 4427 * 4428 * Use {@link Builder} to create a new instance and call mutator methods to add constraints. 4429 * If no mutators were called, default constraints will be generated which implies no 4430 * constraints. It is recommended to use preset constraints which are useful in most 4431 * cases. 4432 * 4433 * For the purpose of gentle update, it is recommended to always use {@link #GENTLE_UPDATE} 4434 * for the system knows best how to do it. It will also benefits the installer as the 4435 * platform evolves and add more constraints to improve the accuracy and efficiency of 4436 * gentle update. 4437 * 4438 * Note the constraints are applied transitively. If app Foo is used by app Bar (via shared 4439 * library or bounded service), the constraints will also be applied to Bar. 4440 */ 4441 @DataClass(genParcelable = true, genHiddenConstructor = true, genEqualsHashCode=true) 4442 public static final class InstallConstraints implements Parcelable { 4443 /** 4444 * Preset constraints suitable for gentle update. 4445 */ 4446 @NonNull 4447 public static final InstallConstraints GENTLE_UPDATE = 4448 new Builder().setAppNotInteractingRequired().build(); 4449 4450 private final boolean mDeviceIdleRequired; 4451 private final boolean mAppNotForegroundRequired; 4452 private final boolean mAppNotInteractingRequired; 4453 private final boolean mAppNotTopVisibleRequired; 4454 private final boolean mNotInCallRequired; 4455 4456 /** 4457 * Builder class for constructing {@link InstallConstraints}. 4458 */ 4459 public static final class Builder { 4460 private boolean mDeviceIdleRequired; 4461 private boolean mAppNotForegroundRequired; 4462 private boolean mAppNotInteractingRequired; 4463 private boolean mAppNotTopVisibleRequired; 4464 private boolean mNotInCallRequired; 4465 4466 /** 4467 * This constraint requires the device is idle. 4468 */ 4469 @SuppressLint("MissingGetterMatchingBuilder") 4470 @NonNull setDeviceIdleRequired()4471 public Builder setDeviceIdleRequired() { 4472 mDeviceIdleRequired = true; 4473 return this; 4474 } 4475 4476 /** 4477 * This constraint requires the app in question is not in the foreground. 4478 */ 4479 @SuppressLint("MissingGetterMatchingBuilder") 4480 @NonNull setAppNotForegroundRequired()4481 public Builder setAppNotForegroundRequired() { 4482 mAppNotForegroundRequired = true; 4483 return this; 4484 } 4485 4486 /** 4487 * This constraint requires the app in question is not interacting with the user. 4488 * User interaction includes: 4489 * <ul> 4490 * <li>playing or recording audio/video</li> 4491 * <li>sending or receiving network data</li> 4492 * <li>being visible to the user</li> 4493 * </ul> 4494 */ 4495 @SuppressLint("MissingGetterMatchingBuilder") 4496 @NonNull setAppNotInteractingRequired()4497 public Builder setAppNotInteractingRequired() { 4498 mAppNotInteractingRequired = true; 4499 return this; 4500 } 4501 4502 /** 4503 * This constraint requires the app in question is not top-visible to the user. 4504 * A top-visible app is showing UI at the top of the screen that the user is 4505 * interacting with. 4506 * 4507 * Note this constraint is a subset of {@link #setAppNotForegroundRequired()} 4508 * because a top-visible app is also a foreground app. This is also a subset 4509 * of {@link #setAppNotInteractingRequired()} because a top-visible app is interacting 4510 * with the user. 4511 * 4512 * @see ActivityManager.RunningAppProcessInfo#IMPORTANCE_FOREGROUND 4513 */ 4514 @SuppressLint("MissingGetterMatchingBuilder") 4515 @NonNull setAppNotTopVisibleRequired()4516 public Builder setAppNotTopVisibleRequired() { 4517 mAppNotTopVisibleRequired = true; 4518 return this; 4519 } 4520 4521 /** 4522 * This constraint requires there is no ongoing call in the device. 4523 */ 4524 @SuppressLint("MissingGetterMatchingBuilder") 4525 @NonNull setNotInCallRequired()4526 public Builder setNotInCallRequired() { 4527 mNotInCallRequired = true; 4528 return this; 4529 } 4530 4531 /** 4532 * Builds a new {@link InstallConstraints} instance. 4533 */ 4534 @NonNull build()4535 public InstallConstraints build() { 4536 return new InstallConstraints(mDeviceIdleRequired, mAppNotForegroundRequired, 4537 mAppNotInteractingRequired, mAppNotTopVisibleRequired, mNotInCallRequired); 4538 } 4539 } 4540 4541 4542 4543 // Code below generated by codegen v1.0.23. 4544 // 4545 // DO NOT MODIFY! 4546 // CHECKSTYLE:OFF Generated code 4547 // 4548 // To regenerate run: 4549 // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/PackageInstaller.java 4550 // 4551 // To exclude the generated code from IntelliJ auto-formatting enable (one-time): 4552 // Settings > Editor > Code Style > Formatter Control 4553 //@formatter:off 4554 4555 4556 /** 4557 * Creates a new InstallConstraints. 4558 * 4559 * @hide 4560 */ 4561 @DataClass.Generated.Member InstallConstraints( boolean deviceIdleRequired, boolean appNotForegroundRequired, boolean appNotInteractingRequired, boolean appNotTopVisibleRequired, boolean notInCallRequired)4562 public InstallConstraints( 4563 boolean deviceIdleRequired, 4564 boolean appNotForegroundRequired, 4565 boolean appNotInteractingRequired, 4566 boolean appNotTopVisibleRequired, 4567 boolean notInCallRequired) { 4568 this.mDeviceIdleRequired = deviceIdleRequired; 4569 this.mAppNotForegroundRequired = appNotForegroundRequired; 4570 this.mAppNotInteractingRequired = appNotInteractingRequired; 4571 this.mAppNotTopVisibleRequired = appNotTopVisibleRequired; 4572 this.mNotInCallRequired = notInCallRequired; 4573 4574 // onConstructed(); // You can define this method to get a callback 4575 } 4576 4577 @DataClass.Generated.Member isDeviceIdleRequired()4578 public boolean isDeviceIdleRequired() { 4579 return mDeviceIdleRequired; 4580 } 4581 4582 @DataClass.Generated.Member isAppNotForegroundRequired()4583 public boolean isAppNotForegroundRequired() { 4584 return mAppNotForegroundRequired; 4585 } 4586 4587 @DataClass.Generated.Member isAppNotInteractingRequired()4588 public boolean isAppNotInteractingRequired() { 4589 return mAppNotInteractingRequired; 4590 } 4591 4592 @DataClass.Generated.Member isAppNotTopVisibleRequired()4593 public boolean isAppNotTopVisibleRequired() { 4594 return mAppNotTopVisibleRequired; 4595 } 4596 4597 @DataClass.Generated.Member isNotInCallRequired()4598 public boolean isNotInCallRequired() { 4599 return mNotInCallRequired; 4600 } 4601 4602 @Override 4603 @DataClass.Generated.Member equals(@ullable Object o)4604 public boolean equals(@Nullable Object o) { 4605 // You can override field equality logic by defining either of the methods like: 4606 // boolean fieldNameEquals(InstallConstraints other) { ... } 4607 // boolean fieldNameEquals(FieldType otherValue) { ... } 4608 4609 if (this == o) return true; 4610 if (o == null || getClass() != o.getClass()) return false; 4611 @SuppressWarnings("unchecked") 4612 InstallConstraints that = (InstallConstraints) o; 4613 //noinspection PointlessBooleanExpression 4614 return true 4615 && mDeviceIdleRequired == that.mDeviceIdleRequired 4616 && mAppNotForegroundRequired == that.mAppNotForegroundRequired 4617 && mAppNotInteractingRequired == that.mAppNotInteractingRequired 4618 && mAppNotTopVisibleRequired == that.mAppNotTopVisibleRequired 4619 && mNotInCallRequired == that.mNotInCallRequired; 4620 } 4621 4622 @Override 4623 @DataClass.Generated.Member hashCode()4624 public int hashCode() { 4625 // You can override field hashCode logic by defining methods like: 4626 // int fieldNameHashCode() { ... } 4627 4628 int _hash = 1; 4629 _hash = 31 * _hash + Boolean.hashCode(mDeviceIdleRequired); 4630 _hash = 31 * _hash + Boolean.hashCode(mAppNotForegroundRequired); 4631 _hash = 31 * _hash + Boolean.hashCode(mAppNotInteractingRequired); 4632 _hash = 31 * _hash + Boolean.hashCode(mAppNotTopVisibleRequired); 4633 _hash = 31 * _hash + Boolean.hashCode(mNotInCallRequired); 4634 return _hash; 4635 } 4636 4637 @Override 4638 @DataClass.Generated.Member writeToParcel(@onNull Parcel dest, int flags)4639 public void writeToParcel(@NonNull Parcel dest, int flags) { 4640 // You can override field parcelling by defining methods like: 4641 // void parcelFieldName(Parcel dest, int flags) { ... } 4642 4643 byte flg = 0; 4644 if (mDeviceIdleRequired) flg |= 0x1; 4645 if (mAppNotForegroundRequired) flg |= 0x2; 4646 if (mAppNotInteractingRequired) flg |= 0x4; 4647 if (mAppNotTopVisibleRequired) flg |= 0x8; 4648 if (mNotInCallRequired) flg |= 0x10; 4649 dest.writeByte(flg); 4650 } 4651 4652 @Override 4653 @DataClass.Generated.Member describeContents()4654 public int describeContents() { return 0; } 4655 4656 /** @hide */ 4657 @SuppressWarnings({"unchecked", "RedundantCast"}) 4658 @DataClass.Generated.Member InstallConstraints(@onNull Parcel in)4659 /* package-private */ InstallConstraints(@NonNull Parcel in) { 4660 // You can override field unparcelling by defining methods like: 4661 // static FieldType unparcelFieldName(Parcel in) { ... } 4662 4663 byte flg = in.readByte(); 4664 boolean deviceIdleRequired = (flg & 0x1) != 0; 4665 boolean appNotForegroundRequired = (flg & 0x2) != 0; 4666 boolean appNotInteractingRequired = (flg & 0x4) != 0; 4667 boolean appNotTopVisibleRequired = (flg & 0x8) != 0; 4668 boolean notInCallRequired = (flg & 0x10) != 0; 4669 4670 this.mDeviceIdleRequired = deviceIdleRequired; 4671 this.mAppNotForegroundRequired = appNotForegroundRequired; 4672 this.mAppNotInteractingRequired = appNotInteractingRequired; 4673 this.mAppNotTopVisibleRequired = appNotTopVisibleRequired; 4674 this.mNotInCallRequired = notInCallRequired; 4675 4676 // onConstructed(); // You can define this method to get a callback 4677 } 4678 4679 @DataClass.Generated.Member 4680 public static final @NonNull Parcelable.Creator<InstallConstraints> CREATOR 4681 = new Parcelable.Creator<InstallConstraints>() { 4682 @Override 4683 public InstallConstraints[] newArray(int size) { 4684 return new InstallConstraints[size]; 4685 } 4686 4687 @Override 4688 public InstallConstraints createFromParcel(@NonNull Parcel in) { 4689 return new InstallConstraints(in); 4690 } 4691 }; 4692 4693 @DataClass.Generated( 4694 time = 1676970504352L, 4695 codegenVersion = "1.0.23", 4696 sourceFile = "frameworks/base/core/java/android/content/pm/PackageInstaller.java", 4697 inputSignatures = "public static final @android.annotation.NonNull android.content.pm.PackageInstaller.InstallConstraints GENTLE_UPDATE\nprivate final boolean mDeviceIdleRequired\nprivate final boolean mAppNotForegroundRequired\nprivate final boolean mAppNotInteractingRequired\nprivate final boolean mAppNotTopVisibleRequired\nprivate final boolean mNotInCallRequired\nclass InstallConstraints extends java.lang.Object implements [android.os.Parcelable]\nprivate boolean mDeviceIdleRequired\nprivate boolean mAppNotForegroundRequired\nprivate boolean mAppNotInteractingRequired\nprivate boolean mAppNotTopVisibleRequired\nprivate boolean mNotInCallRequired\npublic @android.annotation.SuppressLint @android.annotation.NonNull android.content.pm.PackageInstaller.InstallConstraints.Builder setDeviceIdleRequired()\npublic @android.annotation.SuppressLint @android.annotation.NonNull android.content.pm.PackageInstaller.InstallConstraints.Builder setAppNotForegroundRequired()\npublic @android.annotation.SuppressLint @android.annotation.NonNull android.content.pm.PackageInstaller.InstallConstraints.Builder setAppNotInteractingRequired()\npublic @android.annotation.SuppressLint @android.annotation.NonNull android.content.pm.PackageInstaller.InstallConstraints.Builder setAppNotTopVisibleRequired()\npublic @android.annotation.SuppressLint @android.annotation.NonNull android.content.pm.PackageInstaller.InstallConstraints.Builder setNotInCallRequired()\npublic @android.annotation.NonNull android.content.pm.PackageInstaller.InstallConstraints build()\nclass Builder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genParcelable=true, genHiddenConstructor=true, genEqualsHashCode=true)") 4698 @Deprecated __metadata()4699 private void __metadata() {} 4700 4701 4702 //@formatter:on 4703 // End of generated code 4704 4705 } 4706 4707 } 4708