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