PackageInstaller.java revision 5d74493f64493cd506d7458b810095259287f623
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 17package android.content.pm; 18 19import android.Manifest; 20import android.annotation.NonNull; 21import android.annotation.Nullable; 22import android.annotation.RequiresPermission; 23import android.annotation.SdkConstant; 24import android.annotation.SdkConstant.SdkConstantType; 25import android.annotation.SystemApi; 26import android.app.ActivityManager; 27import android.app.AppGlobals; 28import android.content.Intent; 29import android.content.IntentSender; 30import android.content.pm.PackageManager.DeleteFlags; 31import android.content.pm.PackageManager.InstallReason; 32import android.graphics.Bitmap; 33import android.net.Uri; 34import android.os.FileBridge; 35import android.os.Handler; 36import android.os.Looper; 37import android.os.Message; 38import android.os.Parcel; 39import android.os.ParcelFileDescriptor; 40import android.os.Parcelable; 41import android.os.ParcelableException; 42import android.os.RemoteException; 43import android.os.SystemProperties; 44import android.system.ErrnoException; 45import android.system.Os; 46import android.util.ExceptionUtils; 47 48import com.android.internal.util.IndentingPrintWriter; 49import com.android.internal.util.Preconditions; 50 51import java.io.Closeable; 52import java.io.IOException; 53import java.io.InputStream; 54import java.io.OutputStream; 55import java.security.MessageDigest; 56import java.util.ArrayList; 57import java.util.Iterator; 58import java.util.List; 59 60/** 61 * Offers the ability to install, upgrade, and remove applications on the 62 * device. This includes support for apps packaged either as a single 63 * "monolithic" APK, or apps packaged as multiple "split" APKs. 64 * <p> 65 * An app is delivered for installation through a 66 * {@link PackageInstaller.Session}, which any app can create. Once the session 67 * is created, the installer can stream one or more APKs into place until it 68 * decides to either commit or destroy the session. Committing may require user 69 * intervention to complete the installation. 70 * <p> 71 * Sessions can install brand new apps, upgrade existing apps, or add new splits 72 * into an existing app. 73 * <p> 74 * Apps packaged as multiple split APKs always consist of a single "base" APK 75 * (with a {@code null} split name) and zero or more "split" APKs (with unique 76 * split names). Any subset of these APKs can be installed together, as long as 77 * the following constraints are met: 78 * <ul> 79 * <li>All APKs must have the exact same package name, version code, and signing 80 * certificates. 81 * <li>All APKs must have unique split names. 82 * <li>All installations must contain a single base APK. 83 * </ul> 84 */ 85public class PackageInstaller { 86 private static final String TAG = "PackageInstaller"; 87 88 /** {@hide} */ 89 public static final boolean ENABLE_REVOCABLE_FD = 90 SystemProperties.getBoolean("fw.revocable_fd", false); 91 92 /** 93 * Activity Action: Show details about a particular install session. This 94 * may surface actions such as pause, resume, or cancel. 95 * <p> 96 * This should always be scoped to the installer package that owns the 97 * session. Clients should use {@link SessionInfo#createDetailsIntent()} to 98 * build this intent correctly. 99 * <p> 100 * In some cases, a matching Activity may not exist, so ensure you safeguard 101 * against this. 102 * <p> 103 * The session to show details for is defined in {@link #EXTRA_SESSION_ID}. 104 */ 105 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 106 public static final String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS"; 107 108 /** 109 * Broadcast Action: Explicit broadcast sent to the last known default launcher when a session 110 * for a new install is committed. For managed profile, this is sent to the default launcher 111 * of the primary profile. 112 * <p> 113 * The associated session is defined in {@link #EXTRA_SESSION} and the user for which this 114 * session was created in {@link Intent#EXTRA_USER}. 115 */ 116 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 117 public static final String ACTION_SESSION_COMMITTED = 118 "android.content.pm.action.SESSION_COMMITTED"; 119 120 /** {@hide} */ 121 public static final String 122 ACTION_CONFIRM_PERMISSIONS = "android.content.pm.action.CONFIRM_PERMISSIONS"; 123 124 /** 125 * An integer session ID that an operation is working with. 126 * 127 * @see Intent#getIntExtra(String, int) 128 */ 129 public static final String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID"; 130 131 /** 132 * {@link SessionInfo} that an operation is working with. 133 * 134 * @see Intent#getParcelableExtra(String) 135 */ 136 public static final String EXTRA_SESSION = "android.content.pm.extra.SESSION"; 137 138 /** 139 * Package name that an operation is working with. 140 * 141 * @see Intent#getStringExtra(String) 142 */ 143 public static final String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME"; 144 145 /** 146 * Current status of an operation. Will be one of 147 * {@link #STATUS_PENDING_USER_ACTION}, {@link #STATUS_SUCCESS}, 148 * {@link #STATUS_FAILURE}, {@link #STATUS_FAILURE_ABORTED}, 149 * {@link #STATUS_FAILURE_BLOCKED}, {@link #STATUS_FAILURE_CONFLICT}, 150 * {@link #STATUS_FAILURE_INCOMPATIBLE}, {@link #STATUS_FAILURE_INVALID}, or 151 * {@link #STATUS_FAILURE_STORAGE}. 152 * <p> 153 * More information about a status may be available through additional 154 * extras; see the individual status documentation for details. 155 * 156 * @see Intent#getIntExtra(String, int) 157 */ 158 public static final String EXTRA_STATUS = "android.content.pm.extra.STATUS"; 159 160 /** 161 * Detailed string representation of the status, including raw details that 162 * are useful for debugging. 163 * 164 * @see Intent#getStringExtra(String) 165 */ 166 public static final String EXTRA_STATUS_MESSAGE = "android.content.pm.extra.STATUS_MESSAGE"; 167 168 /** 169 * Another package name relevant to a status. This is typically the package 170 * responsible for causing an operation failure. 171 * 172 * @see Intent#getStringExtra(String) 173 */ 174 public static final String 175 EXTRA_OTHER_PACKAGE_NAME = "android.content.pm.extra.OTHER_PACKAGE_NAME"; 176 177 /** 178 * Storage path relevant to a status. 179 * 180 * @see Intent#getStringExtra(String) 181 */ 182 public static final String EXTRA_STORAGE_PATH = "android.content.pm.extra.STORAGE_PATH"; 183 184 /** {@hide} */ 185 @Deprecated 186 public static final String EXTRA_PACKAGE_NAMES = "android.content.pm.extra.PACKAGE_NAMES"; 187 188 /** {@hide} */ 189 public static final String EXTRA_LEGACY_STATUS = "android.content.pm.extra.LEGACY_STATUS"; 190 /** {@hide} */ 191 public static final String EXTRA_LEGACY_BUNDLE = "android.content.pm.extra.LEGACY_BUNDLE"; 192 /** {@hide} */ 193 public static final String EXTRA_CALLBACK = "android.content.pm.extra.CALLBACK"; 194 195 /** 196 * User action is currently required to proceed. You can launch the intent 197 * activity described by {@link Intent#EXTRA_INTENT} to involve the user and 198 * continue. 199 * <p> 200 * You may choose to immediately launch the intent if the user is actively 201 * using your app. Otherwise, you should use a notification to guide the 202 * user back into your app before launching. 203 * 204 * @see Intent#getParcelableExtra(String) 205 */ 206 public static final int STATUS_PENDING_USER_ACTION = -1; 207 208 /** 209 * The operation succeeded. 210 */ 211 public static final int STATUS_SUCCESS = 0; 212 213 /** 214 * The operation failed in a generic way. The system will always try to 215 * provide a more specific failure reason, but in some rare cases this may 216 * be delivered. 217 * 218 * @see #EXTRA_STATUS_MESSAGE 219 */ 220 public static final int STATUS_FAILURE = 1; 221 222 /** 223 * The operation failed because it was blocked. For example, a device policy 224 * may be blocking the operation, a package verifier may have blocked the 225 * operation, or the app may be required for core system operation. 226 * <p> 227 * The result may also contain {@link #EXTRA_OTHER_PACKAGE_NAME} with the 228 * specific package blocking the install. 229 * 230 * @see #EXTRA_STATUS_MESSAGE 231 * @see #EXTRA_OTHER_PACKAGE_NAME 232 */ 233 public static final int STATUS_FAILURE_BLOCKED = 2; 234 235 /** 236 * The operation failed because it was actively aborted. For example, the 237 * user actively declined requested permissions, or the session was 238 * abandoned. 239 * 240 * @see #EXTRA_STATUS_MESSAGE 241 */ 242 public static final int STATUS_FAILURE_ABORTED = 3; 243 244 /** 245 * The operation failed because one or more of the APKs was invalid. For 246 * example, they might be malformed, corrupt, incorrectly signed, 247 * mismatched, etc. 248 * 249 * @see #EXTRA_STATUS_MESSAGE 250 */ 251 public static final int STATUS_FAILURE_INVALID = 4; 252 253 /** 254 * The operation failed because it conflicts (or is inconsistent with) with 255 * another package already installed on the device. For example, an existing 256 * permission, incompatible certificates, etc. The user may be able to 257 * uninstall another app to fix the issue. 258 * <p> 259 * The result may also contain {@link #EXTRA_OTHER_PACKAGE_NAME} with the 260 * specific package identified as the cause of the conflict. 261 * 262 * @see #EXTRA_STATUS_MESSAGE 263 * @see #EXTRA_OTHER_PACKAGE_NAME 264 */ 265 public static final int STATUS_FAILURE_CONFLICT = 5; 266 267 /** 268 * The operation failed because of storage issues. For example, the device 269 * may be running low on space, or external media may be unavailable. The 270 * user may be able to help free space or insert different external media. 271 * <p> 272 * The result may also contain {@link #EXTRA_STORAGE_PATH} with the path to 273 * the storage device that caused the failure. 274 * 275 * @see #EXTRA_STATUS_MESSAGE 276 * @see #EXTRA_STORAGE_PATH 277 */ 278 public static final int STATUS_FAILURE_STORAGE = 6; 279 280 /** 281 * The operation failed because it is fundamentally incompatible with this 282 * device. For example, the app may require a hardware feature that doesn't 283 * exist, it may be missing native code for the ABIs supported by the 284 * device, or it requires a newer SDK version, etc. 285 * 286 * @see #EXTRA_STATUS_MESSAGE 287 */ 288 public static final int STATUS_FAILURE_INCOMPATIBLE = 7; 289 290 private final IPackageInstaller mInstaller; 291 private final int mUserId; 292 private final String mInstallerPackageName; 293 294 private final ArrayList<SessionCallbackDelegate> mDelegates = new ArrayList<>(); 295 296 /** {@hide} */ 297 public PackageInstaller(IPackageInstaller installer, 298 String installerPackageName, int userId) { 299 mInstaller = installer; 300 mInstallerPackageName = installerPackageName; 301 mUserId = userId; 302 } 303 304 /** 305 * Create a new session using the given parameters, returning a unique ID 306 * that represents the session. Once created, the session can be opened 307 * multiple times across multiple device boots. 308 * <p> 309 * The system may automatically destroy sessions that have not been 310 * finalized (either committed or abandoned) within a reasonable period of 311 * time, typically on the order of a day. 312 * 313 * @throws IOException if parameters were unsatisfiable, such as lack of 314 * disk space or unavailable media. 315 * @throws SecurityException when installation services are unavailable, 316 * such as when called from a restricted user. 317 * @throws IllegalArgumentException when {@link SessionParams} is invalid. 318 * @return positive, non-zero unique ID that represents the created session. 319 * This ID remains consistent across device reboots until the 320 * session is finalized. IDs are not reused during a given boot. 321 */ 322 public int createSession(@NonNull SessionParams params) throws IOException { 323 try { 324 return mInstaller.createSession(params, mInstallerPackageName, mUserId); 325 } catch (RuntimeException e) { 326 ExceptionUtils.maybeUnwrapIOException(e); 327 throw e; 328 } catch (RemoteException e) { 329 throw e.rethrowFromSystemServer(); 330 } 331 } 332 333 /** 334 * Open an existing session to actively perform work. To succeed, the caller 335 * must be the owner of the install session. 336 * 337 * @throws IOException if parameters were unsatisfiable, such as lack of 338 * disk space or unavailable media. 339 * @throws SecurityException when the caller does not own the session, or 340 * the session is invalid. 341 */ 342 public @NonNull Session openSession(int sessionId) throws IOException { 343 try { 344 return new Session(mInstaller.openSession(sessionId)); 345 } catch (RuntimeException e) { 346 ExceptionUtils.maybeUnwrapIOException(e); 347 throw e; 348 } catch (RemoteException e) { 349 throw e.rethrowFromSystemServer(); 350 } 351 } 352 353 /** 354 * Update the icon representing the app being installed in a specific 355 * session. This should be roughly 356 * {@link ActivityManager#getLauncherLargeIconSize()} in both dimensions. 357 * 358 * @throws SecurityException when the caller does not own the session, or 359 * the session is invalid. 360 */ 361 public void updateSessionAppIcon(int sessionId, @Nullable Bitmap appIcon) { 362 try { 363 mInstaller.updateSessionAppIcon(sessionId, appIcon); 364 } catch (RemoteException e) { 365 throw e.rethrowFromSystemServer(); 366 } 367 } 368 369 /** 370 * Update the label representing the app being installed in a specific 371 * session. 372 * 373 * @throws SecurityException when the caller does not own the session, or 374 * the session is invalid. 375 */ 376 public void updateSessionAppLabel(int sessionId, @Nullable CharSequence appLabel) { 377 try { 378 final String val = (appLabel != null) ? appLabel.toString() : null; 379 mInstaller.updateSessionAppLabel(sessionId, val); 380 } catch (RemoteException e) { 381 throw e.rethrowFromSystemServer(); 382 } 383 } 384 385 /** 386 * Completely abandon the given session, destroying all staged data and 387 * rendering it invalid. Abandoned sessions will be reported to 388 * {@link SessionCallback} listeners as failures. This is equivalent to 389 * opening the session and calling {@link Session#abandon()}. 390 * 391 * @throws SecurityException when the caller does not own the session, or 392 * the session is invalid. 393 */ 394 public void abandonSession(int sessionId) { 395 try { 396 mInstaller.abandonSession(sessionId); 397 } catch (RemoteException e) { 398 throw e.rethrowFromSystemServer(); 399 } 400 } 401 402 /** 403 * Return details for a specific session. No special permissions are 404 * required to retrieve these details. 405 * 406 * @return details for the requested session, or {@code null} if the session 407 * does not exist. 408 */ 409 public @Nullable SessionInfo getSessionInfo(int sessionId) { 410 try { 411 return mInstaller.getSessionInfo(sessionId); 412 } catch (RemoteException e) { 413 throw e.rethrowFromSystemServer(); 414 } 415 } 416 417 /** 418 * Return list of all known install sessions, regardless of the installer. 419 */ 420 public @NonNull List<SessionInfo> getAllSessions() { 421 try { 422 return mInstaller.getAllSessions(mUserId).getList(); 423 } catch (RemoteException e) { 424 throw e.rethrowFromSystemServer(); 425 } 426 } 427 428 /** 429 * Return list of all known install sessions owned by the calling app. 430 */ 431 public @NonNull List<SessionInfo> getMySessions() { 432 try { 433 return mInstaller.getMySessions(mInstallerPackageName, mUserId).getList(); 434 } catch (RemoteException e) { 435 throw e.rethrowFromSystemServer(); 436 } 437 } 438 439 /** 440 * Uninstall the given package, removing it completely from the device. This 441 * method is only available to the current "installer of record" for the 442 * package. 443 * 444 * @param packageName The package to uninstall. 445 * @param statusReceiver Where to deliver the result. 446 */ 447 public void uninstall(@NonNull String packageName, @NonNull IntentSender statusReceiver) { 448 uninstall(packageName, 0 /*flags*/, statusReceiver); 449 } 450 451 /** 452 * Uninstall the given package, removing it completely from the device. This 453 * method is only available to the current "installer of record" for the 454 * package. 455 * 456 * @param packageName The package to uninstall. 457 * @param flags Flags for uninstall. 458 * @param statusReceiver Where to deliver the result. 459 * 460 * @hide 461 */ 462 public void uninstall(@NonNull String packageName, @DeleteFlags int flags, 463 @NonNull IntentSender statusReceiver) { 464 uninstall(new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST), 465 flags, statusReceiver); 466 } 467 468 /** 469 * Uninstall the given package with a specific version code, removing it 470 * completely from the device. This method is only available to the current 471 * "installer of record" for the package. If the version code of the package 472 * does not match the one passed in the versioned package argument this 473 * method is a no-op. Use {@link PackageManager#VERSION_CODE_HIGHEST} to 474 * uninstall the latest version of the package. 475 * 476 * @param versionedPackage The versioned package to uninstall. 477 * @param statusReceiver Where to deliver the result. 478 */ 479 public void uninstall(@NonNull VersionedPackage versionedPackage, 480 @NonNull IntentSender statusReceiver) { 481 uninstall(versionedPackage, 0 /*flags*/, statusReceiver); 482 } 483 484 /** 485 * Uninstall the given package with a specific version code, removing it 486 * completely from the device. This method is only available to the current 487 * "installer of record" for the package. If the version code of the package 488 * does not match the one passed in the versioned package argument this 489 * method is a no-op. Use {@link PackageManager#VERSION_CODE_HIGHEST} to 490 * uninstall the latest version of the package. 491 * 492 * @param versionedPackage The versioned package to uninstall. 493 * @param flags Flags for uninstall. 494 * @param statusReceiver Where to deliver the result. 495 * 496 * @hide 497 */ 498 @RequiresPermission(anyOf = { 499 Manifest.permission.DELETE_PACKAGES, 500 Manifest.permission.REQUEST_DELETE_PACKAGES}) 501 public void uninstall(@NonNull VersionedPackage versionedPackage, @DeleteFlags int flags, 502 @NonNull IntentSender statusReceiver) { 503 Preconditions.checkNotNull(versionedPackage, "versionedPackage cannot be null"); 504 try { 505 mInstaller.uninstall(versionedPackage, mInstallerPackageName, 506 flags, statusReceiver, mUserId); 507 } catch (RemoteException e) { 508 throw e.rethrowFromSystemServer(); 509 } 510 } 511 512 /** {@hide} */ 513 @SystemApi 514 @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) 515 public void setPermissionsResult(int sessionId, boolean accepted) { 516 try { 517 mInstaller.setPermissionsResult(sessionId, accepted); 518 } catch (RemoteException e) { 519 throw e.rethrowFromSystemServer(); 520 } 521 } 522 523 /** 524 * Events for observing session lifecycle. 525 * <p> 526 * A typical session lifecycle looks like this: 527 * <ul> 528 * <li>An installer creates a session to indicate pending app delivery. All 529 * install details are available at this point. 530 * <li>The installer opens the session to deliver APK data. Note that a 531 * session may be opened and closed multiple times as network connectivity 532 * changes. The installer may deliver periodic progress updates. 533 * <li>The installer commits or abandons the session, resulting in the 534 * session being finished. 535 * </ul> 536 */ 537 public static abstract class SessionCallback { 538 /** 539 * New session has been created. Details about the session can be 540 * obtained from {@link PackageInstaller#getSessionInfo(int)}. 541 */ 542 public abstract void onCreated(int sessionId); 543 544 /** 545 * Badging details for an existing session has changed. For example, the 546 * app icon or label has been updated. 547 */ 548 public abstract void onBadgingChanged(int sessionId); 549 550 /** 551 * Active state for session has been changed. 552 * <p> 553 * A session is considered active whenever there is ongoing forward 554 * progress being made, such as the installer holding an open 555 * {@link Session} instance while streaming data into place, or the 556 * system optimizing code as the result of 557 * {@link Session#commit(IntentSender)}. 558 * <p> 559 * If the installer closes the {@link Session} without committing, the 560 * session is considered inactive until the installer opens the session 561 * again. 562 */ 563 public abstract void onActiveChanged(int sessionId, boolean active); 564 565 /** 566 * Progress for given session has been updated. 567 * <p> 568 * Note that this progress may not directly correspond to the value 569 * reported by 570 * {@link PackageInstaller.Session#setStagingProgress(float)}, as the 571 * system may carve out a portion of the overall progress to represent 572 * its own internal installation work. 573 */ 574 public abstract void onProgressChanged(int sessionId, float progress); 575 576 /** 577 * Session has completely finished, either with success or failure. 578 */ 579 public abstract void onFinished(int sessionId, boolean success); 580 } 581 582 /** {@hide} */ 583 private static class SessionCallbackDelegate extends IPackageInstallerCallback.Stub implements 584 Handler.Callback { 585 private static final int MSG_SESSION_CREATED = 1; 586 private static final int MSG_SESSION_BADGING_CHANGED = 2; 587 private static final int MSG_SESSION_ACTIVE_CHANGED = 3; 588 private static final int MSG_SESSION_PROGRESS_CHANGED = 4; 589 private static final int MSG_SESSION_FINISHED = 5; 590 591 final SessionCallback mCallback; 592 final Handler mHandler; 593 594 public SessionCallbackDelegate(SessionCallback callback, Looper looper) { 595 mCallback = callback; 596 mHandler = new Handler(looper, this); 597 } 598 599 @Override 600 public boolean handleMessage(Message msg) { 601 final int sessionId = msg.arg1; 602 switch (msg.what) { 603 case MSG_SESSION_CREATED: 604 mCallback.onCreated(sessionId); 605 return true; 606 case MSG_SESSION_BADGING_CHANGED: 607 mCallback.onBadgingChanged(sessionId); 608 return true; 609 case MSG_SESSION_ACTIVE_CHANGED: 610 final boolean active = msg.arg2 != 0; 611 mCallback.onActiveChanged(sessionId, active); 612 return true; 613 case MSG_SESSION_PROGRESS_CHANGED: 614 mCallback.onProgressChanged(sessionId, (float) msg.obj); 615 return true; 616 case MSG_SESSION_FINISHED: 617 mCallback.onFinished(sessionId, msg.arg2 != 0); 618 return true; 619 } 620 return false; 621 } 622 623 @Override 624 public void onSessionCreated(int sessionId) { 625 mHandler.obtainMessage(MSG_SESSION_CREATED, sessionId, 0).sendToTarget(); 626 } 627 628 @Override 629 public void onSessionBadgingChanged(int sessionId) { 630 mHandler.obtainMessage(MSG_SESSION_BADGING_CHANGED, sessionId, 0).sendToTarget(); 631 } 632 633 @Override 634 public void onSessionActiveChanged(int sessionId, boolean active) { 635 mHandler.obtainMessage(MSG_SESSION_ACTIVE_CHANGED, sessionId, active ? 1 : 0) 636 .sendToTarget(); 637 } 638 639 @Override 640 public void onSessionProgressChanged(int sessionId, float progress) { 641 mHandler.obtainMessage(MSG_SESSION_PROGRESS_CHANGED, sessionId, 0, progress) 642 .sendToTarget(); 643 } 644 645 @Override 646 public void onSessionFinished(int sessionId, boolean success) { 647 mHandler.obtainMessage(MSG_SESSION_FINISHED, sessionId, success ? 1 : 0) 648 .sendToTarget(); 649 } 650 } 651 652 /** {@hide} */ 653 @Deprecated 654 public void addSessionCallback(@NonNull SessionCallback callback) { 655 registerSessionCallback(callback); 656 } 657 658 /** 659 * Register to watch for session lifecycle events. No special permissions 660 * are required to watch for these events. 661 */ 662 public void registerSessionCallback(@NonNull SessionCallback callback) { 663 registerSessionCallback(callback, new Handler()); 664 } 665 666 /** {@hide} */ 667 @Deprecated 668 public void addSessionCallback(@NonNull SessionCallback callback, @NonNull Handler handler) { 669 registerSessionCallback(callback, handler); 670 } 671 672 /** 673 * Register to watch for session lifecycle events. No special permissions 674 * are required to watch for these events. 675 * 676 * @param handler to dispatch callback events through, otherwise uses 677 * calling thread. 678 */ 679 public void registerSessionCallback(@NonNull SessionCallback callback, @NonNull Handler handler) { 680 synchronized (mDelegates) { 681 final SessionCallbackDelegate delegate = new SessionCallbackDelegate(callback, 682 handler.getLooper()); 683 try { 684 mInstaller.registerCallback(delegate, mUserId); 685 } catch (RemoteException e) { 686 throw e.rethrowFromSystemServer(); 687 } 688 mDelegates.add(delegate); 689 } 690 } 691 692 /** {@hide} */ 693 @Deprecated 694 public void removeSessionCallback(@NonNull SessionCallback callback) { 695 unregisterSessionCallback(callback); 696 } 697 698 /** 699 * Unregister a previously registered callback. 700 */ 701 public void unregisterSessionCallback(@NonNull SessionCallback callback) { 702 synchronized (mDelegates) { 703 for (Iterator<SessionCallbackDelegate> i = mDelegates.iterator(); i.hasNext();) { 704 final SessionCallbackDelegate delegate = i.next(); 705 if (delegate.mCallback == callback) { 706 try { 707 mInstaller.unregisterCallback(delegate); 708 } catch (RemoteException e) { 709 throw e.rethrowFromSystemServer(); 710 } 711 i.remove(); 712 } 713 } 714 } 715 } 716 717 /** 718 * An installation that is being actively staged. For an install to succeed, 719 * all existing and new packages must have identical package names, version 720 * codes, and signing certificates. 721 * <p> 722 * A session may contain any number of split packages. If the application 723 * does not yet exist, this session must include a base package. 724 * <p> 725 * If an APK included in this session is already defined by the existing 726 * installation (for example, the same split name), the APK in this session 727 * will replace the existing APK. 728 */ 729 public static class Session implements Closeable { 730 private IPackageInstallerSession mSession; 731 732 /** {@hide} */ 733 public Session(IPackageInstallerSession session) { 734 mSession = session; 735 } 736 737 /** {@hide} */ 738 @Deprecated 739 public void setProgress(float progress) { 740 setStagingProgress(progress); 741 } 742 743 /** 744 * Set current progress of staging this session. Valid values are 745 * anywhere between 0 and 1. 746 * <p> 747 * Note that this progress may not directly correspond to the value 748 * reported by {@link SessionCallback#onProgressChanged(int, float)}, as 749 * the system may carve out a portion of the overall progress to 750 * represent its own internal installation work. 751 */ 752 public void setStagingProgress(float progress) { 753 try { 754 mSession.setClientProgress(progress); 755 } catch (RemoteException e) { 756 throw e.rethrowFromSystemServer(); 757 } 758 } 759 760 /** {@hide} */ 761 public void addProgress(float progress) { 762 try { 763 mSession.addClientProgress(progress); 764 } catch (RemoteException e) { 765 throw e.rethrowFromSystemServer(); 766 } 767 } 768 769 /** 770 * Open a stream to write an APK file into the session. 771 * <p> 772 * The returned stream will start writing data at the requested offset 773 * in the underlying file, which can be used to resume a partially 774 * written file. If a valid file length is specified, the system will 775 * preallocate the underlying disk space to optimize placement on disk. 776 * It's strongly recommended to provide a valid file length when known. 777 * <p> 778 * You can write data into the returned stream, optionally call 779 * {@link #fsync(OutputStream)} as needed to ensure bytes have been 780 * persisted to disk, and then close when finished. All streams must be 781 * closed before calling {@link #commit(IntentSender)}. 782 * 783 * @param name arbitrary, unique name of your choosing to identify the 784 * APK being written. You can open a file again for 785 * additional writes (such as after a reboot) by using the 786 * same name. This name is only meaningful within the context 787 * of a single install session. 788 * @param offsetBytes offset into the file to begin writing at, or 0 to 789 * start at the beginning of the file. 790 * @param lengthBytes total size of the file being written, used to 791 * preallocate the underlying disk space, or -1 if unknown. 792 * The system may clear various caches as needed to allocate 793 * this space. 794 * @throws IOException if trouble opening the file for writing, such as 795 * lack of disk space or unavailable media. 796 * @throws SecurityException if called after the session has been 797 * sealed or abandoned 798 */ 799 public @NonNull OutputStream openWrite(@NonNull String name, long offsetBytes, 800 long lengthBytes) throws IOException { 801 try { 802 if (ENABLE_REVOCABLE_FD) { 803 return new ParcelFileDescriptor.AutoCloseOutputStream( 804 mSession.openWrite(name, offsetBytes, lengthBytes)); 805 } else { 806 final ParcelFileDescriptor clientSocket = mSession.openWrite(name, 807 offsetBytes, lengthBytes); 808 return new FileBridge.FileBridgeOutputStream(clientSocket); 809 } 810 } catch (RuntimeException e) { 811 ExceptionUtils.maybeUnwrapIOException(e); 812 throw e; 813 } catch (RemoteException e) { 814 throw e.rethrowFromSystemServer(); 815 } 816 817 } 818 819 /** 820 * Ensure that any outstanding data for given stream has been committed 821 * to disk. This is only valid for streams returned from 822 * {@link #openWrite(String, long, long)}. 823 */ 824 public void fsync(@NonNull OutputStream out) throws IOException { 825 if (ENABLE_REVOCABLE_FD) { 826 if (out instanceof ParcelFileDescriptor.AutoCloseOutputStream) { 827 try { 828 Os.fsync(((ParcelFileDescriptor.AutoCloseOutputStream) out).getFD()); 829 } catch (ErrnoException e) { 830 throw e.rethrowAsIOException(); 831 } 832 } else { 833 throw new IllegalArgumentException("Unrecognized stream"); 834 } 835 } else { 836 if (out instanceof FileBridge.FileBridgeOutputStream) { 837 ((FileBridge.FileBridgeOutputStream) out).fsync(); 838 } else { 839 throw new IllegalArgumentException("Unrecognized stream"); 840 } 841 } 842 } 843 844 /** 845 * Return all APK names contained in this session. 846 * <p> 847 * This returns all names which have been previously written through 848 * {@link #openWrite(String, long, long)} as part of this session. 849 * 850 * @throws SecurityException if called after the session has been 851 * committed or abandoned. 852 */ 853 public @NonNull String[] getNames() throws IOException { 854 try { 855 return mSession.getNames(); 856 } catch (RuntimeException e) { 857 ExceptionUtils.maybeUnwrapIOException(e); 858 throw e; 859 } catch (RemoteException e) { 860 throw e.rethrowFromSystemServer(); 861 } 862 } 863 864 /** 865 * Open a stream to read an APK file from the session. 866 * <p> 867 * This is only valid for names which have been previously written 868 * through {@link #openWrite(String, long, long)} as part of this 869 * session. For example, this stream may be used to calculate a 870 * {@link MessageDigest} of a written APK before committing. 871 * 872 * @throws SecurityException if called after the session has been 873 * committed or abandoned. 874 */ 875 public @NonNull InputStream openRead(@NonNull String name) throws IOException { 876 try { 877 final ParcelFileDescriptor pfd = mSession.openRead(name); 878 return new ParcelFileDescriptor.AutoCloseInputStream(pfd); 879 } catch (RuntimeException e) { 880 ExceptionUtils.maybeUnwrapIOException(e); 881 throw e; 882 } catch (RemoteException e) { 883 throw e.rethrowFromSystemServer(); 884 } 885 } 886 887 /** 888 * Removes a split. 889 * <p> 890 * Split removals occur prior to adding new APKs. If upgrading a feature 891 * split, it is not expected nor desirable to remove the split prior to 892 * upgrading. 893 * <p> 894 * When split removal is bundled with new APKs, the packageName must be 895 * identical. 896 */ 897 public void removeSplit(@NonNull String splitName) throws IOException { 898 try { 899 mSession.removeSplit(splitName); 900 } catch (RuntimeException e) { 901 ExceptionUtils.maybeUnwrapIOException(e); 902 throw e; 903 } catch (RemoteException e) { 904 throw e.rethrowFromSystemServer(); 905 } 906 } 907 908 /** 909 * Attempt to commit everything staged in this session. This may require 910 * user intervention, and so it may not happen immediately. The final 911 * result of the commit will be reported through the given callback. 912 * <p> 913 * Once this method is called, the session is sealed and no additional 914 * mutations may be performed on the session. If the device reboots 915 * before the session has been finalized, you may commit the session again. 916 * 917 * @throws SecurityException if streams opened through 918 * {@link #openWrite(String, long, long)} are still open. 919 */ 920 public void commit(@NonNull IntentSender statusReceiver) { 921 try { 922 mSession.commit(statusReceiver, false); 923 } catch (RemoteException e) { 924 throw e.rethrowFromSystemServer(); 925 } 926 } 927 928 /** 929 * Attempt to commit a session that has been {@link #transfer(String) transferred}. 930 * 931 * <p>If the device reboots before the session has been finalized, you may commit the 932 * session again. 933 * 934 * <p>The caller of this method is responsible to ensure the safety of the session. As the 935 * session was created by another - usually less trusted - app, it is paramount that before 936 * committing <u>all</u> public and system {@link SessionInfo properties of the session} 937 * and <u>all</u> {@link #openRead(String) APKs} are verified by the caller. It might happen 938 * that new properties are added to the session with a new API revision. In this case the 939 * callers need to be updated. 940 * 941 * @param statusReceiver Callbacks called when the state of the session changes. 942 * 943 * @hide 944 */ 945 @SystemApi 946 @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) 947 public void commitTransferred(@NonNull IntentSender statusReceiver) { 948 try { 949 mSession.commit(statusReceiver, true); 950 } catch (RemoteException e) { 951 throw e.rethrowFromSystemServer(); 952 } 953 } 954 955 /** 956 * Transfer the session to a new owner. 957 * <p> 958 * Only sessions that update the installing app can be transferred. 959 * <p> 960 * After the transfer to a package with a different uid all method calls on the session 961 * will cause {@link SecurityException}s. 962 * <p> 963 * Once this method is called, the session is sealed and no additional mutations beside 964 * committing it may be performed on the session. 965 * 966 * @param packageName The package of the new owner. Needs to hold the INSTALL_PACKAGES 967 * permission. 968 * 969 * @throws PackageManager.NameNotFoundException if the new owner could not be found. 970 * @throws SecurityException if called after the session has been committed or abandoned. 971 * @throws SecurityException if the session does not update the original installer 972 * @throws SecurityException if streams opened through 973 * {@link #openWrite(String, long, long) are still open. 974 */ 975 public void transfer(@NonNull String packageName) 976 throws PackageManager.NameNotFoundException { 977 Preconditions.checkNotNull(packageName); 978 979 try { 980 mSession.transfer(packageName); 981 } catch (ParcelableException e) { 982 e.maybeRethrow(PackageManager.NameNotFoundException.class); 983 throw new RuntimeException(e); 984 } catch (RemoteException e) { 985 throw e.rethrowFromSystemServer(); 986 } 987 } 988 989 /** 990 * Release this session object. You can open the session again if it 991 * hasn't been finalized. 992 */ 993 @Override 994 public void close() { 995 try { 996 mSession.close(); 997 } catch (RemoteException e) { 998 throw e.rethrowFromSystemServer(); 999 } 1000 } 1001 1002 /** 1003 * Completely abandon this session, destroying all staged data and 1004 * rendering it invalid. Abandoned sessions will be reported to 1005 * {@link SessionCallback} listeners as failures. This is equivalent to 1006 * opening the session and calling {@link Session#abandon()}. 1007 */ 1008 public void abandon() { 1009 try { 1010 mSession.abandon(); 1011 } catch (RemoteException e) { 1012 throw e.rethrowFromSystemServer(); 1013 } 1014 } 1015 } 1016 1017 /** 1018 * Parameters for creating a new {@link PackageInstaller.Session}. 1019 */ 1020 public static class SessionParams implements Parcelable { 1021 1022 /** {@hide} */ 1023 public static final int MODE_INVALID = -1; 1024 1025 /** 1026 * Mode for an install session whose staged APKs should fully replace any 1027 * existing APKs for the target app. 1028 */ 1029 public static final int MODE_FULL_INSTALL = 1; 1030 1031 /** 1032 * Mode for an install session that should inherit any existing APKs for the 1033 * target app, unless they have been explicitly overridden (based on split 1034 * name) by the session. For example, this can be used to add one or more 1035 * split APKs to an existing installation. 1036 * <p> 1037 * If there are no existing APKs for the target app, this behaves like 1038 * {@link #MODE_FULL_INSTALL}. 1039 */ 1040 public static final int MODE_INHERIT_EXISTING = 2; 1041 1042 /** {@hide} */ 1043 public static final int UID_UNKNOWN = -1; 1044 1045 /** {@hide} */ 1046 public int mode = MODE_INVALID; 1047 /** {@hide} */ 1048 public int installFlags; 1049 /** {@hide} */ 1050 public int installLocation = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY; 1051 /** {@hide} */ 1052 public @InstallReason int installReason = PackageManager.INSTALL_REASON_UNKNOWN; 1053 /** {@hide} */ 1054 public long sizeBytes = -1; 1055 /** {@hide} */ 1056 public String appPackageName; 1057 /** {@hide} */ 1058 public Bitmap appIcon; 1059 /** {@hide} */ 1060 public String appLabel; 1061 /** {@hide} */ 1062 public long appIconLastModified = -1; 1063 /** {@hide} */ 1064 public Uri originatingUri; 1065 /** {@hide} */ 1066 public int originatingUid = UID_UNKNOWN; 1067 /** {@hide} */ 1068 public Uri referrerUri; 1069 /** {@hide} */ 1070 public String abiOverride; 1071 /** {@hide} */ 1072 public String volumeUuid; 1073 /** {@hide} */ 1074 public String[] grantedRuntimePermissions; 1075 1076 /** 1077 * Construct parameters for a new package install session. 1078 * 1079 * @param mode one of {@link #MODE_FULL_INSTALL} or 1080 * {@link #MODE_INHERIT_EXISTING} describing how the session 1081 * should interact with an existing app. 1082 */ 1083 public SessionParams(int mode) { 1084 this.mode = mode; 1085 } 1086 1087 /** {@hide} */ 1088 public SessionParams(Parcel source) { 1089 mode = source.readInt(); 1090 installFlags = source.readInt(); 1091 installLocation = source.readInt(); 1092 installReason = source.readInt(); 1093 sizeBytes = source.readLong(); 1094 appPackageName = source.readString(); 1095 appIcon = source.readParcelable(null); 1096 appLabel = source.readString(); 1097 originatingUri = source.readParcelable(null); 1098 originatingUid = source.readInt(); 1099 referrerUri = source.readParcelable(null); 1100 abiOverride = source.readString(); 1101 volumeUuid = source.readString(); 1102 grantedRuntimePermissions = source.readStringArray(); 1103 } 1104 1105 /** 1106 * Check if there are hidden options set. 1107 * 1108 * <p>Hidden options are those options that cannot be verified via public or system-api 1109 * methods on {@link SessionInfo}. 1110 * 1111 * @return {@code true} if any hidden option is set. 1112 * 1113 * @hide 1114 */ 1115 public boolean areHiddenOptionsSet() { 1116 return (installFlags & (PackageManager.INSTALL_ALLOW_DOWNGRADE 1117 | PackageManager.INSTALL_DONT_KILL_APP 1118 | PackageManager.INSTALL_INSTANT_APP 1119 | PackageManager.INSTALL_FULL_APP 1120 | PackageManager.INSTALL_VIRTUAL_PRELOAD 1121 | PackageManager.INSTALL_ALLOCATE_AGGRESSIVE)) != installFlags 1122 || abiOverride != null || volumeUuid != null; 1123 } 1124 1125 /** 1126 * Provide value of {@link PackageInfo#installLocation}, which may be used 1127 * to determine where the app will be staged. Defaults to 1128 * {@link PackageInfo#INSTALL_LOCATION_INTERNAL_ONLY}. 1129 */ 1130 public void setInstallLocation(int installLocation) { 1131 this.installLocation = installLocation; 1132 } 1133 1134 /** 1135 * Optionally indicate the total size (in bytes) of all APKs that will be 1136 * delivered in this session. The system may use this to ensure enough disk 1137 * space exists before proceeding, or to estimate container size for 1138 * installations living on external storage. 1139 * 1140 * @see PackageInfo#INSTALL_LOCATION_AUTO 1141 * @see PackageInfo#INSTALL_LOCATION_PREFER_EXTERNAL 1142 */ 1143 public void setSize(long sizeBytes) { 1144 this.sizeBytes = sizeBytes; 1145 } 1146 1147 /** 1148 * Optionally set the package name of the app being installed. It's strongly 1149 * recommended that you provide this value when known, so that observers can 1150 * communicate installing apps to users. 1151 * <p> 1152 * If the APKs staged in the session aren't consistent with this package 1153 * name, the install will fail. Regardless of this value, all APKs in the 1154 * app must have the same package name. 1155 */ 1156 public void setAppPackageName(@Nullable String appPackageName) { 1157 this.appPackageName = appPackageName; 1158 } 1159 1160 /** 1161 * Optionally set an icon representing the app being installed. This should 1162 * be roughly {@link ActivityManager#getLauncherLargeIconSize()} in both 1163 * dimensions. 1164 */ 1165 public void setAppIcon(@Nullable Bitmap appIcon) { 1166 this.appIcon = appIcon; 1167 } 1168 1169 /** 1170 * Optionally set a label representing the app being installed. 1171 */ 1172 public void setAppLabel(@Nullable CharSequence appLabel) { 1173 this.appLabel = (appLabel != null) ? appLabel.toString() : null; 1174 } 1175 1176 /** 1177 * Optionally set the URI where this package was downloaded from. This is 1178 * informational and may be used as a signal for anti-malware purposes. 1179 * 1180 * @see Intent#EXTRA_ORIGINATING_URI 1181 */ 1182 public void setOriginatingUri(@Nullable Uri originatingUri) { 1183 this.originatingUri = originatingUri; 1184 } 1185 1186 /** 1187 * Sets the UID that initiated package installation. This is informational 1188 * and may be used as a signal for anti-malware purposes. 1189 * 1190 * @see PackageManager#EXTRA_VERIFICATION_INSTALLER_UID 1191 */ 1192 public void setOriginatingUid(int originatingUid) { 1193 this.originatingUid = originatingUid; 1194 } 1195 1196 /** 1197 * Optionally set the URI that referred you to install this package. This is 1198 * informational and may be used as a signal for anti-malware purposes. 1199 * 1200 * @see Intent#EXTRA_REFERRER 1201 */ 1202 public void setReferrerUri(@Nullable Uri referrerUri) { 1203 this.referrerUri = referrerUri; 1204 } 1205 1206 /** 1207 * Sets which runtime permissions to be granted to the package at installation. 1208 * 1209 * @param permissions The permissions to grant or null to grant all runtime 1210 * permissions. 1211 * 1212 * @hide 1213 */ 1214 @SystemApi 1215 @RequiresPermission(android.Manifest.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS) 1216 public void setGrantedRuntimePermissions(String[] permissions) { 1217 installFlags |= PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS; 1218 this.grantedRuntimePermissions = permissions; 1219 } 1220 1221 /** {@hide} */ 1222 public void setInstallFlagsInternal() { 1223 installFlags |= PackageManager.INSTALL_INTERNAL; 1224 installFlags &= ~PackageManager.INSTALL_EXTERNAL; 1225 } 1226 1227 /** {@hide} */ 1228 @SystemApi 1229 public void setAllowDowngrade(boolean allowDowngrade) { 1230 if (allowDowngrade) { 1231 installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE; 1232 } else { 1233 installFlags &= ~PackageManager.INSTALL_ALLOW_DOWNGRADE; 1234 } 1235 } 1236 1237 /** {@hide} */ 1238 public void setInstallFlagsExternal() { 1239 installFlags |= PackageManager.INSTALL_EXTERNAL; 1240 installFlags &= ~PackageManager.INSTALL_INTERNAL; 1241 } 1242 1243 /** {@hide} */ 1244 public void setInstallFlagsForcePermissionPrompt() { 1245 installFlags |= PackageManager.INSTALL_FORCE_PERMISSION_PROMPT; 1246 } 1247 1248 /** {@hide} */ 1249 @SystemApi 1250 public void setDontKillApp(boolean dontKillApp) { 1251 if (dontKillApp) { 1252 installFlags |= PackageManager.INSTALL_DONT_KILL_APP; 1253 } else { 1254 installFlags &= ~PackageManager.INSTALL_DONT_KILL_APP; 1255 } 1256 } 1257 1258 /** {@hide} */ 1259 @SystemApi 1260 public void setInstallAsInstantApp(boolean isInstantApp) { 1261 if (isInstantApp) { 1262 installFlags |= PackageManager.INSTALL_INSTANT_APP; 1263 installFlags &= ~PackageManager.INSTALL_FULL_APP; 1264 } else { 1265 installFlags &= ~PackageManager.INSTALL_INSTANT_APP; 1266 installFlags |= PackageManager.INSTALL_FULL_APP; 1267 } 1268 } 1269 1270 /** 1271 * Sets the install as a virtual preload. Will only have effect when called 1272 * by the verifier. 1273 * {@hide} 1274 */ 1275 @SystemApi 1276 public void setInstallAsVirtualPreload() { 1277 installFlags |= PackageManager.INSTALL_VIRTUAL_PRELOAD; 1278 } 1279 1280 /** 1281 * Set the reason for installing this package. 1282 */ 1283 public void setInstallReason(@InstallReason int installReason) { 1284 this.installReason = installReason; 1285 } 1286 1287 /** {@hide} */ 1288 @SystemApi 1289 @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE) 1290 public void setAllocateAggressive(boolean allocateAggressive) { 1291 if (allocateAggressive) { 1292 installFlags |= PackageManager.INSTALL_ALLOCATE_AGGRESSIVE; 1293 } else { 1294 installFlags &= ~PackageManager.INSTALL_ALLOCATE_AGGRESSIVE; 1295 } 1296 } 1297 1298 /** {@hide} */ 1299 public void dump(IndentingPrintWriter pw) { 1300 pw.printPair("mode", mode); 1301 pw.printHexPair("installFlags", installFlags); 1302 pw.printPair("installLocation", installLocation); 1303 pw.printPair("sizeBytes", sizeBytes); 1304 pw.printPair("appPackageName", appPackageName); 1305 pw.printPair("appIcon", (appIcon != null)); 1306 pw.printPair("appLabel", appLabel); 1307 pw.printPair("originatingUri", originatingUri); 1308 pw.printPair("originatingUid", originatingUid); 1309 pw.printPair("referrerUri", referrerUri); 1310 pw.printPair("abiOverride", abiOverride); 1311 pw.printPair("volumeUuid", volumeUuid); 1312 pw.printPair("grantedRuntimePermissions", grantedRuntimePermissions); 1313 pw.println(); 1314 } 1315 1316 @Override 1317 public int describeContents() { 1318 return 0; 1319 } 1320 1321 @Override 1322 public void writeToParcel(Parcel dest, int flags) { 1323 dest.writeInt(mode); 1324 dest.writeInt(installFlags); 1325 dest.writeInt(installLocation); 1326 dest.writeInt(installReason); 1327 dest.writeLong(sizeBytes); 1328 dest.writeString(appPackageName); 1329 dest.writeParcelable(appIcon, flags); 1330 dest.writeString(appLabel); 1331 dest.writeParcelable(originatingUri, flags); 1332 dest.writeInt(originatingUid); 1333 dest.writeParcelable(referrerUri, flags); 1334 dest.writeString(abiOverride); 1335 dest.writeString(volumeUuid); 1336 dest.writeStringArray(grantedRuntimePermissions); 1337 } 1338 1339 public static final Parcelable.Creator<SessionParams> 1340 CREATOR = new Parcelable.Creator<SessionParams>() { 1341 @Override 1342 public SessionParams createFromParcel(Parcel p) { 1343 return new SessionParams(p); 1344 } 1345 1346 @Override 1347 public SessionParams[] newArray(int size) { 1348 return new SessionParams[size]; 1349 } 1350 }; 1351 } 1352 1353 /** 1354 * Details for an active install session. 1355 */ 1356 public static class SessionInfo implements Parcelable { 1357 1358 /** {@hide} */ 1359 public int sessionId; 1360 /** {@hide} */ 1361 public String installerPackageName; 1362 /** {@hide} */ 1363 public String resolvedBaseCodePath; 1364 /** {@hide} */ 1365 public float progress; 1366 /** {@hide} */ 1367 public boolean sealed; 1368 /** {@hide} */ 1369 public boolean active; 1370 1371 /** {@hide} */ 1372 public int mode; 1373 /** {@hide} */ 1374 public @InstallReason int installReason; 1375 /** {@hide} */ 1376 public long sizeBytes; 1377 /** {@hide} */ 1378 public String appPackageName; 1379 /** {@hide} */ 1380 public Bitmap appIcon; 1381 /** {@hide} */ 1382 public CharSequence appLabel; 1383 1384 /** {@hide} */ 1385 public int installLocation; 1386 /** {@hide} */ 1387 public Uri originatingUri; 1388 /** {@hide} */ 1389 public int originatingUid; 1390 /** {@hide} */ 1391 public Uri referrerUri; 1392 /** {@hide} */ 1393 public String[] grantedRuntimePermissions; 1394 /** {@hide} */ 1395 public int installFlags; 1396 1397 /** {@hide} */ 1398 public SessionInfo() { 1399 } 1400 1401 /** {@hide} */ 1402 public SessionInfo(Parcel source) { 1403 sessionId = source.readInt(); 1404 installerPackageName = source.readString(); 1405 resolvedBaseCodePath = source.readString(); 1406 progress = source.readFloat(); 1407 sealed = source.readInt() != 0; 1408 active = source.readInt() != 0; 1409 1410 mode = source.readInt(); 1411 installReason = source.readInt(); 1412 sizeBytes = source.readLong(); 1413 appPackageName = source.readString(); 1414 appIcon = source.readParcelable(null); 1415 appLabel = source.readString(); 1416 1417 installLocation = source.readInt(); 1418 originatingUri = source.readParcelable(null); 1419 originatingUid = source.readInt(); 1420 referrerUri = source.readParcelable(null); 1421 grantedRuntimePermissions = source.readStringArray(); 1422 installFlags = source.readInt(); 1423 } 1424 1425 /** 1426 * Return the ID for this session. 1427 */ 1428 public int getSessionId() { 1429 return sessionId; 1430 } 1431 1432 /** 1433 * Return the package name of the app that owns this session. 1434 */ 1435 public @Nullable String getInstallerPackageName() { 1436 return installerPackageName; 1437 } 1438 1439 /** 1440 * Return current overall progress of this session, between 0 and 1. 1441 * <p> 1442 * Note that this progress may not directly correspond to the value 1443 * reported by 1444 * {@link PackageInstaller.Session#setStagingProgress(float)}, as the 1445 * system may carve out a portion of the overall progress to represent 1446 * its own internal installation work. 1447 */ 1448 public float getProgress() { 1449 return progress; 1450 } 1451 1452 /** 1453 * Return if this session is currently active. 1454 * <p> 1455 * A session is considered active whenever there is ongoing forward 1456 * progress being made, such as the installer holding an open 1457 * {@link Session} instance while streaming data into place, or the 1458 * system optimizing code as the result of 1459 * {@link Session#commit(IntentSender)}. 1460 * <p> 1461 * If the installer closes the {@link Session} without committing, the 1462 * session is considered inactive until the installer opens the session 1463 * again. 1464 */ 1465 public boolean isActive() { 1466 return active; 1467 } 1468 1469 /** 1470 * Return if this session is sealed. 1471 * <p> 1472 * Once sealed, no further changes may be made to the session. A session 1473 * is sealed the moment {@link Session#commit(IntentSender)} is called. 1474 */ 1475 public boolean isSealed() { 1476 return sealed; 1477 } 1478 1479 /** 1480 * Return the reason for installing this package. 1481 * 1482 * @return The install reason. 1483 */ 1484 public @InstallReason int getInstallReason() { 1485 return installReason; 1486 } 1487 1488 /** {@hide} */ 1489 @Deprecated 1490 public boolean isOpen() { 1491 return isActive(); 1492 } 1493 1494 /** 1495 * Return the package name this session is working with. May be {@code null} 1496 * if unknown. 1497 */ 1498 public @Nullable String getAppPackageName() { 1499 return appPackageName; 1500 } 1501 1502 /** 1503 * Return an icon representing the app being installed. May be {@code null} 1504 * if unavailable. 1505 */ 1506 public @Nullable Bitmap getAppIcon() { 1507 if (appIcon == null) { 1508 // Icon may have been omitted for calls that return bulk session 1509 // lists, so try fetching the specific icon. 1510 try { 1511 final SessionInfo info = AppGlobals.getPackageManager().getPackageInstaller() 1512 .getSessionInfo(sessionId); 1513 appIcon = (info != null) ? info.appIcon : null; 1514 } catch (RemoteException e) { 1515 throw e.rethrowFromSystemServer(); 1516 } 1517 } 1518 return appIcon; 1519 } 1520 1521 /** 1522 * Return a label representing the app being installed. May be {@code null} 1523 * if unavailable. 1524 */ 1525 public @Nullable CharSequence getAppLabel() { 1526 return appLabel; 1527 } 1528 1529 /** 1530 * Return an Intent that can be started to view details about this install 1531 * session. This may surface actions such as pause, resume, or cancel. 1532 * <p> 1533 * In some cases, a matching Activity may not exist, so ensure you safeguard 1534 * against this. 1535 * 1536 * @see PackageInstaller#ACTION_SESSION_DETAILS 1537 */ 1538 public @Nullable Intent createDetailsIntent() { 1539 final Intent intent = new Intent(PackageInstaller.ACTION_SESSION_DETAILS); 1540 intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId); 1541 intent.setPackage(installerPackageName); 1542 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1543 return intent; 1544 } 1545 1546 /** 1547 * Get the mode of the session as set in the constructor of the {@link SessionParams}. 1548 * 1549 * @return One of {@link SessionParams#MODE_FULL_INSTALL} 1550 * or {@link SessionParams#MODE_INHERIT_EXISTING} 1551 */ 1552 public int getMode() { 1553 return mode; 1554 } 1555 1556 /** 1557 * Get the value set in {@link SessionParams#setInstallLocation(int)}. 1558 */ 1559 public int getInstallLocation() { 1560 return installLocation; 1561 } 1562 1563 /** 1564 * Get the value as set in {@link SessionParams#setSize(long)}. 1565 * 1566 * <p>The value is a hint and does not have to match the actual size. 1567 */ 1568 public long getSize() { 1569 return sizeBytes; 1570 } 1571 1572 /** 1573 * Get the value set in {@link SessionParams#setOriginatingUri(Uri)}. 1574 */ 1575 public @Nullable Uri getOriginatingUri() { 1576 return originatingUri; 1577 } 1578 1579 /** 1580 * Get the value set in {@link SessionParams#setOriginatingUid(int)}. 1581 */ 1582 public int getOriginatingUid() { 1583 return originatingUid; 1584 } 1585 1586 /** 1587 * Get the value set in {@link SessionParams#setReferrerUri(Uri)} 1588 */ 1589 public @Nullable Uri getReferrerUri() { 1590 return referrerUri; 1591 } 1592 1593 /** 1594 * Get the value set in {@link SessionParams#setGrantedRuntimePermissions(String[])}. 1595 * 1596 * @hide 1597 */ 1598 @SystemApi 1599 public @Nullable String[] getGrantedRuntimePermissions() { 1600 return grantedRuntimePermissions; 1601 } 1602 1603 /** 1604 * Get the value set in {@link SessionParams#setAllowDowngrade(boolean)}. 1605 * 1606 * @hide 1607 */ 1608 @SystemApi 1609 public boolean getAllowDowngrade() { 1610 return (installFlags & PackageManager.INSTALL_ALLOW_DOWNGRADE) != 0; 1611 } 1612 1613 /** 1614 * Get the value set in {@link SessionParams#setDontKillApp(boolean)}. 1615 * 1616 * @hide 1617 */ 1618 @SystemApi 1619 public boolean getDontKillApp() { 1620 return (installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0; 1621 } 1622 1623 /** 1624 * If {@link SessionParams#setInstallAsInstantApp(boolean)} was called with {@code true}, 1625 * return true. If it was called with {@code false} or if it was not called return false. 1626 * 1627 * @hide 1628 * 1629 * @see #getInstallAsFullApp 1630 */ 1631 @SystemApi 1632 public boolean getInstallAsInstantApp(boolean isInstantApp) { 1633 return (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0; 1634 } 1635 1636 /** 1637 * If {@link SessionParams#setInstallAsInstantApp(boolean)} was called with {@code false}, 1638 * return true. If it was called with {@code true} or if it was not called return false. 1639 * 1640 * @hide 1641 * 1642 * @see #getInstallAsInstantApp 1643 */ 1644 @SystemApi 1645 public boolean getInstallAsFullApp(boolean isInstantApp) { 1646 return (installFlags & PackageManager.INSTALL_FULL_APP) != 0; 1647 } 1648 1649 /** 1650 * Get if {@link SessionParams#setInstallAsVirtualPreload()} was called. 1651 * 1652 * @hide 1653 */ 1654 @SystemApi 1655 public boolean getInstallAsVirtualPreload() { 1656 return (installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0; 1657 } 1658 1659 /** 1660 * Get the value set in {@link SessionParams#setAllocateAggressive(boolean)}. 1661 * 1662 * @hide 1663 */ 1664 @SystemApi 1665 public boolean getAllocateAggressive() { 1666 return (installFlags & PackageManager.INSTALL_ALLOCATE_AGGRESSIVE) != 0; 1667 } 1668 1669 1670 /** {@hide} */ 1671 @Deprecated 1672 public @Nullable Intent getDetailsIntent() { 1673 return createDetailsIntent(); 1674 } 1675 1676 @Override 1677 public int describeContents() { 1678 return 0; 1679 } 1680 1681 @Override 1682 public void writeToParcel(Parcel dest, int flags) { 1683 dest.writeInt(sessionId); 1684 dest.writeString(installerPackageName); 1685 dest.writeString(resolvedBaseCodePath); 1686 dest.writeFloat(progress); 1687 dest.writeInt(sealed ? 1 : 0); 1688 dest.writeInt(active ? 1 : 0); 1689 1690 dest.writeInt(mode); 1691 dest.writeInt(installReason); 1692 dest.writeLong(sizeBytes); 1693 dest.writeString(appPackageName); 1694 dest.writeParcelable(appIcon, flags); 1695 dest.writeString(appLabel != null ? appLabel.toString() : null); 1696 1697 dest.writeInt(installLocation); 1698 dest.writeParcelable(originatingUri, flags); 1699 dest.writeInt(originatingUid); 1700 dest.writeParcelable(referrerUri, flags); 1701 dest.writeStringArray(grantedRuntimePermissions); 1702 dest.writeInt(installFlags); 1703 } 1704 1705 public static final Parcelable.Creator<SessionInfo> 1706 CREATOR = new Parcelable.Creator<SessionInfo>() { 1707 @Override 1708 public SessionInfo createFromParcel(Parcel p) { 1709 return new SessionInfo(p); 1710 } 1711 1712 @Override 1713 public SessionInfo[] newArray(int size) { 1714 return new SessionInfo[size]; 1715 } 1716 }; 1717 } 1718} 1719