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 com.android.server.pm; 18 19 import static android.app.admin.DevicePolicyResources.Strings.Core.PACKAGE_DELETED_BY_DO; 20 import static android.content.pm.PackageInstaller.LOCATION_DATA_APP; 21 import static android.content.pm.PackageInstaller.UNARCHIVAL_ERROR_INSTALLER_DISABLED; 22 import static android.content.pm.PackageInstaller.UNARCHIVAL_ERROR_INSTALLER_UNINSTALLED; 23 import static android.content.pm.PackageInstaller.UNARCHIVAL_ERROR_INSUFFICIENT_STORAGE; 24 import static android.content.pm.PackageInstaller.UNARCHIVAL_ERROR_NO_CONNECTIVITY; 25 import static android.content.pm.PackageInstaller.UNARCHIVAL_ERROR_USER_ACTION_NEEDED; 26 import static android.content.pm.PackageInstaller.UNARCHIVAL_GENERIC_ERROR; 27 import static android.content.pm.PackageInstaller.UNARCHIVAL_OK; 28 import static android.content.pm.PackageManager.DELETE_ARCHIVE; 29 import static android.content.pm.PackageManager.INSTALL_UNARCHIVE_DRAFT; 30 import static android.os.Process.INVALID_UID; 31 import static android.os.Process.SYSTEM_UID; 32 33 import static com.android.server.pm.PackageArchiver.isArchivingEnabled; 34 import static com.android.server.pm.PackageManagerService.SHELL_PACKAGE_NAME; 35 36 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; 37 import static org.xmlpull.v1.XmlPullParser.START_TAG; 38 39 import android.Manifest; 40 import android.annotation.NonNull; 41 import android.annotation.Nullable; 42 import android.app.ActivityManager; 43 import android.app.AppGlobals; 44 import android.app.AppOpsManager; 45 import android.app.BroadcastOptions; 46 import android.app.Notification; 47 import android.app.NotificationManager; 48 import android.app.PackageDeleteObserver; 49 import android.app.PendingIntent; 50 import android.app.admin.DevicePolicyEventLogger; 51 import android.app.admin.DevicePolicyManager; 52 import android.app.admin.DevicePolicyManagerInternal; 53 import android.content.Context; 54 import android.content.Intent; 55 import android.content.IntentSender; 56 import android.content.IntentSender.SendIntentException; 57 import android.content.pm.ApplicationInfo; 58 import android.content.pm.ArchivedPackageParcel; 59 import android.content.pm.Flags; 60 import android.content.pm.IPackageInstaller; 61 import android.content.pm.IPackageInstallerCallback; 62 import android.content.pm.IPackageInstallerSession; 63 import android.content.pm.PackageInfo; 64 import android.content.pm.PackageInstaller; 65 import android.content.pm.PackageInstaller.InstallConstraints; 66 import android.content.pm.PackageInstaller.InstallConstraintsResult; 67 import android.content.pm.PackageInstaller.SessionInfo; 68 import android.content.pm.PackageInstaller.SessionParams; 69 import android.content.pm.PackageInstaller.UnarchivalStatus; 70 import android.content.pm.PackageItemInfo; 71 import android.content.pm.PackageManager; 72 import android.content.pm.PackageManager.DeleteFlags; 73 import android.content.pm.ParceledListSlice; 74 import android.content.pm.VersionedPackage; 75 import android.content.pm.parsing.FrameworkParsingPackageUtils; 76 import android.graphics.Bitmap; 77 import android.net.Uri; 78 import android.os.Binder; 79 import android.os.Build; 80 import android.os.Bundle; 81 import android.os.Environment; 82 import android.os.Handler; 83 import android.os.HandlerThread; 84 import android.os.Looper; 85 import android.os.Message; 86 import android.os.ParcelableException; 87 import android.os.Process; 88 import android.os.RemoteCallback; 89 import android.os.RemoteCallbackList; 90 import android.os.RemoteException; 91 import android.os.SELinux; 92 import android.os.UserHandle; 93 import android.os.UserManager; 94 import android.os.storage.StorageManager; 95 import android.stats.devicepolicy.DevicePolicyEnums; 96 import android.system.ErrnoException; 97 import android.system.Os; 98 import android.text.TextUtils; 99 import android.text.format.DateUtils; 100 import android.util.ArraySet; 101 import android.util.AtomicFile; 102 import android.util.ExceptionUtils; 103 import android.util.Log; 104 import android.util.Slog; 105 import android.util.SparseArray; 106 import android.util.SparseBooleanArray; 107 import android.util.SparseIntArray; 108 import android.util.Xml; 109 110 import com.android.internal.R; 111 import com.android.internal.annotations.GuardedBy; 112 import com.android.internal.annotations.VisibleForTesting; 113 import com.android.internal.content.InstallLocationUtils; 114 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; 115 import com.android.internal.notification.SystemNotificationChannels; 116 import com.android.internal.pm.parsing.PackageParser2; 117 import com.android.internal.util.ImageUtils; 118 import com.android.internal.util.IndentingPrintWriter; 119 import com.android.modules.utils.TypedXmlPullParser; 120 import com.android.modules.utils.TypedXmlSerializer; 121 import com.android.server.IoThread; 122 import com.android.server.LocalServices; 123 import com.android.server.SystemConfig; 124 import com.android.server.SystemService; 125 import com.android.server.SystemServiceManager; 126 import com.android.server.pm.pkg.PackageStateInternal; 127 import com.android.server.pm.utils.RequestThrottle; 128 129 import libcore.io.IoUtils; 130 131 import org.xmlpull.v1.XmlPullParserException; 132 133 import java.io.File; 134 import java.io.FileInputStream; 135 import java.io.FileNotFoundException; 136 import java.io.FileOutputStream; 137 import java.io.FilenameFilter; 138 import java.io.IOException; 139 import java.security.SecureRandom; 140 import java.util.ArrayList; 141 import java.util.Collections; 142 import java.util.Comparator; 143 import java.util.List; 144 import java.util.Map; 145 import java.util.Objects; 146 import java.util.Random; 147 import java.util.Set; 148 import java.util.TreeMap; 149 import java.util.TreeSet; 150 import java.util.concurrent.CompletableFuture; 151 import java.util.function.IntPredicate; 152 import java.util.function.Supplier; 153 154 /** The service responsible for installing packages. */ 155 public class PackageInstallerService extends IPackageInstaller.Stub implements 156 PackageSessionProvider { 157 private static final String TAG = "PackageInstaller"; 158 private static final boolean LOGD = Log.isLoggable(TAG, Log.DEBUG); 159 160 private static final boolean DEBUG = Build.IS_DEBUGGABLE; 161 162 // TODO: remove outstanding sessions when installer package goes away 163 // TODO: notify listeners in other users when package has been installed there 164 // TODO: purge expired sessions periodically in addition to at reboot 165 166 /** XML constants used in {@link #mSessionsFile} */ 167 private static final String TAG_SESSIONS = "sessions"; 168 169 /** Automatically destroy sessions older than this */ 170 private static final long MAX_AGE_MILLIS = 3 * DateUtils.DAY_IN_MILLIS; 171 /** Automatically destroy staged sessions that have not changed state in this time */ 172 private static final long MAX_TIME_SINCE_UPDATE_MILLIS = 21 * DateUtils.DAY_IN_MILLIS; 173 /** Upper bound on number of active sessions for a UID that has INSTALL_PACKAGES */ 174 private static final long MAX_ACTIVE_SESSIONS_WITH_PERMISSION = 1024; 175 /** Upper bound on number of active sessions for a UID without INSTALL_PACKAGES */ 176 private static final long MAX_ACTIVE_SESSIONS_NO_PERMISSION = 50; 177 /** Upper bound on number of historical sessions for a UID */ 178 private static final long MAX_HISTORICAL_SESSIONS = 1048576; 179 /** Destroy sessions older than this on storage free request */ 180 private static final long MAX_SESSION_AGE_ON_LOW_STORAGE_MILLIS = 8 * DateUtils.HOUR_IN_MILLIS; 181 /** Maximum time to wait for install constraints to be satisfied */ 182 private static final long MAX_INSTALL_CONSTRAINTS_TIMEOUT_MILLIS = DateUtils.WEEK_IN_MILLIS; 183 184 /** Threshold of historical sessions size */ 185 private static final int HISTORICAL_SESSIONS_THRESHOLD = 500; 186 /** Size of historical sessions to be cleared when reaching threshold */ 187 private static final int HISTORICAL_CLEAR_SIZE = 400; 188 189 /** 190 * Allow verification-skipping if it's a development app installed through ADB with 191 * disable verification flag specified. 192 */ 193 private static final int ADB_DEV_MODE = PackageManager.INSTALL_FROM_ADB 194 | PackageManager.INSTALL_ALLOW_TEST; 195 196 /** 197 * Set of app op permissions that the installer of a session is allowed to change through 198 * {@link PackageInstaller.SessionParams#setPermissionState(String, int)}. 199 */ 200 public static final Set<String> INSTALLER_CHANGEABLE_APP_OP_PERMISSIONS = Set.of( 201 Manifest.permission.USE_FULL_SCREEN_INTENT 202 ); 203 204 final PackageArchiver mPackageArchiver; 205 206 private final Context mContext; 207 private final PackageManagerService mPm; 208 private final ApexManager mApexManager; 209 private final StagingManager mStagingManager; 210 211 private AppOpsManager mAppOps; 212 213 private final HandlerThread mInstallThread; 214 private final Handler mInstallHandler; 215 216 private final Callbacks mCallbacks; 217 218 private volatile boolean mOkToSendBroadcasts = false; 219 private volatile boolean mBypassNextStagedInstallerCheck = false; 220 private volatile boolean mBypassNextAllowedApexUpdateCheck = false; 221 private volatile int mDisableVerificationForUid = INVALID_UID; 222 223 /** 224 * File storing persisted {@link #mSessions} metadata. 225 */ 226 private final AtomicFile mSessionsFile; 227 228 /** 229 * Directory storing persisted {@link #mSessions} metadata which is too 230 * heavy to store directly in {@link #mSessionsFile}. 231 */ 232 private final File mSessionsDir; 233 234 private final InternalCallback mInternalCallback = new InternalCallback(); 235 private final PackageSessionVerifier mSessionVerifier; 236 private final GentleUpdateHelper mGentleUpdateHelper; 237 238 /** 239 * Used for generating session IDs. Since this is created at boot time, 240 * normal random might be predictable. 241 */ 242 private final Random mRandom = new SecureRandom(); 243 244 /** All sessions allocated */ 245 @GuardedBy("mSessions") 246 private final SparseBooleanArray mAllocatedSessions = new SparseBooleanArray(); 247 248 @GuardedBy("mSessions") 249 private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>(); 250 251 /** Historical sessions kept around for debugging purposes */ 252 @GuardedBy("mSessions") 253 private final List<PackageInstallerHistoricalSession> mHistoricalSessions = new ArrayList<>(); 254 255 @GuardedBy("mSessions") 256 private final SparseIntArray mHistoricalSessionsByInstaller = new SparseIntArray(); 257 258 /** Sessions allocated to legacy users */ 259 @GuardedBy("mSessions") 260 private final SparseBooleanArray mLegacySessions = new SparseBooleanArray(); 261 262 /** Policy for allowing a silent update. */ 263 private final SilentUpdatePolicy mSilentUpdatePolicy = new SilentUpdatePolicy(); 264 265 private static final FilenameFilter sStageFilter = new FilenameFilter() { 266 @Override 267 public boolean accept(File dir, String name) { 268 return isStageName(name); 269 } 270 }; 271 272 private static final class Lifecycle extends SystemService { 273 private final PackageInstallerService mPackageInstallerService; 274 Lifecycle(Context context, PackageInstallerService service)275 Lifecycle(Context context, PackageInstallerService service) { 276 super(context); 277 mPackageInstallerService = service; 278 } 279 280 @Override onStart()281 public void onStart() { 282 // no-op 283 } 284 285 @Override onBootPhase(int phase)286 public void onBootPhase(int phase) { 287 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) { 288 mPackageInstallerService.onBroadcastReady(); 289 } 290 } 291 } 292 293 @NonNull 294 private final RequestThrottle mSettingsWriteRequest = new RequestThrottle(IoThread.getHandler(), 295 () -> { 296 return writeSessions(); 297 }); 298 PackageInstallerService(Context context, PackageManagerService pm, Supplier<PackageParser2> apexParserSupplier)299 public PackageInstallerService(Context context, PackageManagerService pm, 300 Supplier<PackageParser2> apexParserSupplier) { 301 mContext = context; 302 mPm = pm; 303 304 mInstallThread = new HandlerThread(TAG); 305 mInstallThread.start(); 306 307 mInstallHandler = new Handler(mInstallThread.getLooper()); 308 309 mCallbacks = new Callbacks(mInstallThread.getLooper()); 310 311 mSessionsFile = new AtomicFile( 312 new File(Environment.getDataSystemDirectory(), "install_sessions.xml"), 313 "package-session"); 314 mSessionsDir = new File(Environment.getDataSystemDirectory(), "install_sessions"); 315 mSessionsDir.mkdirs(); 316 317 mApexManager = ApexManager.getInstance(); 318 mStagingManager = new StagingManager(context); 319 mSessionVerifier = new PackageSessionVerifier(context, mPm, mApexManager, 320 apexParserSupplier, mInstallThread.getLooper()); 321 mGentleUpdateHelper = new GentleUpdateHelper( 322 context, mInstallThread.getLooper(), new AppStateHelper(context)); 323 mPackageArchiver = new PackageArchiver(mContext, mPm); 324 325 LocalServices.getService(SystemServiceManager.class).startService( 326 new Lifecycle(context, this)); 327 } 328 getStagingManager()329 StagingManager getStagingManager() { 330 return mStagingManager; 331 } 332 okToSendBroadcasts()333 boolean okToSendBroadcasts() { 334 return mOkToSendBroadcasts; 335 } 336 systemReady()337 public void systemReady() { 338 mAppOps = mContext.getSystemService(AppOpsManager.class); 339 mStagingManager.systemReady(); 340 mGentleUpdateHelper.systemReady(); 341 342 synchronized (mSessions) { 343 readSessionsLocked(); 344 expireSessionsLocked(); 345 346 reconcileStagesLocked(StorageManager.UUID_PRIVATE_INTERNAL); 347 348 final ArraySet<File> unclaimedIcons = newArraySet( 349 mSessionsDir.listFiles()); 350 351 // Ignore stages and icons claimed by active sessions 352 for (int i = 0; i < mSessions.size(); i++) { 353 final PackageInstallerSession session = mSessions.valueAt(i); 354 unclaimedIcons.remove(buildAppIconFile(session.sessionId)); 355 } 356 357 // Clean up orphaned icons 358 for (File icon : unclaimedIcons) { 359 Slog.w(TAG, "Deleting orphan icon " + icon); 360 icon.delete(); 361 } 362 363 // Invalid sessions might have been marked while parsing. Re-write the database with 364 // the updated information. 365 mSettingsWriteRequest.runNow(); 366 367 } 368 } 369 onBroadcastReady()370 private void onBroadcastReady() { 371 // Broadcasts are not sent while we restore sessions on boot, since no processes would be 372 // ready to listen to them. From now on, it is safe to send broadcasts which otherwise will 373 // be rejected by ActivityManagerService if its systemReady() is not completed. 374 mOkToSendBroadcasts = true; 375 } 376 restoreAndApplyStagedSessionIfNeeded()377 void restoreAndApplyStagedSessionIfNeeded() { 378 List<StagingManager.StagedSession> stagedSessionsToRestore = new ArrayList<>(); 379 synchronized (mSessions) { 380 for (int i = 0; i < mSessions.size(); i++) { 381 final PackageInstallerSession session = mSessions.valueAt(i); 382 if (!session.isStaged()) { 383 continue; 384 } 385 StagingManager.StagedSession stagedSession = session.mStagedSession; 386 if (!stagedSession.isInTerminalState() && stagedSession.hasParentSessionId() 387 && getSession(stagedSession.getParentSessionId()) == null) { 388 stagedSession.setSessionFailed(PackageManager.INSTALL_ACTIVATION_FAILED, 389 "An orphan staged session " + stagedSession.sessionId() + " is found, " 390 + "parent " + stagedSession.getParentSessionId() + " is missing"); 391 continue; 392 } 393 if (!stagedSession.hasParentSessionId() && stagedSession.isCommitted() 394 && !stagedSession.isInTerminalState()) { 395 // StagingManager.restoreSessions expects a list of committed, non-finalized 396 // parent staged sessions. 397 stagedSessionsToRestore.add(stagedSession); 398 } 399 } 400 } 401 // Don't hold mSessions lock when calling restoreSessions, since it might trigger an APK 402 // atomic install which needs to query sessions, which requires lock on mSessions. 403 // Note: restoreSessions mutates content of stagedSessionsToRestore. 404 mStagingManager.restoreSessions(stagedSessionsToRestore, mPm.isDeviceUpgrading()); 405 } 406 407 @GuardedBy("mSessions") reconcileStagesLocked(String volumeUuid)408 private void reconcileStagesLocked(String volumeUuid) { 409 final ArraySet<File> unclaimedStages = getStagingDirsOnVolume(volumeUuid); 410 // Ignore stages claimed by active sessions 411 for (int i = 0; i < mSessions.size(); i++) { 412 final PackageInstallerSession session = mSessions.valueAt(i); 413 unclaimedStages.remove(session.stageDir); 414 } 415 removeStagingDirs(unclaimedStages); 416 } 417 getStagingDirsOnVolume(String volumeUuid)418 private ArraySet<File> getStagingDirsOnVolume(String volumeUuid) { 419 final File stagingDir = getTmpSessionDir(volumeUuid); 420 final ArraySet<File> stagingDirs = newArraySet(stagingDir.listFiles(sStageFilter)); 421 422 // We also need to clean up orphaned staging directory for staged sessions 423 final File stagedSessionStagingDir = Environment.getDataStagingDirectory(volumeUuid); 424 stagingDirs.addAll(newArraySet(stagedSessionStagingDir.listFiles())); 425 return stagingDirs; 426 } 427 removeStagingDirs(ArraySet<File> stagingDirsToRemove)428 private void removeStagingDirs(ArraySet<File> stagingDirsToRemove) { 429 // Clean up orphaned staging directories 430 for (File stage : stagingDirsToRemove) { 431 Slog.w(TAG, "Deleting orphan stage " + stage); 432 mPm.removeCodePath(stage); 433 } 434 } 435 onPrivateVolumeMounted(String volumeUuid)436 public void onPrivateVolumeMounted(String volumeUuid) { 437 synchronized (mSessions) { 438 reconcileStagesLocked(volumeUuid); 439 } 440 } 441 442 /** 443 * Called to free up some storage space from obsolete installation files 444 */ freeStageDirs(String volumeUuid)445 public void freeStageDirs(String volumeUuid) { 446 final ArraySet<File> unclaimedStagingDirsOnVolume = getStagingDirsOnVolume(volumeUuid); 447 final long currentTimeMillis = System.currentTimeMillis(); 448 synchronized (mSessions) { 449 for (int i = 0; i < mSessions.size(); i++) { 450 final PackageInstallerSession session = mSessions.valueAt(i); 451 if (!unclaimedStagingDirsOnVolume.contains(session.stageDir)) { 452 // Only handles sessions stored on the target volume 453 continue; 454 } 455 final long age = currentTimeMillis - session.createdMillis; 456 if (age >= MAX_SESSION_AGE_ON_LOW_STORAGE_MILLIS) { 457 // Aggressively close old sessions because we are running low on storage 458 // Their staging dirs will be removed too 459 PackageInstallerSession root = !session.hasParentSessionId() 460 ? session : mSessions.get(session.getParentSessionId()); 461 if (root == null) { 462 Slog.e(TAG, "freeStageDirs: found an orphaned session: " 463 + session.sessionId + " parent=" + session.getParentSessionId()); 464 } else if (!root.isDestroyed()) { 465 root.abandon(); 466 } 467 } else { 468 // Session is new enough, so it deserves to be kept even on low storage 469 unclaimedStagingDirsOnVolume.remove(session.stageDir); 470 } 471 } 472 } 473 removeStagingDirs(unclaimedStagingDirsOnVolume); 474 } 475 476 @Deprecated allocateStageDirLegacy(String volumeUuid, boolean isEphemeral)477 public File allocateStageDirLegacy(String volumeUuid, boolean isEphemeral) throws IOException { 478 synchronized (mSessions) { 479 try { 480 final int sessionId = allocateSessionIdLocked(); 481 mLegacySessions.put(sessionId, true); 482 final File sessionStageDir = buildTmpSessionDir(sessionId, volumeUuid); 483 prepareStageDir(sessionStageDir); 484 return sessionStageDir; 485 } catch (IllegalStateException e) { 486 throw new IOException(e); 487 } 488 } 489 } 490 491 @Deprecated allocateExternalStageCidLegacy()492 public String allocateExternalStageCidLegacy() { 493 synchronized (mSessions) { 494 final int sessionId = allocateSessionIdLocked(); 495 mLegacySessions.put(sessionId, true); 496 return "smdl" + sessionId + ".tmp"; 497 } 498 } 499 500 @GuardedBy("mSessions") readSessionsLocked()501 private void readSessionsLocked() { 502 if (LOGD) Slog.v(TAG, "readSessionsLocked()"); 503 504 mSessions.clear(); 505 506 FileInputStream fis = null; 507 try { 508 fis = mSessionsFile.openRead(); 509 final TypedXmlPullParser in = Xml.resolvePullParser(fis); 510 511 int type; 512 while ((type = in.next()) != END_DOCUMENT) { 513 if (type == START_TAG) { 514 final String tag = in.getName(); 515 if (PackageInstallerSession.TAG_SESSION.equals(tag)) { 516 final PackageInstallerSession session; 517 try { 518 session = PackageInstallerSession.readFromXml(in, mInternalCallback, 519 mContext, mPm, mInstallThread.getLooper(), mStagingManager, 520 mSessionsDir, this, mSilentUpdatePolicy); 521 } catch (Exception e) { 522 Slog.e(TAG, "Could not read session", e); 523 continue; 524 } 525 mSessions.put(session.sessionId, session); 526 mAllocatedSessions.put(session.sessionId, true); 527 } 528 } 529 } 530 } catch (FileNotFoundException e) { 531 // Missing sessions are okay, probably first boot 532 } catch (IOException | XmlPullParserException | ArrayIndexOutOfBoundsException e) { 533 Slog.wtf(TAG, "Failed reading install sessions", e); 534 } finally { 535 IoUtils.closeQuietly(fis); 536 } 537 // After reboot housekeeping. 538 for (int i = 0; i < mSessions.size(); ++i) { 539 PackageInstallerSession session = mSessions.valueAt(i); 540 session.onAfterSessionRead(mSessions); 541 } 542 } 543 544 @GuardedBy("mSessions") expireSessionsLocked()545 private void expireSessionsLocked() { 546 SparseArray<PackageInstallerSession> tmp = mSessions.clone(); 547 final int n = tmp.size(); 548 for (int i = 0; i < n; ++i) { 549 PackageInstallerSession session = tmp.valueAt(i); 550 if (session.hasParentSessionId()) { 551 // Child sessions will be expired when handling parent sessions 552 continue; 553 } 554 final long age = System.currentTimeMillis() - session.createdMillis; 555 final long timeSinceUpdate = System.currentTimeMillis() - session.getUpdatedMillis(); 556 final boolean valid; 557 if (session.isStaged()) { 558 valid = !session.isStagedAndInTerminalState() 559 || timeSinceUpdate < MAX_TIME_SINCE_UPDATE_MILLIS; 560 } else if (age >= MAX_AGE_MILLIS) { 561 Slog.w(TAG, "Abandoning old session created at " 562 + session.createdMillis); 563 valid = false; 564 } else { 565 valid = true; 566 } 567 if (!valid) { 568 Slog.w(TAG, "Remove old session: " + session.sessionId); 569 // Remove expired sessions as well as child sessions if any 570 removeActiveSession(session); 571 } 572 } 573 } 574 575 /** 576 * Moves a session (including the child sessions) from mSessions to mHistoricalSessions. 577 * This should only be called on a root session. 578 */ 579 @GuardedBy("mSessions") 580 private void removeActiveSession(PackageInstallerSession session) { 581 mSessions.remove(session.sessionId); 582 addHistoricalSessionLocked(session); 583 for (PackageInstallerSession child : session.getChildSessions()) { 584 mSessions.remove(child.sessionId); 585 addHistoricalSessionLocked(child); 586 } 587 } 588 589 @GuardedBy("mSessions") 590 private void addHistoricalSessionLocked(PackageInstallerSession session) { 591 if (mHistoricalSessions.size() > HISTORICAL_SESSIONS_THRESHOLD) { 592 Slog.d(TAG, "Historical sessions size reaches threshold, clear the oldest"); 593 mHistoricalSessions.subList(0, HISTORICAL_CLEAR_SIZE).clear(); 594 } 595 mHistoricalSessions.add(session.createHistoricalSession()); 596 597 int installerUid = session.getInstallerUid(); 598 // Increment the number of sessions by this installerUid. 599 mHistoricalSessionsByInstaller.put(installerUid, 600 mHistoricalSessionsByInstaller.get(installerUid) + 1); 601 } 602 603 private boolean writeSessions() { 604 if (LOGD) Slog.v(TAG, "writeSessions()"); 605 final PackageInstallerSession[] sessions; 606 synchronized (mSessions) { 607 final int size = mSessions.size(); 608 sessions = new PackageInstallerSession[size]; 609 for (int i = 0; i < size; i++) { 610 sessions[i] = mSessions.valueAt(i); 611 } 612 } 613 614 FileOutputStream fos = null; 615 try { 616 fos = mSessionsFile.startWrite(); 617 618 final TypedXmlSerializer out = Xml.resolveSerializer(fos); 619 out.startDocument(null, true); 620 out.startTag(null, TAG_SESSIONS); 621 for (var session : sessions) { 622 session.write(out, mSessionsDir); 623 } 624 out.endTag(null, TAG_SESSIONS); 625 out.endDocument(); 626 627 mSessionsFile.finishWrite(fos); 628 return true; 629 } catch (IOException e) { 630 if (fos != null) { 631 mSessionsFile.failWrite(fos); 632 } 633 } 634 635 return false; 636 } 637 638 private File buildAppIconFile(int sessionId) { 639 return new File(mSessionsDir, "app_icon." + sessionId + ".png"); 640 } 641 642 @Override 643 public int createSession(SessionParams params, String installerPackageName, 644 String callingAttributionTag, int userId) { 645 try { 646 if (params.dataLoaderParams != null 647 && mContext.checkCallingOrSelfPermission(Manifest.permission.USE_INSTALLER_V2) 648 != PackageManager.PERMISSION_GRANTED) { 649 throw new SecurityException("You need the " 650 + "com.android.permission.USE_INSTALLER_V2 permission " 651 + "to use a data loader"); 652 } 653 654 // Draft sessions cannot be created through the public API. 655 params.installFlags &= ~PackageManager.INSTALL_UNARCHIVE_DRAFT; 656 return createSessionInternal(params, installerPackageName, callingAttributionTag, 657 Binder.getCallingUid(), userId); 658 } catch (IOException e) { 659 throw ExceptionUtils.wrap(e); 660 } 661 } 662 663 int createSessionInternal(SessionParams params, String installerPackageName, 664 String installerAttributionTag, int callingUid, int userId) 665 throws IOException { 666 final Computer snapshot = mPm.snapshotComputer(); 667 snapshot.enforceCrossUserPermission(callingUid, userId, true, true, "createSession"); 668 669 if (mPm.isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) { 670 throw new SecurityException("User restriction prevents installing"); 671 } 672 673 // INSTALL_REASON_ROLLBACK allows an app to be rolled back without requiring the ROLLBACK 674 // capability; ensure if this is set as the install reason the app has one of the necessary 675 // signature permissions to perform the rollback. 676 if (params.installReason == PackageManager.INSTALL_REASON_ROLLBACK) { 677 if (mContext.checkCallingOrSelfPermission(Manifest.permission.MANAGE_ROLLBACKS) 678 != PackageManager.PERMISSION_GRANTED && 679 mContext.checkCallingOrSelfPermission(Manifest.permission.TEST_MANAGE_ROLLBACKS) 680 != PackageManager.PERMISSION_GRANTED) { 681 throw new SecurityException( 682 "INSTALL_REASON_ROLLBACK requires the MANAGE_ROLLBACKS permission or the " 683 + "TEST_MANAGE_ROLLBACKS permission"); 684 } 685 } 686 687 // App package name and label length is restricted so that really long strings aren't 688 // written to disk. 689 if (params.appPackageName != null && !isValidPackageName(params.appPackageName)) { 690 params.appPackageName = null; 691 } 692 693 params.appLabel = TextUtils.trimToSize(params.appLabel, 694 PackageItemInfo.MAX_SAFE_LABEL_LENGTH); 695 696 // Validate requested installer package name. 697 if (params.installerPackageName != null && !isValidPackageName( 698 params.installerPackageName)) { 699 params.installerPackageName = null; 700 } 701 702 // Validate installer package name. 703 if (installerPackageName != null && !isValidPackageName(installerPackageName)) { 704 installerPackageName = null; 705 } 706 707 String requestedInstallerPackageName = 708 params.installerPackageName != null ? params.installerPackageName 709 : installerPackageName; 710 711 if (PackageManagerServiceUtils.isRootOrShell(callingUid) 712 || PackageInstallerSession.isSystemDataLoaderInstallation(params) 713 || PackageManagerServiceUtils.isAdoptedShell(callingUid, mContext)) { 714 params.installFlags |= PackageManager.INSTALL_FROM_ADB; 715 // adb installs can override the installingPackageName, but not the 716 // initiatingPackageName 717 installerPackageName = SHELL_PACKAGE_NAME; 718 } else { 719 if (callingUid != SYSTEM_UID) { 720 // The supplied installerPackageName must always belong to the calling app. 721 mAppOps.checkPackage(callingUid, installerPackageName); 722 } 723 // Only apps with INSTALL_PACKAGES are allowed to set an installer that is not the 724 // caller. 725 if (!TextUtils.equals(requestedInstallerPackageName, installerPackageName)) { 726 if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES) 727 != PackageManager.PERMISSION_GRANTED) { 728 mAppOps.checkPackage(callingUid, requestedInstallerPackageName); 729 } 730 } 731 732 params.installFlags &= ~PackageManager.INSTALL_FROM_ADB; 733 params.installFlags &= ~PackageManager.INSTALL_ALL_USERS; 734 params.installFlags &= ~PackageManager.INSTALL_ARCHIVED; 735 params.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING; 736 if ((params.installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0 737 && !mPm.isCallerVerifier(snapshot, callingUid)) { 738 params.installFlags &= ~PackageManager.INSTALL_VIRTUAL_PRELOAD; 739 } 740 if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_TEST_ONLY_PACKAGE) 741 != PackageManager.PERMISSION_GRANTED) { 742 params.installFlags &= ~PackageManager.INSTALL_ALLOW_TEST; 743 } 744 745 // developmentInstallFlags can ony be set by shell or root. 746 params.developmentInstallFlags = 0; 747 } 748 749 String originatingPackageName = null; 750 if (params.originatingUid != SessionParams.UID_UNKNOWN 751 && params.originatingUid != callingUid) { 752 String[] packages = snapshot.getPackagesForUid(params.originatingUid); 753 if (packages != null && packages.length > 0) { 754 // Choose an arbitrary representative package in the case of a shared UID. 755 originatingPackageName = packages[0]; 756 } 757 } 758 759 if (Build.IS_DEBUGGABLE || PackageManagerServiceUtils.isSystemOrRoot(callingUid)) { 760 params.installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE; 761 } else { 762 params.installFlags &= ~PackageManager.INSTALL_ALLOW_DOWNGRADE; 763 } 764 765 if (mDisableVerificationForUid != INVALID_UID) { 766 if (callingUid == mDisableVerificationForUid) { 767 params.installFlags |= PackageManager.INSTALL_DISABLE_VERIFICATION; 768 } else { 769 // Clear the flag if current calling uid doesn't match the requested uid. 770 params.installFlags &= ~PackageManager.INSTALL_DISABLE_VERIFICATION; 771 } 772 // Reset the field as this is a one-off request. 773 mDisableVerificationForUid = INVALID_UID; 774 } else if ((params.installFlags & ADB_DEV_MODE) != ADB_DEV_MODE) { 775 // Only tools under specific conditions (test app installed through ADB, and 776 // verification disabled flag specified) can disable verification. 777 params.installFlags &= ~PackageManager.INSTALL_DISABLE_VERIFICATION; 778 } 779 780 if (Flags.rollbackLifetime()) { 781 if (params.rollbackLifetimeMillis > 0) { 782 if ((params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) == 0) { 783 throw new IllegalArgumentException( 784 "Can't set rollbackLifetimeMillis when rollback is not enabled"); 785 } 786 if (mContext.checkCallingOrSelfPermission(Manifest.permission.MANAGE_ROLLBACKS) 787 != PackageManager.PERMISSION_GRANTED) { 788 throw new SecurityException( 789 "Setting rollback lifetime requires the MANAGE_ROLLBACKS permission"); 790 } 791 } else if (params.rollbackLifetimeMillis < 0) { 792 throw new IllegalArgumentException("rollbackLifetimeMillis can't be negative."); 793 } 794 } 795 796 if (Flags.recoverabilityDetection()) { 797 if (params.rollbackImpactLevel == PackageManager.ROLLBACK_USER_IMPACT_HIGH 798 || params.rollbackImpactLevel 799 == PackageManager.ROLLBACK_USER_IMPACT_ONLY_MANUAL) { 800 if ((params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) == 0) { 801 throw new IllegalArgumentException( 802 "Can't set rollbackImpactLevel when rollback is not enabled"); 803 } 804 if (mContext.checkCallingOrSelfPermission(Manifest.permission.MANAGE_ROLLBACKS) 805 != PackageManager.PERMISSION_GRANTED) { 806 throw new SecurityException( 807 "Setting rollbackImpactLevel requires the MANAGE_ROLLBACKS permission"); 808 } 809 } else if (params.rollbackImpactLevel < 0) { 810 throw new IllegalArgumentException("rollbackImpactLevel can't be negative."); 811 } 812 } 813 814 boolean isApex = (params.installFlags & PackageManager.INSTALL_APEX) != 0; 815 if (isApex) { 816 if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGE_UPDATES) 817 == PackageManager.PERMISSION_DENIED 818 && mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES) 819 == PackageManager.PERMISSION_DENIED) { 820 throw new SecurityException("Not allowed to perform APEX updates"); 821 } 822 } else if (params.isStaged) { 823 mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, TAG); 824 } 825 826 if (isApex) { 827 if (!mApexManager.isApexSupported()) { 828 throw new IllegalArgumentException( 829 "This device doesn't support the installation of APEX files"); 830 } 831 if (params.isMultiPackage) { 832 throw new IllegalArgumentException("A multi-session can't be set as APEX."); 833 } 834 if (PackageManagerServiceUtils.isSystemOrRootOrShell(callingUid) 835 || mBypassNextAllowedApexUpdateCheck) { 836 params.installFlags |= PackageManager.INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK; 837 } else { 838 // Only specific APEX updates (installed through ADB, or for CTS tests) can disable 839 // allowed APEX update check. 840 params.installFlags &= ~PackageManager.INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK; 841 } 842 } 843 844 if ((params.installFlags & PackageManager.INSTALL_BYPASS_LOW_TARGET_SDK_BLOCK) != 0 845 && !PackageManagerServiceUtils.isSystemOrRootOrShell(callingUid) 846 && !Build.IS_DEBUGGABLE 847 && !PackageManagerServiceUtils.isAdoptedShell(callingUid, mContext)) { 848 // If the bypass flag is set, but not running as system root or shell then remove 849 // the flag 850 params.installFlags &= ~PackageManager.INSTALL_BYPASS_LOW_TARGET_SDK_BLOCK; 851 } 852 853 params.installFlags &= ~PackageManager.INSTALL_UNARCHIVE; 854 if (isArchivingEnabled() && params.appPackageName != null) { 855 PackageStateInternal ps = mPm.snapshotComputer().getPackageStateInternal( 856 params.appPackageName, SYSTEM_UID); 857 if (ps != null 858 && PackageArchiver.isArchived(ps.getUserStateOrDefault(userId)) 859 && PackageArchiver.getResponsibleInstallerPackage(ps) 860 .equals(requestedInstallerPackageName)) { 861 params.installFlags |= PackageManager.INSTALL_UNARCHIVE; 862 } 863 } 864 865 if ((params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0 866 && !PackageManagerServiceUtils.isSystemOrRootOrShell(callingUid) 867 && (snapshot.getFlagsForUid(callingUid) & ApplicationInfo.FLAG_SYSTEM) 868 == 0) { 869 throw new SecurityException( 870 "Only system apps could use the PackageManager.INSTALL_INSTANT_APP flag."); 871 } 872 873 if (params.isStaged && !PackageManagerServiceUtils.isSystemOrRootOrShell(callingUid)) { 874 if (!mBypassNextStagedInstallerCheck 875 && !isStagedInstallerAllowed(requestedInstallerPackageName)) { 876 throw new SecurityException("Installer not allowed to commit staged install"); 877 } 878 } 879 if (isApex && !PackageManagerServiceUtils.isSystemOrRootOrShell(callingUid)) { 880 if (!mBypassNextStagedInstallerCheck 881 && !isStagedInstallerAllowed(requestedInstallerPackageName)) { 882 throw new SecurityException( 883 "Installer not allowed to commit non-staged APEX install"); 884 } 885 } 886 887 mBypassNextStagedInstallerCheck = false; 888 mBypassNextAllowedApexUpdateCheck = false; 889 890 if (!params.isMultiPackage) { 891 var hasInstallGrantRuntimePermissions = mContext.checkCallingOrSelfPermission( 892 Manifest.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS) 893 == PackageManager.PERMISSION_GRANTED; 894 895 // Only system components can circumvent runtime permissions when installing. 896 if ((params.installFlags & PackageManager.INSTALL_GRANT_ALL_REQUESTED_PERMISSIONS) != 0 897 && !hasInstallGrantRuntimePermissions) { 898 throw new SecurityException("You need the " 899 + Manifest.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS 900 + " permission to use the" 901 + " PackageManager.INSTALL_GRANT_ALL_REQUESTED_PERMISSIONS flag"); 902 } 903 904 var permissionStates = params.getPermissionStates(); 905 if (!permissionStates.isEmpty()) { 906 if (!hasInstallGrantRuntimePermissions) { 907 for (int index = 0; index < permissionStates.size(); index++) { 908 var permissionName = permissionStates.keyAt(index); 909 if (!INSTALLER_CHANGEABLE_APP_OP_PERMISSIONS.contains(permissionName)) { 910 throw new SecurityException("You need the " 911 + Manifest.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS 912 + " permission to grant runtime permissions for a session"); 913 } 914 } 915 } 916 } 917 918 // Defensively resize giant app icons 919 if (params.appIcon != null) { 920 final ActivityManager am = (ActivityManager) mContext.getSystemService( 921 Context.ACTIVITY_SERVICE); 922 final int iconSize = am.getLauncherLargeIconSize(); 923 if ((params.appIcon.getWidth() > iconSize * 2) 924 || (params.appIcon.getHeight() > iconSize * 2)) { 925 params.appIcon = Bitmap.createScaledBitmap(params.appIcon, iconSize, iconSize, 926 true); 927 } 928 } 929 930 switch (params.mode) { 931 case SessionParams.MODE_FULL_INSTALL: 932 case SessionParams.MODE_INHERIT_EXISTING: 933 break; 934 default: 935 throw new IllegalArgumentException("Invalid install mode: " + params.mode); 936 } 937 938 // If caller requested explicit location, validity check it, otherwise 939 // resolve the best internal or adopted location. 940 if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) { 941 if (!InstallLocationUtils.fitsOnInternal(mContext, params)) { 942 throw new IOException("No suitable internal storage available"); 943 } 944 } else if ((params.installFlags & PackageManager.INSTALL_FORCE_VOLUME_UUID) != 0) { 945 // For now, installs to adopted media are treated as internal from 946 // an install flag point-of-view. 947 params.installFlags |= PackageManager.INSTALL_INTERNAL; 948 } else { 949 params.installFlags |= PackageManager.INSTALL_INTERNAL; 950 951 // Resolve best location for install, based on combination of 952 // requested install flags, delta size, and manifest settings. 953 final long ident = Binder.clearCallingIdentity(); 954 try { 955 params.volumeUuid = InstallLocationUtils.resolveInstallVolume(mContext, params); 956 } finally { 957 Binder.restoreCallingIdentity(ident); 958 } 959 } 960 } 961 962 int requestedInstallerPackageUid = INVALID_UID; 963 if (requestedInstallerPackageName != null) { 964 requestedInstallerPackageUid = snapshot.getPackageUid(requestedInstallerPackageName, 965 0 /* flags */, userId); 966 } 967 if (requestedInstallerPackageUid == INVALID_UID) { 968 // Requested installer package is invalid, reset it 969 requestedInstallerPackageName = null; 970 } 971 972 final int sessionId; 973 final PackageInstallerSession session; 974 synchronized (mSessions) { 975 // Check that the installer does not have too many active sessions. 976 final int activeCount = getSessionCount(mSessions, callingUid); 977 if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES) 978 == PackageManager.PERMISSION_GRANTED) { 979 if (activeCount >= MAX_ACTIVE_SESSIONS_WITH_PERMISSION) { 980 throw new IllegalStateException( 981 "Too many active sessions for UID " + callingUid); 982 } 983 } else if (activeCount >= MAX_ACTIVE_SESSIONS_NO_PERMISSION) { 984 throw new IllegalStateException( 985 "Too many active sessions for UID " + callingUid); 986 } 987 final int historicalCount = mHistoricalSessionsByInstaller.get(callingUid); 988 if (historicalCount >= MAX_HISTORICAL_SESSIONS) { 989 throw new IllegalStateException( 990 "Too many historical sessions for UID " + callingUid); 991 } 992 final int existingDraftSessionId = 993 getExistingDraftSessionId(requestedInstallerPackageUid, params, userId); 994 995 sessionId = existingDraftSessionId != SessionInfo.INVALID_ID ? existingDraftSessionId 996 : allocateSessionIdLocked(); 997 } 998 999 final long createdMillis = System.currentTimeMillis(); 1000 // We're staging to exactly one location 1001 File stageDir = null; 1002 String stageCid = null; 1003 if (!params.isMultiPackage) { 1004 if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) { 1005 stageDir = buildSessionDir(sessionId, params); 1006 } else { 1007 stageCid = buildExternalStageCid(sessionId); 1008 } 1009 } 1010 1011 // reset the force queryable param if it's not called by an approved caller. 1012 if (params.forceQueryableOverride) { 1013 if (!PackageManagerServiceUtils.isRootOrShell(callingUid)) { 1014 params.forceQueryableOverride = false; 1015 } 1016 } 1017 1018 final var dpmi = LocalServices.getService(DevicePolicyManagerInternal.class); 1019 if (dpmi != null && dpmi.isUserOrganizationManaged(userId)) { 1020 params.installFlags |= PackageManager.INSTALL_FROM_MANAGED_USER_OR_PROFILE; 1021 } 1022 1023 if (isApex || mContext.checkCallingOrSelfPermission( 1024 Manifest.permission.ENFORCE_UPDATE_OWNERSHIP) == PackageManager.PERMISSION_DENIED) { 1025 params.installFlags &= ~PackageManager.INSTALL_REQUEST_UPDATE_OWNERSHIP; 1026 } 1027 1028 InstallSource installSource = InstallSource.create(installerPackageName, 1029 originatingPackageName, requestedInstallerPackageName, requestedInstallerPackageUid, 1030 requestedInstallerPackageName, installerAttributionTag, params.packageSource); 1031 session = new PackageInstallerSession(mInternalCallback, mContext, mPm, this, 1032 mSilentUpdatePolicy, mInstallThread.getLooper(), mStagingManager, sessionId, 1033 userId, callingUid, installSource, params, createdMillis, 0L, stageDir, stageCid, 1034 null, null, false, false, false, false, null, SessionInfo.INVALID_ID, 1035 false, false, false, PackageManager.INSTALL_UNKNOWN, "", null); 1036 1037 synchronized (mSessions) { 1038 mSessions.put(sessionId, session); 1039 } 1040 mPm.addInstallerPackageName(session.getInstallSource()); 1041 1042 mCallbacks.notifySessionCreated(session.sessionId, session.userId); 1043 1044 mSettingsWriteRequest.schedule(); 1045 if (LOGD) { 1046 Slog.d(TAG, "Created session id=" + sessionId + " staged=" + params.isStaged); 1047 } 1048 return sessionId; 1049 } 1050 1051 int getExistingDraftSessionId(int installerUid, 1052 @NonNull SessionParams sessionParams, int userId) { 1053 synchronized (mSessions) { 1054 return getExistingDraftSessionIdInternal(installerUid, sessionParams, userId); 1055 } 1056 } 1057 1058 @GuardedBy("mSessions") 1059 private int getExistingDraftSessionIdInternal(int installerUid, 1060 SessionParams sessionParams, int userId) { 1061 String appPackageName = sessionParams.appPackageName; 1062 if (!isArchivingEnabled() || installerUid == INVALID_UID || appPackageName == null) { 1063 return SessionInfo.INVALID_ID; 1064 } 1065 1066 PackageStateInternal ps = mPm.snapshotComputer().getPackageStateInternal(appPackageName, 1067 SYSTEM_UID); 1068 if (ps == null || !PackageArchiver.isArchived(ps.getUserStateOrDefault(userId))) { 1069 return SessionInfo.INVALID_ID; 1070 } 1071 1072 // If unarchiveId is present we match based on it. If unarchiveId is missing we 1073 // choose a draft session too to ensure we don't end up with duplicate sessions 1074 // if the installer doesn't set this field. 1075 if (sessionParams.unarchiveId > 0) { 1076 PackageInstallerSession session = mSessions.get(sessionParams.unarchiveId); 1077 if (session != null 1078 && isValidDraftSession(session, appPackageName, installerUid, userId)) { 1079 return session.sessionId; 1080 } 1081 1082 return SessionInfo.INVALID_ID; 1083 } 1084 1085 for (int i = 0; i < mSessions.size(); i++) { 1086 PackageInstallerSession session = mSessions.valueAt(i); 1087 if (session != null 1088 && isValidDraftSession(session, appPackageName, installerUid, userId)) { 1089 return session.sessionId; 1090 } 1091 } 1092 1093 return SessionInfo.INVALID_ID; 1094 } 1095 1096 private boolean isValidDraftSession(@NonNull PackageInstallerSession session, 1097 @NonNull String appPackageName, int installerUid, int userId) { 1098 return (session.getInstallFlags() & PackageManager.INSTALL_UNARCHIVE_DRAFT) != 0 1099 && appPackageName.equals(session.params.appPackageName) 1100 && session.userId == userId 1101 && installerUid == session.getInstallerUid(); 1102 } 1103 1104 void cleanupDraftIfUnclaimed(int sessionId) { 1105 synchronized (mSessions) { 1106 PackageInstallerSession session = mPm.mInstallerService.getSession(sessionId); 1107 if (session != null && (session.getInstallFlags() & INSTALL_UNARCHIVE_DRAFT) != 0) { 1108 session.abandon(); 1109 } 1110 } 1111 } 1112 1113 private boolean isStagedInstallerAllowed(String installerName) { 1114 return SystemConfig.getInstance().getWhitelistedStagedInstallers().contains(installerName); 1115 } 1116 1117 @Override 1118 public void updateSessionAppIcon(int sessionId, Bitmap appIcon) { 1119 synchronized (mSessions) { 1120 final PackageInstallerSession session = mSessions.get(sessionId); 1121 if (session == null || !isCallingUidOwner(session)) { 1122 throw new SecurityException("Caller has no access to session " + sessionId); 1123 } 1124 1125 // Defensively resize giant app icons 1126 if (appIcon != null) { 1127 final ActivityManager am = (ActivityManager) mContext.getSystemService( 1128 Context.ACTIVITY_SERVICE); 1129 final int iconSize = am.getLauncherLargeIconSize(); 1130 if ((appIcon.getWidth() > iconSize * 2) 1131 || (appIcon.getHeight() > iconSize * 2)) { 1132 appIcon = Bitmap.createScaledBitmap(appIcon, iconSize, iconSize, true); 1133 } 1134 } 1135 1136 session.params.appIcon = appIcon; 1137 session.params.appIconLastModified = -1; 1138 1139 mInternalCallback.onSessionBadgingChanged(session); 1140 } 1141 } 1142 1143 @Override 1144 public void updateSessionAppLabel(int sessionId, String appLabel) { 1145 synchronized (mSessions) { 1146 final PackageInstallerSession session = mSessions.get(sessionId); 1147 if (session == null || !isCallingUidOwner(session)) { 1148 throw new SecurityException("Caller has no access to session " + sessionId); 1149 } 1150 if (!appLabel.equals(session.params.appLabel)) { 1151 session.params.appLabel = appLabel; 1152 mInternalCallback.onSessionBadgingChanged(session); 1153 } 1154 } 1155 } 1156 1157 @Override 1158 public void abandonSession(int sessionId) { 1159 synchronized (mSessions) { 1160 final PackageInstallerSession session = mSessions.get(sessionId); 1161 if (session == null || !isCallingUidOwner(session)) { 1162 throw new SecurityException("Caller has no access to session " + sessionId); 1163 } 1164 session.abandon(); 1165 } 1166 } 1167 1168 @Override 1169 public IPackageInstallerSession openSession(int sessionId) { 1170 try { 1171 return openSessionInternal(sessionId); 1172 } catch (IOException e) { 1173 throw ExceptionUtils.wrap(e); 1174 } 1175 } 1176 1177 private boolean checkOpenSessionAccess(final PackageInstallerSession session) { 1178 if (session == null 1179 || (session.getInstallFlags() & PackageManager.INSTALL_UNARCHIVE_DRAFT) != 0) { 1180 return false; 1181 } 1182 if (isCallingUidOwner(session)) { 1183 return true; 1184 } 1185 // Package verifiers have access to openSession for sealed sessions. 1186 if (session.isSealed() && mContext.checkCallingOrSelfPermission( 1187 android.Manifest.permission.PACKAGE_VERIFICATION_AGENT) 1188 == PackageManager.PERMISSION_GRANTED) { 1189 return true; 1190 } 1191 return false; 1192 } 1193 1194 private PackageInstallerSession openSessionInternal(int sessionId) throws IOException { 1195 synchronized (mSessions) { 1196 final PackageInstallerSession session = mSessions.get(sessionId); 1197 if (!checkOpenSessionAccess(session)) { 1198 throw new SecurityException("Caller has no access to session " + sessionId); 1199 } 1200 session.open(); 1201 return session; 1202 } 1203 } 1204 1205 @GuardedBy("mSessions") 1206 private int allocateSessionIdLocked() { 1207 int n = 0; 1208 int sessionId; 1209 do { 1210 sessionId = mRandom.nextInt(Integer.MAX_VALUE - 1) + 1; 1211 if (!mAllocatedSessions.get(sessionId, false)) { 1212 mAllocatedSessions.put(sessionId, true); 1213 return sessionId; 1214 } 1215 } while (n++ < 32); 1216 1217 throw new IllegalStateException("Failed to allocate session ID"); 1218 } 1219 1220 static boolean isStageName(String name) { 1221 final boolean isFile = name.startsWith("vmdl") && name.endsWith(".tmp"); 1222 final boolean isContainer = name.startsWith("smdl") && name.endsWith(".tmp"); 1223 final boolean isLegacyContainer = name.startsWith("smdl2tmp"); 1224 return isFile || isContainer || isLegacyContainer; 1225 } 1226 1227 static int tryParseSessionId(@NonNull String tmpSessionDir) 1228 throws IllegalArgumentException { 1229 if (!tmpSessionDir.startsWith("vmdl") || !tmpSessionDir.endsWith(".tmp")) { 1230 throw new IllegalArgumentException("Not a temporary session directory"); 1231 } 1232 String sessionId = tmpSessionDir.substring("vmdl".length(), 1233 tmpSessionDir.length() - ".tmp".length()); 1234 return Integer.parseInt(sessionId); 1235 } 1236 1237 private static boolean isValidPackageName(@NonNull String packageName) { 1238 if (packageName.length() > SessionParams.MAX_PACKAGE_NAME_LENGTH) { 1239 return false; 1240 } 1241 // "android" is a valid package name 1242 var errorMessage = FrameworkParsingPackageUtils.validateName( 1243 packageName, /* requireSeparator= */ false, /* requireFilename */ true); 1244 if (errorMessage != null) { 1245 return false; 1246 } 1247 return true; 1248 } 1249 1250 private File getTmpSessionDir(String volumeUuid) { 1251 return Environment.getDataAppDirectory(volumeUuid); 1252 } 1253 1254 private File buildTmpSessionDir(int sessionId, String volumeUuid) { 1255 final File sessionStagingDir = getTmpSessionDir(volumeUuid); 1256 return new File(sessionStagingDir, "vmdl" + sessionId + ".tmp"); 1257 } 1258 1259 private File buildSessionDir(int sessionId, SessionParams params) { 1260 if (params.isStaged || (params.installFlags & PackageManager.INSTALL_APEX) != 0) { 1261 final File sessionStagingDir = Environment.getDataStagingDirectory(params.volumeUuid); 1262 return new File(sessionStagingDir, "session_" + sessionId); 1263 } 1264 final File result = buildTmpSessionDir(sessionId, params.volumeUuid); 1265 if (DEBUG && !Objects.equals(tryParseSessionId(result.getName()), sessionId)) { 1266 throw new RuntimeException( 1267 "session folder format is off: " + result.getName() + " (" + sessionId + ")"); 1268 } 1269 return result; 1270 } 1271 1272 static void prepareStageDir(File stageDir) throws IOException { 1273 if (stageDir.exists()) { 1274 throw new IOException("Session dir already exists: " + stageDir); 1275 } 1276 1277 try { 1278 Os.mkdir(stageDir.getAbsolutePath(), 0775); 1279 Os.chmod(stageDir.getAbsolutePath(), 0775); 1280 } catch (ErrnoException e) { 1281 // This purposefully throws if directory already exists 1282 throw new IOException("Failed to prepare session dir: " + stageDir, e); 1283 } 1284 1285 if (!SELinux.restorecon(stageDir)) { 1286 String path = stageDir.getCanonicalPath(); 1287 String ctx = SELinux.fileSelabelLookup(path); 1288 boolean success = SELinux.setFileContext(path, ctx); 1289 Slog.e(TAG, 1290 "Failed to SELinux.restorecon session dir, path: [" + path + "], ctx: [" + ctx 1291 + "]. Retrying via SELinux.fileSelabelLookup/SELinux.setFileContext: " 1292 + (success ? "SUCCESS" : "FAILURE")); 1293 if (!success) { 1294 throw new IOException("Failed to restorecon session dir: " + stageDir); 1295 } 1296 } 1297 } 1298 1299 private String buildExternalStageCid(int sessionId) { 1300 return "smdl" + sessionId + ".tmp"; 1301 } 1302 1303 private boolean shouldFilterSession(@NonNull Computer snapshot, int uid, SessionInfo info) { 1304 if (info == null) { 1305 return false; 1306 } 1307 return uid != info.getInstallerUid() 1308 && !snapshot.canQueryPackage(uid, info.getAppPackageName()); 1309 } 1310 1311 @Override 1312 public SessionInfo getSessionInfo(int sessionId) { 1313 final int callingUid = Binder.getCallingUid(); 1314 final SessionInfo result; 1315 synchronized (mSessions) { 1316 final PackageInstallerSession session = mSessions.get(sessionId); 1317 result = (session != null && !(session.isStaged() && session.isDestroyed())) 1318 ? session.generateInfoForCaller(true /* includeIcon */, callingUid) 1319 : null; 1320 } 1321 return shouldFilterSession(mPm.snapshotComputer(), callingUid, result) ? null : result; 1322 } 1323 1324 @Override 1325 public ParceledListSlice<SessionInfo> getStagedSessions() { 1326 final int callingUid = Binder.getCallingUid(); 1327 final List<SessionInfo> result = new ArrayList<>(); 1328 synchronized (mSessions) { 1329 for (int i = 0; i < mSessions.size(); i++) { 1330 final PackageInstallerSession session = mSessions.valueAt(i); 1331 if (session.isStaged() && !session.isDestroyed()) { 1332 result.add(session.generateInfoForCaller(false /* includeIcon */, callingUid)); 1333 } 1334 } 1335 } 1336 final Computer snapshot = mPm.snapshotComputer(); 1337 result.removeIf(info -> shouldFilterSession(snapshot, callingUid, info)); 1338 return new ParceledListSlice<>(result); 1339 } 1340 1341 @Override 1342 public ParceledListSlice<SessionInfo> getAllSessions(int userId) { 1343 final int callingUid = Binder.getCallingUid(); 1344 final Computer snapshot = mPm.snapshotComputer(); 1345 snapshot.enforceCrossUserPermission(callingUid, userId, true, false, "getAllSessions"); 1346 1347 final List<SessionInfo> result = new ArrayList<>(); 1348 synchronized (mSessions) { 1349 for (int i = 0; i < mSessions.size(); i++) { 1350 final PackageInstallerSession session = mSessions.valueAt(i); 1351 if (session.userId == userId && !session.hasParentSessionId() 1352 && !(session.isStaged() && session.isDestroyed())) { 1353 result.add(session.generateInfoForCaller(false /* includeIcon */, callingUid)); 1354 } 1355 } 1356 } 1357 result.removeIf(info -> shouldFilterSession(snapshot, callingUid, info)); 1358 return new ParceledListSlice<>(result); 1359 } 1360 1361 @Override 1362 public ParceledListSlice<SessionInfo> getMySessions(String installerPackageName, int userId) { 1363 final Computer snapshot = mPm.snapshotComputer(); 1364 final int callingUid = Binder.getCallingUid(); 1365 snapshot.enforceCrossUserPermission(callingUid, userId, true, false, "getMySessions"); 1366 mAppOps.checkPackage(callingUid, installerPackageName); 1367 1368 final List<SessionInfo> result = new ArrayList<>(); 1369 synchronized (mSessions) { 1370 for (int i = 0; i < mSessions.size(); i++) { 1371 final PackageInstallerSession session = mSessions.valueAt(i); 1372 1373 SessionInfo info = 1374 session.generateInfoForCaller(false /*withIcon*/, SYSTEM_UID); 1375 if (Objects.equals(info.getInstallerPackageName(), installerPackageName) 1376 && session.userId == userId && !session.hasParentSessionId() 1377 && isCallingUidOwner(session) 1378 && (session.getInstallFlags() & PackageManager.INSTALL_UNARCHIVE_DRAFT) 1379 == 0) { 1380 result.add(info); 1381 } 1382 } 1383 } 1384 return new ParceledListSlice<>(result); 1385 } 1386 1387 ParceledListSlice<SessionInfo> getHistoricalSessions(int userId) { 1388 final int callingUid = Binder.getCallingUid(); 1389 final Computer snapshot = mPm.snapshotComputer(); 1390 snapshot.enforceCrossUserPermission(callingUid, userId, true, false, "getAllSessions"); 1391 1392 final List<SessionInfo> result = new ArrayList<>(); 1393 synchronized (mSessions) { 1394 for (int i = 0; i < mHistoricalSessions.size(); i++) { 1395 final PackageInstallerHistoricalSession session = mHistoricalSessions.get(i); 1396 if (userId == UserHandle.USER_ALL || session.userId == userId) { 1397 result.add(session.generateInfo()); 1398 } 1399 } 1400 } 1401 result.removeIf(info -> shouldFilterSession(snapshot, callingUid, info)); 1402 return new ParceledListSlice<>(result); 1403 } 1404 1405 @Override 1406 public void uninstall(VersionedPackage versionedPackage, String callerPackageName, int flags, 1407 IntentSender statusReceiver, int userId) { 1408 uninstall( 1409 versionedPackage, 1410 callerPackageName, 1411 flags, 1412 statusReceiver, 1413 userId, 1414 Binder.getCallingUid(), 1415 Binder.getCallingPid()); 1416 } 1417 1418 void uninstall(VersionedPackage versionedPackage, String callerPackageName, int flags, 1419 IntentSender statusReceiver, int userId, int callingUid, int callingPid) { 1420 final Computer snapshot = mPm.snapshotComputer(); 1421 snapshot.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall"); 1422 if (!PackageManagerServiceUtils.isRootOrShell(callingUid)) { 1423 mAppOps.checkPackage(callingUid, callerPackageName); 1424 } 1425 1426 // Check whether the caller is device owner or affiliated profile owner, in which case we do 1427 // it silently. 1428 DevicePolicyManagerInternal dpmi = 1429 LocalServices.getService(DevicePolicyManagerInternal.class); 1430 final boolean canSilentlyInstallPackage = 1431 (dpmi != null && dpmi.canSilentlyInstallPackage(callerPackageName, callingUid)) 1432 || PackageInstallerSession.isEmergencyInstallerEnabled( 1433 versionedPackage.getPackageName(), snapshot, userId, callingUid); 1434 1435 final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext, 1436 statusReceiver, versionedPackage.getPackageName(), 1437 canSilentlyInstallPackage, userId, mPackageArchiver, flags); 1438 if (mContext.checkPermission(Manifest.permission.DELETE_PACKAGES, callingPid, callingUid) 1439 == PackageManager.PERMISSION_GRANTED) { 1440 // Sweet, call straight through! 1441 mPm.deletePackageVersioned(versionedPackage, adapter.getBinder(), userId, flags); 1442 } else if (canSilentlyInstallPackage) { 1443 // Allow the device owner and affiliated profile owner to silently delete packages 1444 // Need to clear the calling identity to get DELETE_PACKAGES permission 1445 final long ident = Binder.clearCallingIdentity(); 1446 try { 1447 mPm.deletePackageVersioned(versionedPackage, adapter.getBinder(), userId, flags); 1448 } finally { 1449 Binder.restoreCallingIdentity(ident); 1450 } 1451 DevicePolicyEventLogger 1452 .createEvent(DevicePolicyEnums.UNINSTALL_PACKAGE) 1453 .setAdmin(callerPackageName) 1454 .write(); 1455 } else { 1456 ApplicationInfo appInfo = snapshot.getApplicationInfo(callerPackageName, 0, userId); 1457 if (appInfo.targetSdkVersion >= Build.VERSION_CODES.P) { 1458 mContext.enforcePermission(Manifest.permission.REQUEST_DELETE_PACKAGES, callingPid, 1459 callingUid, null); 1460 } 1461 1462 // Take a short detour to confirm with user 1463 final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE); 1464 intent.setData(Uri.fromParts("package", versionedPackage.getPackageName(), null)); 1465 intent.putExtra(PackageInstaller.EXTRA_CALLBACK, 1466 new PackageManager.UninstallCompleteCallback(adapter.getBinder().asBinder())); 1467 if ((flags & PackageManager.DELETE_ARCHIVE) != 0) { 1468 // Delete flags are passed to the uninstaller activity so it can be preserved 1469 // in the follow-up uninstall operation after the user confirmation 1470 intent.putExtra(PackageInstaller.EXTRA_DELETE_FLAGS, flags); 1471 } 1472 adapter.onUserActionRequired(intent); 1473 } 1474 } 1475 1476 @Override 1477 public void uninstallExistingPackage(VersionedPackage versionedPackage, 1478 String callerPackageName, IntentSender statusReceiver, int userId) { 1479 final int callingUid = Binder.getCallingUid(); 1480 mContext.enforceCallingOrSelfPermission(Manifest.permission.DELETE_PACKAGES, null); 1481 final Computer snapshot = mPm.snapshotComputer(); 1482 snapshot.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall"); 1483 if (!PackageManagerServiceUtils.isRootOrShell(callingUid)) { 1484 mAppOps.checkPackage(callingUid, callerPackageName); 1485 } 1486 1487 final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext, 1488 statusReceiver, versionedPackage.getPackageName(), false, userId); 1489 mPm.deleteExistingPackageAsUser(versionedPackage, adapter.getBinder(), userId); 1490 } 1491 1492 @Override 1493 public void installExistingPackage(String packageName, int installFlags, int installReason, 1494 IntentSender statusReceiver, int userId, List<String> allowListedPermissions) { 1495 1496 var result = mPm.installExistingPackageAsUser(packageName, userId, 1497 installFlags, installReason, allowListedPermissions, statusReceiver); 1498 1499 int returnCode = result.first; 1500 IntentSender onCompleteSender = result.second; 1501 if (onCompleteSender != null) { 1502 InstallPackageHelper.onInstallComplete(returnCode, mContext, onCompleteSender); 1503 } 1504 } 1505 1506 @android.annotation.EnforcePermission(android.Manifest.permission.INSTALL_PACKAGES) 1507 @Override 1508 public void setPermissionsResult(int sessionId, boolean accepted) { 1509 setPermissionsResult_enforcePermission(); 1510 1511 synchronized (mSessions) { 1512 PackageInstallerSession session = mSessions.get(sessionId); 1513 if (session != null) { 1514 session.setPermissionsResult(accepted); 1515 } 1516 } 1517 } 1518 1519 private boolean isValidForInstallConstraints(PackageStateInternal ps, 1520 String installerPackageName, int installerUid, String packageName) { 1521 final var snapshot = mPm.snapshotComputer(); 1522 final var isSelfUpdatePermissionGranted = 1523 (snapshot.checkUidPermission(android.Manifest.permission.INSTALL_SELF_UPDATES, 1524 installerUid) == PackageManager.PERMISSION_GRANTED); 1525 final var isSelfUpdateAllowed = isSelfUpdatePermissionGranted && TextUtils.equals( 1526 packageName, installerPackageName); 1527 return TextUtils.equals(ps.getInstallSource().mInstallerPackageName, installerPackageName) 1528 || TextUtils.equals(ps.getInstallSource().mUpdateOwnerPackageName, 1529 installerPackageName) || isSelfUpdateAllowed; 1530 } 1531 1532 private CompletableFuture<InstallConstraintsResult> checkInstallConstraintsInternal( 1533 String installerPackageName, List<String> packageNames, 1534 InstallConstraints constraints, long timeoutMillis) { 1535 Objects.requireNonNull(packageNames); 1536 Objects.requireNonNull(constraints); 1537 1538 final var snapshot = mPm.snapshotComputer(); 1539 final int callingUid = Binder.getCallingUid(); 1540 final var callingPackageName = snapshot.getNameForUid(callingUid); 1541 if (!TextUtils.equals(callingPackageName, installerPackageName)) { 1542 throw new SecurityException("The installerPackageName set by the caller doesn't match " 1543 + "the caller's own package name."); 1544 } 1545 if (!PackageManagerServiceUtils.isSystemOrRootOrShell(callingUid)) { 1546 for (var packageName : packageNames) { 1547 var ps = snapshot.getPackageStateInternal(packageName); 1548 if (ps == null || !isValidForInstallConstraints(ps, installerPackageName, 1549 callingUid, packageName)) { 1550 throw new SecurityException("Caller has no access to package " + packageName); 1551 } 1552 } 1553 } 1554 1555 return mGentleUpdateHelper.checkInstallConstraints( 1556 packageNames, constraints, timeoutMillis); 1557 } 1558 1559 @Override 1560 public void checkInstallConstraints(String installerPackageName, List<String> packageNames, 1561 InstallConstraints constraints, RemoteCallback callback) { 1562 Objects.requireNonNull(callback); 1563 var future = checkInstallConstraintsInternal( 1564 installerPackageName, packageNames, constraints, /*timeoutMillis=*/0); 1565 future.thenAccept(result -> { 1566 var b = new Bundle(); 1567 b.putParcelable("result", result); 1568 callback.sendResult(b); 1569 }); 1570 } 1571 1572 @Override 1573 public void waitForInstallConstraints(String installerPackageName, List<String> packageNames, 1574 InstallConstraints constraints, IntentSender callback, long timeoutMillis) { 1575 Objects.requireNonNull(callback); 1576 if (timeoutMillis < 0 || timeoutMillis > MAX_INSTALL_CONSTRAINTS_TIMEOUT_MILLIS) { 1577 throw new IllegalArgumentException("Invalid timeoutMillis=" + timeoutMillis); 1578 } 1579 var future = checkInstallConstraintsInternal( 1580 installerPackageName, packageNames, constraints, timeoutMillis); 1581 future.thenAccept(result -> { 1582 final var intent = new Intent(); 1583 intent.putExtra(Intent.EXTRA_PACKAGES, packageNames.toArray(new String[0])); 1584 intent.putExtra(PackageInstaller.EXTRA_INSTALL_CONSTRAINTS, constraints); 1585 intent.putExtra(PackageInstaller.EXTRA_INSTALL_CONSTRAINTS_RESULT, result); 1586 try { 1587 final BroadcastOptions options = BroadcastOptions.makeBasic(); 1588 options.setPendingIntentBackgroundActivityLaunchAllowed(false); 1589 callback.sendIntent(mContext, 0, intent, null /* onFinished*/, 1590 null /* handler */, null /* requiredPermission */, options.toBundle()); 1591 } catch (SendIntentException ignore) { 1592 } 1593 }); 1594 } 1595 1596 @Override 1597 public void registerCallback(IPackageInstallerCallback callback, int userId) { 1598 final Computer snapshot = mPm.snapshotComputer(); 1599 snapshot.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, 1600 "registerCallback"); 1601 registerCallback(callback, eventUserId -> userId == eventUserId); 1602 } 1603 1604 /** 1605 * Assume permissions already checked and caller's identity cleared 1606 */ 1607 public void registerCallback(IPackageInstallerCallback callback, IntPredicate userCheck) { 1608 mCallbacks.register(callback, new BroadcastCookie(Binder.getCallingUid(), userCheck)); 1609 } 1610 1611 @Override 1612 public void unregisterCallback(IPackageInstallerCallback callback) { 1613 mCallbacks.unregister(callback); 1614 } 1615 1616 @Override 1617 public PackageInstallerSession getSession(int sessionId) { 1618 synchronized (mSessions) { 1619 return mSessions.get(sessionId); 1620 } 1621 } 1622 1623 @Override 1624 public PackageSessionVerifier getSessionVerifier() { 1625 return mSessionVerifier; 1626 } 1627 1628 @Override 1629 public GentleUpdateHelper getGentleUpdateHelper() { 1630 return mGentleUpdateHelper; 1631 } 1632 1633 @Override 1634 public void bypassNextStagedInstallerCheck(boolean value) { 1635 if (!PackageManagerServiceUtils.isSystemOrRootOrShell(Binder.getCallingUid())) { 1636 throw new SecurityException("Caller not allowed to bypass staged installer check"); 1637 } 1638 mBypassNextStagedInstallerCheck = value; 1639 } 1640 1641 @Override 1642 public void bypassNextAllowedApexUpdateCheck(boolean value) { 1643 if (!PackageManagerServiceUtils.isSystemOrRootOrShell(Binder.getCallingUid())) { 1644 throw new SecurityException("Caller not allowed to bypass allowed apex update check"); 1645 } 1646 mBypassNextAllowedApexUpdateCheck = value; 1647 } 1648 1649 @Override 1650 public void disableVerificationForUid(int uid) { 1651 if (!PackageManagerServiceUtils.isSystemOrRootOrShell(Binder.getCallingUid())) { 1652 throw new SecurityException("Operation not allowed for caller"); 1653 } 1654 mDisableVerificationForUid = uid; 1655 } 1656 1657 /** 1658 * Set an installer to allow for the unlimited silent updates. 1659 */ 1660 @Override 1661 public void setAllowUnlimitedSilentUpdates(@Nullable String installerPackageName) { 1662 if (!PackageManagerServiceUtils.isSystemOrRootOrShell(Binder.getCallingUid())) { 1663 throw new SecurityException("Caller not allowed to unlimite silent updates"); 1664 } 1665 mSilentUpdatePolicy.setAllowUnlimitedSilentUpdates(installerPackageName); 1666 } 1667 1668 /** 1669 * Set the silent updates throttle time in seconds. 1670 */ 1671 @Override 1672 public void setSilentUpdatesThrottleTime(long throttleTimeInSeconds) { 1673 if (!PackageManagerServiceUtils.isSystemOrRootOrShell(Binder.getCallingUid())) { 1674 throw new SecurityException("Caller not allowed to set silent updates throttle time"); 1675 } 1676 mSilentUpdatePolicy.setSilentUpdatesThrottleTime(throttleTimeInSeconds); 1677 } 1678 1679 @Override 1680 public void requestArchive( 1681 @NonNull String packageName, 1682 @NonNull String callerPackageName, 1683 int flags, 1684 @NonNull IntentSender intentSender, 1685 @NonNull UserHandle userHandle) { 1686 mPackageArchiver.requestArchive(packageName, callerPackageName, flags, intentSender, 1687 userHandle); 1688 } 1689 1690 @Override 1691 public void requestUnarchive( 1692 @NonNull String packageName, 1693 @NonNull String callerPackageName, 1694 @NonNull IntentSender statusReceiver, 1695 @NonNull UserHandle userHandle) { 1696 mPackageArchiver.requestUnarchive(packageName, callerPackageName, statusReceiver, 1697 userHandle); 1698 } 1699 1700 @Override 1701 public void installPackageArchived( 1702 @NonNull ArchivedPackageParcel archivedPackageParcel, 1703 @NonNull SessionParams params, 1704 @NonNull IntentSender statusReceiver, 1705 @NonNull String installerPackageName, 1706 @NonNull UserHandle userHandle) { 1707 Objects.requireNonNull(params); 1708 Objects.requireNonNull(archivedPackageParcel); 1709 Objects.requireNonNull(statusReceiver); 1710 Objects.requireNonNull(installerPackageName); 1711 Objects.requireNonNull(userHandle); 1712 1713 Slog.i(TAG, 1714 TextUtils.formatSimple("Requested archived install of package %s for user %s.", 1715 archivedPackageParcel.packageName, 1716 userHandle.getIdentifier())); 1717 final int callingUid = Binder.getCallingUid(); 1718 final int userId = userHandle.getIdentifier(); 1719 final Computer snapshot = mPm.snapshotComputer(); 1720 snapshot.enforceCrossUserPermission(callingUid, userId, true, true, 1721 "installPackageArchived"); 1722 1723 if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES) 1724 != PackageManager.PERMISSION_GRANTED) { 1725 throw new SecurityException("You need the " 1726 + "com.android.permission.INSTALL_PACKAGES permission " 1727 + "to request archived package install"); 1728 } 1729 1730 params.installFlags |= PackageManager.INSTALL_ARCHIVED; 1731 if (params.dataLoaderParams != null) { 1732 throw new IllegalArgumentException( 1733 "Incompatible session param: dataLoaderParams has to be null"); 1734 } 1735 1736 params.setDataLoaderParams( 1737 PackageManagerShellCommandDataLoader.getStreamingDataLoaderParams(null)); 1738 var metadata = PackageManagerShellCommandDataLoader.Metadata.forArchived( 1739 archivedPackageParcel); 1740 1741 // Create and commit install archived session. 1742 // Session belongs to the system_server and would not appear anywhere in the Public APIs. 1743 Binder.withCleanCallingIdentity(() -> { 1744 PackageInstallerSession session = null; 1745 try { 1746 var sessionId = createSessionInternal(params, installerPackageName, null 1747 /*installerAttributionTag*/, Binder.getCallingUid(), userId); 1748 session = openSessionInternal(sessionId); 1749 session.addFile(LOCATION_DATA_APP, "base", 0 /*lengthBytes*/, 1750 metadata.toByteArray(), null /*signature*/); 1751 session.commit(statusReceiver, false /*forTransfer*/); 1752 Slog.i(TAG, TextUtils.formatSimple("Installed archived app %s.", 1753 archivedPackageParcel.packageName)); 1754 } catch (IOException e) { 1755 throw ExceptionUtils.wrap(e); 1756 } finally { 1757 if (session != null) { 1758 session.close(); 1759 } 1760 } 1761 }); 1762 } 1763 1764 @Override 1765 public void reportUnarchivalStatus( 1766 int unarchiveId, 1767 @UnarchivalStatus int status, 1768 long requiredStorageBytes, 1769 @Nullable PendingIntent userActionIntent, 1770 @NonNull UserHandle userHandle) { 1771 verifyReportUnarchiveStatusInput( 1772 status, requiredStorageBytes, userActionIntent, userHandle); 1773 1774 int userId = userHandle.getIdentifier(); 1775 int binderUid = Binder.getCallingUid(); 1776 1777 synchronized (mSessions) { 1778 PackageInstallerSession session = mSessions.get(unarchiveId); 1779 if (session == null || session.userId != userId 1780 || session.params.appPackageName == null) { 1781 throw new ParcelableException(new PackageManager.NameNotFoundException( 1782 TextUtils.formatSimple( 1783 "No valid session with unarchival ID %s found for user %s.", 1784 unarchiveId, userId))); 1785 } 1786 1787 if (!isCallingUidOwner(session)) { 1788 throw new SecurityException(TextUtils.formatSimple( 1789 "The caller UID %s does not have access to the session with unarchiveId " 1790 + "%d.", 1791 binderUid, unarchiveId)); 1792 } 1793 1794 session.reportUnarchivalStatus(status, unarchiveId, requiredStorageBytes, 1795 userActionIntent); 1796 } 1797 } 1798 1799 private static void verifyReportUnarchiveStatusInput(int status, long requiredStorageBytes, 1800 @Nullable PendingIntent userActionIntent, 1801 @NonNull UserHandle userHandle) { 1802 Objects.requireNonNull(userHandle); 1803 if (status == UNARCHIVAL_ERROR_USER_ACTION_NEEDED) { 1804 Objects.requireNonNull(userActionIntent); 1805 } 1806 if (status == UNARCHIVAL_ERROR_INSUFFICIENT_STORAGE && requiredStorageBytes <= 0) { 1807 throw new IllegalStateException( 1808 "Insufficient storage error set, but requiredStorageBytes unspecified."); 1809 } 1810 if (status != UNARCHIVAL_ERROR_INSUFFICIENT_STORAGE && requiredStorageBytes > 0) { 1811 throw new IllegalStateException( 1812 TextUtils.formatSimple("requiredStorageBytes set, but error is %s.", status) 1813 ); 1814 } 1815 if (!List.of( 1816 UNARCHIVAL_OK, 1817 UNARCHIVAL_ERROR_USER_ACTION_NEEDED, 1818 UNARCHIVAL_ERROR_INSUFFICIENT_STORAGE, 1819 UNARCHIVAL_ERROR_NO_CONNECTIVITY, 1820 UNARCHIVAL_ERROR_INSTALLER_DISABLED, 1821 UNARCHIVAL_ERROR_INSTALLER_UNINSTALLED, 1822 UNARCHIVAL_GENERIC_ERROR).contains(status)) { 1823 throw new IllegalStateException("Invalid status code passed " + status); 1824 } 1825 } 1826 1827 private static int getSessionCount(SparseArray<PackageInstallerSession> sessions, 1828 int installerUid) { 1829 int count = 0; 1830 final int size = sessions.size(); 1831 for (int i = 0; i < size; i++) { 1832 final PackageInstallerSession session = sessions.valueAt(i); 1833 if (session.getInstallerUid() == installerUid) { 1834 count++; 1835 } 1836 } 1837 return count; 1838 } 1839 1840 private boolean isCallingUidOwner(PackageInstallerSession session) { 1841 final int callingUid = Binder.getCallingUid(); 1842 if (callingUid == Process.ROOT_UID) { 1843 return true; 1844 } else { 1845 return (session != null) && (callingUid == session.getInstallerUid()); 1846 } 1847 } 1848 1849 private boolean shouldFilterSession(@NonNull Computer snapshot, int uid, int sessionId) { 1850 final PackageInstallerSession session = getSession(sessionId); 1851 if (session == null) { 1852 return false; 1853 } 1854 return uid != session.getInstallerUid() 1855 && !snapshot.canQueryPackage(uid, session.getPackageName()); 1856 } 1857 1858 static class PackageDeleteObserverAdapter extends PackageDeleteObserver { 1859 private final Context mContext; 1860 private final IntentSender mTarget; 1861 private final String mPackageName; 1862 private final Notification mNotification; 1863 private final int mUserId; 1864 1865 @DeleteFlags 1866 private final int mFlags; 1867 1868 @Nullable 1869 private final PackageArchiver mPackageArchiver; 1870 1871 PackageDeleteObserverAdapter(Context context, IntentSender target, 1872 String packageName, boolean showNotification, int userId) { 1873 this(context, target, packageName, showNotification, userId, 1874 /* packageArchiver= */ null, /* flags= */ 0); 1875 } 1876 1877 PackageDeleteObserverAdapter(Context context, IntentSender target, 1878 String packageName, boolean showNotification, int userId, 1879 PackageArchiver packageArchiver, @DeleteFlags int flags) { 1880 mContext = context; 1881 mTarget = target; 1882 mPackageName = packageName; 1883 if (showNotification) { 1884 mNotification = buildSuccessNotification(mContext, 1885 getDeviceOwnerDeletedPackageMsg(), 1886 packageName, 1887 userId); 1888 } else { 1889 mNotification = null; 1890 } 1891 mUserId = userId; 1892 mPackageArchiver = packageArchiver; 1893 mFlags = flags; 1894 } 1895 1896 private String getDeviceOwnerDeletedPackageMsg() { 1897 final long ident = Binder.clearCallingIdentity(); 1898 try { 1899 DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class); 1900 return dpm.getResources().getString(PACKAGE_DELETED_BY_DO, 1901 () -> mContext.getString(R.string.package_deleted_device_owner)); 1902 } finally { 1903 Binder.restoreCallingIdentity(ident); 1904 } 1905 } 1906 1907 @Override 1908 public void onUserActionRequired(Intent intent) { 1909 if (mTarget == null) { 1910 return; 1911 } 1912 final Intent fillIn = new Intent(); 1913 fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName); 1914 fillIn.putExtra(PackageInstaller.EXTRA_STATUS, 1915 PackageInstaller.STATUS_PENDING_USER_ACTION); 1916 fillIn.putExtra(Intent.EXTRA_INTENT, intent); 1917 try { 1918 final BroadcastOptions options = BroadcastOptions.makeBasic(); 1919 options.setPendingIntentBackgroundActivityLaunchAllowed(false); 1920 mTarget.sendIntent(mContext, 0, fillIn, null /* onFinished*/, 1921 null /* handler */, null /* requiredPermission */, options.toBundle()); 1922 } catch (SendIntentException ignored) { 1923 } 1924 } 1925 1926 @Override 1927 public void onPackageDeleted(String basePackageName, int returnCode, String msg) { 1928 if (PackageManager.DELETE_SUCCEEDED == returnCode && mNotification != null) { 1929 NotificationManager notificationManager = (NotificationManager) 1930 mContext.getSystemService(Context.NOTIFICATION_SERVICE); 1931 notificationManager.notify(basePackageName, 1932 SystemMessage.NOTE_PACKAGE_STATE, 1933 mNotification); 1934 } 1935 if (mPackageArchiver != null 1936 && PackageManager.DELETE_SUCCEEDED != returnCode 1937 && (mFlags & DELETE_ARCHIVE) != 0) { 1938 mPackageArchiver.clearArchiveState(mPackageName, mUserId); 1939 } 1940 if (mTarget == null) { 1941 return; 1942 } 1943 final Intent fillIn = new Intent(); 1944 fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName); 1945 fillIn.putExtra(PackageInstaller.EXTRA_STATUS, 1946 PackageManager.deleteStatusToPublicStatus(returnCode)); 1947 fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, 1948 PackageManager.deleteStatusToString(returnCode, msg)); 1949 fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode); 1950 try { 1951 final BroadcastOptions options = BroadcastOptions.makeBasic(); 1952 options.setPendingIntentBackgroundActivityLaunchAllowed(false); 1953 mTarget.sendIntent(mContext, 0, fillIn, null /* onFinished*/, 1954 null /* handler */, null /* requiredPermission */, options.toBundle()); 1955 } catch (SendIntentException ignored) { 1956 } 1957 } 1958 } 1959 1960 /** 1961 * Build a notification for package installation / deletion by device owners that is shown if 1962 * the operation succeeds. 1963 */ 1964 static Notification buildSuccessNotification(Context context, String contentText, 1965 String basePackageName, int userId) { 1966 PackageInfo packageInfo = null; 1967 try { 1968 packageInfo = AppGlobals.getPackageManager().getPackageInfo( 1969 basePackageName, PackageManager.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES, userId); 1970 } catch (RemoteException ignored) { 1971 } 1972 if (packageInfo == null || packageInfo.applicationInfo == null) { 1973 Slog.w(TAG, "Notification not built for package: " + basePackageName); 1974 return null; 1975 } 1976 PackageManager pm = context.getPackageManager(); 1977 Bitmap packageIcon = ImageUtils.buildScaledBitmap( 1978 packageInfo.applicationInfo.loadIcon(pm), 1979 context.getResources().getDimensionPixelSize( 1980 android.R.dimen.notification_large_icon_width), 1981 context.getResources().getDimensionPixelSize( 1982 android.R.dimen.notification_large_icon_height)); 1983 CharSequence packageLabel = packageInfo.applicationInfo.loadLabel(pm); 1984 return new Notification.Builder(context, SystemNotificationChannels.DEVICE_ADMIN) 1985 .setSmallIcon(R.drawable.ic_check_circle_24px) 1986 .setColor(context.getResources().getColor( 1987 R.color.system_notification_accent_color)) 1988 .setContentTitle(packageLabel) 1989 .setContentText(contentText) 1990 .setStyle(new Notification.BigTextStyle().bigText(contentText)) 1991 .setLargeIcon(packageIcon) 1992 .build(); 1993 } 1994 1995 public static <E> ArraySet<E> newArraySet(E... elements) { 1996 final ArraySet<E> set = new ArraySet<E>(); 1997 if (elements != null) { 1998 set.ensureCapacity(elements.length); 1999 Collections.addAll(set, elements); 2000 } 2001 return set; 2002 } 2003 2004 private static final class BroadcastCookie { 2005 public final int callingUid; 2006 public final IntPredicate userCheck; 2007 2008 BroadcastCookie(int callingUid, IntPredicate userCheck) { 2009 this.callingUid = callingUid; 2010 this.userCheck = userCheck; 2011 } 2012 } 2013 2014 private class Callbacks extends Handler { 2015 private static final int MSG_SESSION_CREATED = 1; 2016 private static final int MSG_SESSION_BADGING_CHANGED = 2; 2017 private static final int MSG_SESSION_ACTIVE_CHANGED = 3; 2018 private static final int MSG_SESSION_PROGRESS_CHANGED = 4; 2019 private static final int MSG_SESSION_FINISHED = 5; 2020 2021 private final RemoteCallbackList<IPackageInstallerCallback> 2022 mCallbacks = new RemoteCallbackList<>(); 2023 2024 public Callbacks(Looper looper) { 2025 super(looper); 2026 } 2027 2028 public void register(IPackageInstallerCallback callback, BroadcastCookie cookie) { 2029 mCallbacks.register(callback, cookie); 2030 } 2031 2032 public void unregister(IPackageInstallerCallback callback) { 2033 mCallbacks.unregister(callback); 2034 } 2035 2036 @Override 2037 public void handleMessage(Message msg) { 2038 final int sessionId = msg.arg1; 2039 final int userId = msg.arg2; 2040 final int n = mCallbacks.beginBroadcast(); 2041 final Computer snapshot = mPm.snapshotComputer(); 2042 for (int i = 0; i < n; i++) { 2043 final IPackageInstallerCallback callback = mCallbacks.getBroadcastItem(i); 2044 final BroadcastCookie cookie = (BroadcastCookie) mCallbacks.getBroadcastCookie(i); 2045 if (cookie.userCheck.test(userId) 2046 && !shouldFilterSession(snapshot, cookie.callingUid, sessionId)) { 2047 try { 2048 invokeCallback(callback, msg); 2049 } catch (RemoteException ignored) { 2050 } 2051 } 2052 } 2053 mCallbacks.finishBroadcast(); 2054 } 2055 2056 private void invokeCallback(IPackageInstallerCallback callback, Message msg) 2057 throws RemoteException { 2058 final int sessionId = msg.arg1; 2059 switch (msg.what) { 2060 case MSG_SESSION_CREATED: 2061 callback.onSessionCreated(sessionId); 2062 break; 2063 case MSG_SESSION_BADGING_CHANGED: 2064 callback.onSessionBadgingChanged(sessionId); 2065 break; 2066 case MSG_SESSION_ACTIVE_CHANGED: 2067 callback.onSessionActiveChanged(sessionId, (boolean) msg.obj); 2068 break; 2069 case MSG_SESSION_PROGRESS_CHANGED: 2070 callback.onSessionProgressChanged(sessionId, (float) msg.obj); 2071 break; 2072 case MSG_SESSION_FINISHED: 2073 callback.onSessionFinished(sessionId, (boolean) msg.obj); 2074 break; 2075 } 2076 } 2077 2078 private void notifySessionCreated(int sessionId, int userId) { 2079 obtainMessage(MSG_SESSION_CREATED, sessionId, userId).sendToTarget(); 2080 } 2081 2082 private void notifySessionBadgingChanged(int sessionId, int userId) { 2083 obtainMessage(MSG_SESSION_BADGING_CHANGED, sessionId, userId).sendToTarget(); 2084 } 2085 2086 private void notifySessionActiveChanged(int sessionId, int userId, boolean active) { 2087 obtainMessage(MSG_SESSION_ACTIVE_CHANGED, sessionId, userId, active).sendToTarget(); 2088 } 2089 2090 private void notifySessionProgressChanged(int sessionId, int userId, float progress) { 2091 obtainMessage(MSG_SESSION_PROGRESS_CHANGED, sessionId, userId, progress).sendToTarget(); 2092 } 2093 2094 public void notifySessionFinished(int sessionId, int userId, boolean success) { 2095 obtainMessage(MSG_SESSION_FINISHED, sessionId, userId, success).sendToTarget(); 2096 } 2097 } 2098 2099 static class ParentChildSessionMap { 2100 private final TreeMap<PackageInstallerSession, TreeSet<PackageInstallerSession>> 2101 mSessionMap; 2102 2103 private final Comparator<PackageInstallerSession> mSessionCreationComparator = 2104 Comparator.comparingLong( 2105 (PackageInstallerSession sess) -> sess != null ? sess.createdMillis : -1) 2106 .thenComparingInt(sess -> sess != null ? sess.sessionId : -1); 2107 2108 ParentChildSessionMap() { 2109 mSessionMap = new TreeMap<>(mSessionCreationComparator); 2110 } 2111 2112 boolean containsSession() { 2113 return !(mSessionMap.isEmpty()); 2114 } 2115 2116 private void addParentSession(PackageInstallerSession session) { 2117 if (!mSessionMap.containsKey(session)) { 2118 mSessionMap.put(session, new TreeSet<>(mSessionCreationComparator)); 2119 } 2120 } 2121 2122 private void addChildSession(PackageInstallerSession session, 2123 PackageInstallerSession parentSession) { 2124 addParentSession(parentSession); 2125 mSessionMap.get(parentSession).add(session); 2126 } 2127 2128 void addSession(PackageInstallerSession session, 2129 PackageInstallerSession parentSession) { 2130 if (session.hasParentSessionId()) { 2131 addChildSession(session, parentSession); 2132 } else { 2133 addParentSession(session); 2134 } 2135 } 2136 2137 void dump(String tag, IndentingPrintWriter pw) { 2138 pw.println(tag + " install sessions:"); 2139 pw.increaseIndent(); 2140 2141 for (Map.Entry<PackageInstallerSession, TreeSet<PackageInstallerSession>> entry 2142 : mSessionMap.entrySet()) { 2143 PackageInstallerSession parentSession = entry.getKey(); 2144 if (parentSession != null) { 2145 pw.print(tag + " "); 2146 parentSession.dump(pw); 2147 pw.println(); 2148 pw.increaseIndent(); 2149 } 2150 2151 for (PackageInstallerSession childSession : entry.getValue()) { 2152 pw.print(tag + " Child "); 2153 childSession.dump(pw); 2154 pw.println(); 2155 } 2156 2157 pw.decreaseIndent(); 2158 } 2159 2160 pw.println(); 2161 pw.decreaseIndent(); 2162 } 2163 } 2164 2165 void dump(IndentingPrintWriter pw) { 2166 synchronized (mSessions) { 2167 ParentChildSessionMap activeSessionMap = new ParentChildSessionMap(); 2168 ParentChildSessionMap orphanedChildSessionMap = new ParentChildSessionMap(); 2169 ParentChildSessionMap finalizedSessionMap = new ParentChildSessionMap(); 2170 2171 int N = mSessions.size(); 2172 for (int i = 0; i < N; i++) { 2173 final PackageInstallerSession session = mSessions.valueAt(i); 2174 2175 final PackageInstallerSession rootSession = session.hasParentSessionId() 2176 ? getSession(session.getParentSessionId()) 2177 : session; 2178 // Do not print orphaned child sessions as active install sessions 2179 if (rootSession == null) { 2180 orphanedChildSessionMap.addSession(session, rootSession); 2181 continue; 2182 } 2183 2184 // Do not print finalized staged session as active install sessions 2185 if (rootSession.isStagedAndInTerminalState()) { 2186 finalizedSessionMap.addSession(session, rootSession); 2187 continue; 2188 } 2189 2190 activeSessionMap.addSession(session, rootSession); 2191 } 2192 2193 activeSessionMap.dump("Active", pw); 2194 2195 if (orphanedChildSessionMap.containsSession()) { 2196 // Presence of orphaned sessions indicate leak in cleanup for multi-package and 2197 // should be cleaned up. 2198 orphanedChildSessionMap.dump("Orphaned", pw); 2199 } 2200 2201 finalizedSessionMap.dump("Finalized", pw); 2202 2203 pw.println("Historical install sessions:"); 2204 pw.increaseIndent(); 2205 N = mHistoricalSessions.size(); 2206 for (int i = 0; i < N; i++) { 2207 mHistoricalSessions.get(i).dump(pw); 2208 pw.println(); 2209 } 2210 pw.println(); 2211 pw.decreaseIndent(); 2212 2213 pw.println("Legacy install sessions:"); 2214 pw.increaseIndent(); 2215 pw.println(mLegacySessions.toString()); 2216 pw.println(); 2217 pw.decreaseIndent(); 2218 } 2219 mSilentUpdatePolicy.dump(pw); 2220 mGentleUpdateHelper.dump(pw); 2221 } 2222 2223 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) 2224 public class InternalCallback { 2225 public void onSessionBadgingChanged(PackageInstallerSession session) { 2226 mCallbacks.notifySessionBadgingChanged(session.sessionId, session.userId); 2227 mSettingsWriteRequest.schedule(); 2228 } 2229 2230 public void onSessionActiveChanged(PackageInstallerSession session, boolean active) { 2231 mCallbacks.notifySessionActiveChanged(session.sessionId, session.userId, 2232 active); 2233 } 2234 2235 public void onSessionProgressChanged(PackageInstallerSession session, float progress) { 2236 mCallbacks.notifySessionProgressChanged(session.sessionId, session.userId, 2237 progress); 2238 } 2239 2240 public void onSessionChanged(PackageInstallerSession session) { 2241 session.markUpdated(); 2242 mSettingsWriteRequest.schedule(); 2243 // TODO(b/210359798): Remove the session.isStaged() check. Some apps assume this 2244 // broadcast is sent by only staged sessions and call isStagedSessionApplied() without 2245 // checking if it is a staged session or not and cause exception. 2246 if (mOkToSendBroadcasts && !session.isDestroyed() && session.isStaged()) { 2247 // we don't scrub the data here as this is sent only to the installer several 2248 // privileged system packages 2249 sendSessionUpdatedBroadcast( 2250 session.generateInfoForCaller(false/*icon*/, SYSTEM_UID), 2251 session.userId); 2252 } 2253 } 2254 2255 public void onSessionFinished(final PackageInstallerSession session, boolean success) { 2256 if (success) { 2257 // There is a timing issue here, if the callback opens the session again in 2258 // notifySessionFinished() immediately, the session may not be removed from 2259 // the mSession. But to avoid adding unknown latency, only notifying failures 2260 // are moved to the last of posted runnable, notifying success cases are 2261 // still kept here. 2262 mCallbacks.notifySessionFinished(session.sessionId, session.userId, success); 2263 } 2264 2265 mInstallHandler.post(new Runnable() { 2266 @Override 2267 public void run() { 2268 if (session.isStaged() && !success) { 2269 mStagingManager.abortSession(session.mStagedSession); 2270 } 2271 synchronized (mSessions) { 2272 // Child sessions will be removed along with its parent as a whole 2273 if (!session.hasParentSessionId()) { 2274 // Retain policy: 2275 // 1. Don't keep non-staged sessions 2276 // 2. Don't keep explicitly abandoned sessions 2277 // 3. Don't keep sessions that fail validation (isCommitted() is false) 2278 boolean shouldRemove = !session.isStaged() || session.isDestroyed() 2279 || !session.isCommitted(); 2280 if (shouldRemove) { 2281 removeActiveSession(session); 2282 } 2283 } 2284 2285 final File appIconFile = buildAppIconFile(session.sessionId); 2286 if (appIconFile.exists()) { 2287 appIconFile.delete(); 2288 } 2289 2290 mSettingsWriteRequest.runNow(); 2291 } 2292 if (!success) { 2293 mCallbacks.notifySessionFinished( 2294 session.sessionId, session.userId, success); 2295 } 2296 } 2297 }); 2298 } 2299 2300 public void onSessionPrepared(PackageInstallerSession session) { 2301 // We prepared the destination to write into; we want to persist 2302 // this, but it's not critical enough to block for. 2303 mSettingsWriteRequest.schedule(); 2304 } 2305 2306 public void onSessionSealedBlocking(PackageInstallerSession session) { 2307 // It's very important that we block until we've recorded the 2308 // session as being sealed, since we never want to allow mutation 2309 // after sealing. 2310 mSettingsWriteRequest.runNow(); 2311 } 2312 } 2313 2314 /** 2315 * Send a {@code PackageInstaller.ACTION_SESSION_UPDATED} broadcast intent, containing 2316 * the {@code sessionInfo} in the extra field {@code PackageInstaller.EXTRA_SESSION}. 2317 */ 2318 private void sendSessionUpdatedBroadcast(PackageInstaller.SessionInfo sessionInfo, 2319 int userId) { 2320 if (TextUtils.isEmpty(sessionInfo.installerPackageName)) { 2321 return; 2322 } 2323 Intent sessionUpdatedIntent = new Intent(PackageInstaller.ACTION_SESSION_UPDATED) 2324 .putExtra(PackageInstaller.EXTRA_SESSION, sessionInfo) 2325 .setPackage(sessionInfo.installerPackageName); 2326 mContext.sendBroadcastAsUser(sessionUpdatedIntent, UserHandle.of(userId)); 2327 } 2328 2329 /** 2330 * Abandon unfinished sessions if the installer package has been uninstalled. 2331 * @param installerAppId the app ID of the installer package that has been uninstalled. 2332 * @param userId the user that has the installer package uninstalled. 2333 */ 2334 void onInstallerPackageDeleted(int installerAppId, int userId) { 2335 synchronized (mSessions) { 2336 for (int i = 0; i < mSessions.size(); i++) { 2337 final PackageInstallerSession session = mSessions.valueAt(i); 2338 if (!matchesInstaller(session, installerAppId, userId)) { 2339 continue; 2340 } 2341 // Find parent session and only abandon parent session if installer matches 2342 PackageInstallerSession root = !session.hasParentSessionId() 2343 ? session : mSessions.get(session.getParentSessionId()); 2344 if (root != null && matchesInstaller(root, installerAppId, userId) 2345 && !root.isDestroyed()) { 2346 root.abandon(); 2347 } 2348 } 2349 } 2350 } 2351 2352 private boolean matchesInstaller(PackageInstallerSession session, int installerAppId, 2353 int userId) { 2354 final int installerUid = session.getInstallerUid(); 2355 if (installerAppId == UserHandle.USER_ALL) { 2356 return UserHandle.getAppId(installerUid) == installerAppId; 2357 } else { 2358 return UserHandle.getUid(userId, installerAppId) == installerUid; 2359 } 2360 } 2361 } 2362