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