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.AppOpsManager.MODE_DEFAULT; 20 import static android.app.admin.DevicePolicyResources.Strings.Core.PACKAGE_INSTALLED_BY_DO; 21 import static android.app.admin.DevicePolicyResources.Strings.Core.PACKAGE_UPDATED_BY_DO; 22 import static android.content.pm.DataLoaderType.INCREMENTAL; 23 import static android.content.pm.DataLoaderType.STREAMING; 24 import static android.content.pm.PackageInstaller.LOCATION_DATA_APP; 25 import static android.content.pm.PackageInstaller.UNARCHIVAL_OK; 26 import static android.content.pm.PackageInstaller.UNARCHIVAL_STATUS_UNSET; 27 import static android.content.pm.PackageItemInfo.MAX_SAFE_LABEL_LENGTH; 28 import static android.content.pm.PackageManager.INSTALL_FAILED_ABORTED; 29 import static android.content.pm.PackageManager.INSTALL_FAILED_BAD_SIGNATURE; 30 import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; 31 import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR; 32 import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK; 33 import static android.content.pm.PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE; 34 import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SPLIT; 35 import static android.content.pm.PackageManager.INSTALL_FAILED_PRE_APPROVAL_NOT_AVAILABLE; 36 import static android.content.pm.PackageManager.INSTALL_FAILED_SESSION_INVALID; 37 import static android.content.pm.PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE; 38 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES; 39 import static android.content.pm.PackageManager.INSTALL_STAGED; 40 import static android.content.pm.PackageManager.INSTALL_SUCCEEDED; 41 import static android.os.Process.INVALID_UID; 42 import static android.provider.DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE; 43 import static android.system.OsConstants.O_CREAT; 44 import static android.system.OsConstants.O_RDONLY; 45 import static android.system.OsConstants.O_WRONLY; 46 47 import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; 48 import static com.android.internal.util.XmlUtils.readBitmapAttribute; 49 import static com.android.internal.util.XmlUtils.readByteArrayAttribute; 50 import static com.android.internal.util.XmlUtils.readStringAttribute; 51 import static com.android.internal.util.XmlUtils.readUriAttribute; 52 import static com.android.internal.util.XmlUtils.writeBooleanAttribute; 53 import static com.android.internal.util.XmlUtils.writeByteArrayAttribute; 54 import static com.android.internal.util.XmlUtils.writeStringAttribute; 55 import static com.android.internal.util.XmlUtils.writeUriAttribute; 56 import static com.android.server.pm.PackageInstallerService.prepareStageDir; 57 import static com.android.server.pm.PackageManagerService.APP_METADATA_FILE_NAME; 58 import static com.android.server.pm.PackageManagerService.DEFAULT_FILE_ACCESS_MODE; 59 import static com.android.server.pm.PackageManagerServiceUtils.isInstalledByAdb; 60 import static com.android.server.pm.PackageManagerShellCommandDataLoader.Metadata; 61 62 import android.Manifest; 63 import android.annotation.AnyThread; 64 import android.annotation.IntDef; 65 import android.annotation.NonNull; 66 import android.annotation.Nullable; 67 import android.annotation.WorkerThread; 68 import android.app.AppOpsManager; 69 import android.app.BroadcastOptions; 70 import android.app.Notification; 71 import android.app.NotificationManager; 72 import android.app.PendingIntent; 73 import android.app.admin.DevicePolicyEventLogger; 74 import android.app.admin.DevicePolicyManager; 75 import android.app.admin.DevicePolicyManagerInternal; 76 import android.app.compat.CompatChanges; 77 import android.compat.annotation.ChangeId; 78 import android.compat.annotation.Disabled; 79 import android.compat.annotation.EnabledSince; 80 import android.content.ComponentName; 81 import android.content.Context; 82 import android.content.Intent; 83 import android.content.IntentSender; 84 import android.content.pm.ApplicationInfo; 85 import android.content.pm.Checksum; 86 import android.content.pm.DataLoaderManager; 87 import android.content.pm.DataLoaderParams; 88 import android.content.pm.DataLoaderParamsParcel; 89 import android.content.pm.FileSystemControlParcel; 90 import android.content.pm.IDataLoader; 91 import android.content.pm.IDataLoaderStatusListener; 92 import android.content.pm.IOnChecksumsReadyListener; 93 import android.content.pm.IPackageInstallObserver2; 94 import android.content.pm.IPackageInstallerSession; 95 import android.content.pm.IPackageInstallerSessionFileSystemConnector; 96 import android.content.pm.IPackageLoadingProgressCallback; 97 import android.content.pm.InstallSourceInfo; 98 import android.content.pm.InstallationFile; 99 import android.content.pm.InstallationFileParcel; 100 import android.content.pm.PackageInfo; 101 import android.content.pm.PackageInstaller; 102 import android.content.pm.PackageInstaller.PreapprovalDetails; 103 import android.content.pm.PackageInstaller.SessionInfo; 104 import android.content.pm.PackageInstaller.SessionParams; 105 import android.content.pm.PackageInstaller.UnarchivalStatus; 106 import android.content.pm.PackageInstaller.UserActionReason; 107 import android.content.pm.PackageManager; 108 import android.content.pm.PackageManager.PackageInfoFlags; 109 import android.content.pm.PackageManagerInternal; 110 import android.content.pm.SigningDetails; 111 import android.content.pm.dex.DexMetadataHelper; 112 import android.content.pm.parsing.ApkLite; 113 import android.content.pm.parsing.ApkLiteParseUtils; 114 import android.content.pm.parsing.PackageLite; 115 import android.content.pm.parsing.result.ParseResult; 116 import android.content.pm.parsing.result.ParseTypeImpl; 117 import android.content.pm.verify.domain.DomainSet; 118 import android.content.res.ApkAssets; 119 import android.content.res.AssetManager; 120 import android.content.res.Configuration; 121 import android.content.res.Resources; 122 import android.graphics.Bitmap; 123 import android.graphics.BitmapFactory; 124 import android.icu.util.ULocale; 125 import android.os.Binder; 126 import android.os.Build; 127 import android.os.Bundle; 128 import android.os.Environment; 129 import android.os.FileBridge; 130 import android.os.FileUtils; 131 import android.os.Handler; 132 import android.os.Looper; 133 import android.os.Message; 134 import android.os.ParcelFileDescriptor; 135 import android.os.ParcelableException; 136 import android.os.Process; 137 import android.os.RemoteException; 138 import android.os.RevocableFileDescriptor; 139 import android.os.SELinux; 140 import android.os.ServiceManager; 141 import android.os.SystemProperties; 142 import android.os.UserHandle; 143 import android.os.incremental.IStorageHealthListener; 144 import android.os.incremental.IncrementalFileStorages; 145 import android.os.incremental.IncrementalManager; 146 import android.os.incremental.PerUidReadTimeouts; 147 import android.os.incremental.StorageHealthCheckParams; 148 import android.os.incremental.V4Signature; 149 import android.os.storage.StorageManager; 150 import android.provider.DeviceConfig; 151 import android.provider.Settings.Global; 152 import android.service.persistentdata.PersistentDataBlockManager; 153 import android.stats.devicepolicy.DevicePolicyEnums; 154 import android.system.ErrnoException; 155 import android.system.Int64Ref; 156 import android.system.Os; 157 import android.system.OsConstants; 158 import android.system.StructStat; 159 import android.text.TextUtils; 160 import android.util.ArrayMap; 161 import android.util.ArraySet; 162 import android.util.EventLog; 163 import android.util.ExceptionUtils; 164 import android.util.IntArray; 165 import android.util.Log; 166 import android.util.MathUtils; 167 import android.util.Slog; 168 import android.util.SparseArray; 169 import android.util.apk.ApkSignatureVerifier; 170 171 import com.android.internal.R; 172 import com.android.internal.annotations.GuardedBy; 173 import com.android.internal.annotations.VisibleForTesting; 174 import com.android.internal.compat.IPlatformCompat; 175 import com.android.internal.content.InstallLocationUtils; 176 import com.android.internal.content.NativeLibraryHelper; 177 import com.android.internal.messages.nano.SystemMessageProto; 178 import com.android.internal.os.SomeArgs; 179 import com.android.internal.pm.pkg.parsing.ParsingPackageUtils; 180 import com.android.internal.security.VerityUtils; 181 import com.android.internal.util.ArrayUtils; 182 import com.android.internal.util.CollectionUtils; 183 import com.android.internal.util.FrameworkStatsLog; 184 import com.android.internal.util.IndentingPrintWriter; 185 import com.android.internal.util.Preconditions; 186 import com.android.modules.utils.TypedXmlPullParser; 187 import com.android.modules.utils.TypedXmlSerializer; 188 import com.android.server.LocalServices; 189 import com.android.server.pm.Installer.InstallerException; 190 import com.android.server.pm.dex.DexManager; 191 import com.android.server.pm.pkg.AndroidPackage; 192 import com.android.server.pm.pkg.PackageStateInternal; 193 194 import libcore.io.IoUtils; 195 import libcore.util.EmptyArray; 196 197 import org.xmlpull.v1.XmlPullParser; 198 import org.xmlpull.v1.XmlPullParserException; 199 200 import java.io.ByteArrayOutputStream; 201 import java.io.File; 202 import java.io.FileDescriptor; 203 import java.io.FileFilter; 204 import java.io.FileNotFoundException; 205 import java.io.FileOutputStream; 206 import java.io.IOException; 207 import java.nio.file.Files; 208 import java.security.NoSuchAlgorithmException; 209 import java.security.SignatureException; 210 import java.security.cert.Certificate; 211 import java.util.ArrayList; 212 import java.util.Arrays; 213 import java.util.Collections; 214 import java.util.List; 215 import java.util.Objects; 216 import java.util.Set; 217 import java.util.concurrent.CompletableFuture; 218 import java.util.concurrent.atomic.AtomicBoolean; 219 import java.util.concurrent.atomic.AtomicInteger; 220 import java.util.function.Predicate; 221 222 public class PackageInstallerSession extends IPackageInstallerSession.Stub { 223 private static final String TAG = "PackageInstallerSession"; 224 private static final boolean LOGD = true; 225 private static final String REMOVE_MARKER_EXTENSION = ".removed"; 226 227 private static final int MSG_ON_SESSION_SEALED = 1; 228 private static final int MSG_STREAM_VALIDATE_AND_COMMIT = 2; 229 private static final int MSG_INSTALL = 3; 230 private static final int MSG_ON_PACKAGE_INSTALLED = 4; 231 private static final int MSG_SESSION_VALIDATION_FAILURE = 5; 232 private static final int MSG_PRE_APPROVAL_REQUEST = 6; 233 234 /** XML constants used for persisting a session */ 235 static final String TAG_SESSION = "session"; 236 static final String TAG_CHILD_SESSION = "childSession"; 237 static final String TAG_SESSION_FILE = "sessionFile"; 238 static final String TAG_SESSION_CHECKSUM = "sessionChecksum"; 239 static final String TAG_SESSION_CHECKSUM_SIGNATURE = "sessionChecksumSignature"; 240 private static final String TAG_GRANTED_RUNTIME_PERMISSION = "granted-runtime-permission"; 241 private static final String TAG_GRANT_PERMISSION = "grant-permission"; 242 private static final String TAG_DENY_PERMISSION = "deny-permission"; 243 private static final String TAG_WHITELISTED_RESTRICTED_PERMISSION = 244 "whitelisted-restricted-permission"; 245 private static final String TAG_AUTO_REVOKE_PERMISSIONS_MODE = 246 "auto-revoke-permissions-mode"; 247 248 static final String TAG_PRE_VERIFIED_DOMAINS = "preVerifiedDomains"; 249 private static final String ATTR_SESSION_ID = "sessionId"; 250 private static final String ATTR_USER_ID = "userId"; 251 private static final String ATTR_INSTALLER_PACKAGE_NAME = "installerPackageName"; 252 private static final String ATTR_INSTALLER_PACKAGE_UID = "installerPackageUid"; 253 private static final String ATTR_UPDATE_OWNER_PACKAGE_NAME = "updateOwnererPackageName"; 254 private static final String ATTR_INSTALLER_ATTRIBUTION_TAG = "installerAttributionTag"; 255 private static final String ATTR_INSTALLER_UID = "installerUid"; 256 private static final String ATTR_INITIATING_PACKAGE_NAME = 257 "installInitiatingPackageName"; 258 private static final String ATTR_ORIGINATING_PACKAGE_NAME = 259 "installOriginatingPackageName"; 260 private static final String ATTR_CREATED_MILLIS = "createdMillis"; 261 private static final String ATTR_UPDATED_MILLIS = "updatedMillis"; 262 private static final String ATTR_COMMITTED_MILLIS = "committedMillis"; 263 private static final String ATTR_SESSION_STAGE_DIR = "sessionStageDir"; 264 private static final String ATTR_SESSION_STAGE_CID = "sessionStageCid"; 265 private static final String ATTR_PREPARED = "prepared"; 266 private static final String ATTR_COMMITTED = "committed"; 267 private static final String ATTR_DESTROYED = "destroyed"; 268 private static final String ATTR_SEALED = "sealed"; 269 private static final String ATTR_MULTI_PACKAGE = "multiPackage"; 270 private static final String ATTR_PARENT_SESSION_ID = "parentSessionId"; 271 private static final String ATTR_STAGED_SESSION = "stagedSession"; 272 private static final String ATTR_IS_READY = "isReady"; 273 private static final String ATTR_IS_FAILED = "isFailed"; 274 private static final String ATTR_IS_APPLIED = "isApplied"; 275 private static final String ATTR_PACKAGE_SOURCE = "packageSource"; 276 private static final String ATTR_SESSION_ERROR_CODE = "errorCode"; 277 private static final String ATTR_SESSION_ERROR_MESSAGE = "errorMessage"; 278 private static final String ATTR_MODE = "mode"; 279 private static final String ATTR_INSTALL_FLAGS = "installFlags"; 280 private static final String ATTR_INSTALL_LOCATION = "installLocation"; 281 private static final String ATTR_SIZE_BYTES = "sizeBytes"; 282 private static final String ATTR_APP_PACKAGE_NAME = "appPackageName"; 283 @Deprecated 284 private static final String ATTR_APP_ICON = "appIcon"; 285 private static final String ATTR_APP_LABEL = "appLabel"; 286 private static final String ATTR_ORIGINATING_URI = "originatingUri"; 287 private static final String ATTR_ORIGINATING_UID = "originatingUid"; 288 private static final String ATTR_REFERRER_URI = "referrerUri"; 289 private static final String ATTR_ABI_OVERRIDE = "abiOverride"; 290 private static final String ATTR_VOLUME_UUID = "volumeUuid"; 291 private static final String ATTR_NAME = "name"; 292 private static final String ATTR_INSTALL_REASON = "installRason"; 293 private static final String ATTR_IS_DATALOADER = "isDataLoader"; 294 private static final String ATTR_DATALOADER_TYPE = "dataLoaderType"; 295 private static final String ATTR_DATALOADER_PACKAGE_NAME = "dataLoaderPackageName"; 296 private static final String ATTR_DATALOADER_CLASS_NAME = "dataLoaderClassName"; 297 private static final String ATTR_DATALOADER_ARGUMENTS = "dataLoaderArguments"; 298 private static final String ATTR_LOCATION = "location"; 299 private static final String ATTR_LENGTH_BYTES = "lengthBytes"; 300 private static final String ATTR_METADATA = "metadata"; 301 private static final String ATTR_SIGNATURE = "signature"; 302 private static final String ATTR_CHECKSUM_KIND = "checksumKind"; 303 private static final String ATTR_CHECKSUM_VALUE = "checksumValue"; 304 private static final String ATTR_APPLICATION_ENABLED_SETTING_PERSISTENT = 305 "applicationEnabledSettingPersistent"; 306 private static final String ATTR_DOMAIN = "domain"; 307 308 private static final String PROPERTY_NAME_INHERIT_NATIVE = "pi.inherit_native_on_dont_kill"; 309 private static final int[] EMPTY_CHILD_SESSION_ARRAY = EmptyArray.INT; 310 private static final InstallationFile[] EMPTY_INSTALLATION_FILE_ARRAY = {}; 311 312 private static final String SYSTEM_DATA_LOADER_PACKAGE = "android"; 313 private static final String APEX_FILE_EXTENSION = ".apex"; 314 315 private static final int INCREMENTAL_STORAGE_BLOCKED_TIMEOUT_MS = 2000; 316 private static final int INCREMENTAL_STORAGE_UNHEALTHY_TIMEOUT_MS = 7000; 317 private static final int INCREMENTAL_STORAGE_UNHEALTHY_MONITORING_MS = 60000; 318 319 /** 320 * If an app being installed targets {@link Build.VERSION_CODES#TIRAMISU API 33} and above, 321 * the app can be installed without user action. 322 * See {@link PackageInstaller.SessionParams#setRequireUserAction} for other conditions required 323 * to be satisfied for a silent install. 324 */ 325 @ChangeId 326 @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) 327 private static final long SILENT_INSTALL_ALLOWED = 325888262L; 328 329 /** 330 * The system supports pre-approval and update ownership features from 331 * {@link Build.VERSION_CODES#UPSIDE_DOWN_CAKE API 34}. The change id is used to make sure 332 * the system includes the fix of pre-approval with update ownership case. When checking the 333 * change id, if it is disabled, it means the build includes the fix. The more detail is on 334 * b/293644536. 335 * See {@link PackageInstaller.SessionParams#setRequestUpdateOwnership(boolean)} and 336 * {@link #requestUserPreapproval(PreapprovalDetails, IntentSender)} for more details. 337 */ 338 @Disabled 339 @ChangeId 340 private static final long PRE_APPROVAL_WITH_UPDATE_OWNERSHIP_FIX = 293644536L; 341 342 /** 343 * The default value of {@link #mValidatedTargetSdk} is {@link Integer#MAX_VALUE}. If {@link 344 * #mValidatedTargetSdk} is compared with {@link Build.VERSION_CODES#S} before getting the 345 * target sdk version from a validated apk in {@link #validateApkInstallLocked()}, the compared 346 * result will not trigger any user action in 347 * {@link #checkUserActionRequirement(PackageInstallerSession, IntentSender)}. 348 */ 349 private static final int INVALID_TARGET_SDK_VERSION = Integer.MAX_VALUE; 350 351 /** 352 * Byte size limit for app metadata. 353 * 354 * Flag type: {@code long} 355 * Namespace: NAMESPACE_PACKAGE_MANAGER_SERVICE 356 */ 357 private static final String PROPERTY_APP_METADATA_BYTE_SIZE_LIMIT = 358 "app_metadata_byte_size_limit"; 359 360 /** Default byte size limit for app metadata */ 361 private static final long DEFAULT_APP_METADATA_BYTE_SIZE_LIMIT = 32000; 362 363 static final int APP_METADATA_FILE_ACCESS_MODE = 0640; 364 365 /** 366 * Throws IllegalArgumentException if the {@link IntentSender} from an immutable 367 * {@link android.app.PendingIntent} when caller has a target SDK of API 368 * {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} or above. 369 */ 370 @ChangeId 371 @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM) 372 private static final long THROW_EXCEPTION_COMMIT_WITH_IMMUTABLE_PENDING_INTENT = 240618202L; 373 374 /** 375 * Configurable maximum number of pre-verified domains allowed to be added to the session. 376 * Flag type: {@code long} 377 * Namespace: NAMESPACE_PACKAGE_MANAGER_SERVICE 378 */ 379 private static final String PROPERTY_PRE_VERIFIED_DOMAINS_COUNT_LIMIT = 380 "pre_verified_domains_count_limit"; 381 /** 382 * Configurable maximum string length of each pre-verified domain. 383 * Flag type: {@code long} 384 * Namespace: NAMESPACE_PACKAGE_MANAGER_SERVICE 385 */ 386 private static final String PROPERTY_PRE_VERIFIED_DOMAIN_LENGTH_LIMIT = 387 "pre_verified_domain_length_limit"; 388 /** Default max number of pre-verified domains */ 389 private static final long DEFAULT_PRE_VERIFIED_DOMAINS_COUNT_LIMIT = 1000; 390 /** Default max string length of each pre-verified domain */ 391 private static final long DEFAULT_PRE_VERIFIED_DOMAIN_LENGTH_LIMIT = 256; 392 393 // TODO: enforce INSTALL_ALLOW_TEST 394 // TODO: enforce INSTALL_ALLOW_DOWNGRADE 395 396 private final PackageInstallerService.InternalCallback mCallback; 397 private final Context mContext; 398 private final PackageManagerService mPm; 399 private final Installer mInstaller; 400 private final Handler mHandler; 401 private final PackageSessionProvider mSessionProvider; 402 private final SilentUpdatePolicy mSilentUpdatePolicy; 403 /** 404 * Note all calls must be done outside {@link #mLock} to prevent lock inversion. 405 */ 406 private final StagingManager mStagingManager; 407 408 final int sessionId; 409 final int userId; 410 final SessionParams params; 411 final long createdMillis; 412 413 /** Used for tracking whether user action was required for an install. */ 414 @Nullable 415 private Boolean mUserActionRequired; 416 417 /** Staging location where client data is written. */ 418 final File stageDir; 419 final String stageCid; 420 421 private final AtomicInteger mActiveCount = new AtomicInteger(); 422 423 private final Object mLock = new Object(); 424 425 /** 426 * Used to detect and reject concurrent access to this session object to ensure mutation 427 * to multiple objects like {@link #addChildSessionId} are done atomically. 428 */ 429 private final AtomicBoolean mTransactionLock = new AtomicBoolean(false); 430 431 /** Timestamp of the last time this session changed state */ 432 @GuardedBy("mLock") 433 private long updatedMillis; 434 435 /** Timestamp of the time this session is committed */ 436 @GuardedBy("mLock") 437 private long committedMillis; 438 439 /** Uid of the creator of this session. */ 440 private final int mOriginalInstallerUid; 441 442 /** Package name of the app that created the installation session. */ 443 private final String mOriginalInstallerPackageName; 444 445 /** Uid of the owner of the installer session */ 446 private volatile int mInstallerUid; 447 448 /** Where this install request came from */ 449 @GuardedBy("mLock") 450 private InstallSource mInstallSource; 451 452 private final Object mProgressLock = new Object(); 453 454 @GuardedBy("mProgressLock") 455 private float mClientProgress = 0; 456 @GuardedBy("mProgressLock") 457 private float mInternalProgress = 0; 458 459 @GuardedBy("mProgressLock") 460 private float mProgress = 0; 461 @GuardedBy("mProgressLock") 462 private float mReportedProgress = -1; 463 @GuardedBy("mProgressLock") 464 private float mIncrementalProgress = 0; 465 466 /** State of the session. */ 467 @GuardedBy("mLock") 468 private boolean mPrepared = false; 469 @GuardedBy("mLock") 470 private boolean mSealed = false; 471 @GuardedBy("mLock") 472 private boolean mShouldBeSealed = false; 473 474 private final AtomicBoolean mPreapprovalRequested = new AtomicBoolean(false); 475 private final AtomicBoolean mCommitted = new AtomicBoolean(false); 476 477 /** 478 * True if staging files are being used by external entities like {@link PackageSessionVerifier} 479 * or {@link PackageManagerService} which means it is not safe for {@link #abandon()} to clean 480 * up the files. 481 */ 482 @GuardedBy("mLock") 483 private boolean mStageDirInUse = false; 484 485 /** 486 * True if the verification is already in progress. This is used to prevent running 487 * verification again while one is already in progress which will break internal states. 488 * 489 * Worker thread only. 490 */ 491 private boolean mVerificationInProgress = false; 492 493 /** Permissions have been accepted by the user (see {@link #setPermissionsResult}) */ 494 @GuardedBy("mLock") 495 private boolean mPermissionsManuallyAccepted = false; 496 497 @GuardedBy("mLock") 498 private int mFinalStatus; 499 @GuardedBy("mLock") 500 private String mFinalMessage; 501 502 @GuardedBy("mLock") 503 private final ArrayList<RevocableFileDescriptor> mFds = new ArrayList<>(); 504 @GuardedBy("mLock") 505 private final ArrayList<FileBridge> mBridges = new ArrayList<>(); 506 507 @GuardedBy("mLock") 508 private IntentSender mRemoteStatusReceiver; 509 510 @GuardedBy("mLock") 511 private IntentSender mPreapprovalRemoteStatusReceiver; 512 513 @GuardedBy("mLock") 514 private PreapprovalDetails mPreapprovalDetails; 515 516 /** Fields derived from commit parsing */ 517 @GuardedBy("mLock") 518 private String mPackageName; 519 @GuardedBy("mLock") 520 private long mVersionCode; 521 @GuardedBy("mLock") 522 private SigningDetails mSigningDetails; 523 @GuardedBy("mLock") 524 private final SparseArray<PackageInstallerSession> mChildSessions = new SparseArray<>(); 525 @GuardedBy("mLock") 526 private int mParentSessionId; 527 528 @GuardedBy("mLock") 529 private boolean mHasDeviceAdminReceiver; 530 531 @GuardedBy("mLock") 532 private int mUserActionRequirement; 533 534 @GuardedBy("mLock") 535 private DomainSet mPreVerifiedDomains; 536 537 static class FileEntry { 538 private final int mIndex; 539 private final InstallationFile mFile; 540 FileEntry(int index, InstallationFile file)541 FileEntry(int index, InstallationFile file) { 542 this.mIndex = index; 543 this.mFile = file; 544 } 545 getIndex()546 int getIndex() { 547 return this.mIndex; 548 } 549 getFile()550 InstallationFile getFile() { 551 return this.mFile; 552 } 553 554 @Override equals(Object obj)555 public boolean equals(Object obj) { 556 if (!(obj instanceof FileEntry)) { 557 return false; 558 } 559 final FileEntry rhs = (FileEntry) obj; 560 return (mFile.getLocation() == rhs.mFile.getLocation()) && TextUtils.equals( 561 mFile.getName(), rhs.mFile.getName()); 562 } 563 564 @Override hashCode()565 public int hashCode() { 566 return Objects.hash(mFile.getLocation(), mFile.getName()); 567 } 568 } 569 570 @GuardedBy("mLock") 571 private final ArraySet<FileEntry> mFiles = new ArraySet<>(); 572 573 static class PerFileChecksum { 574 private final Checksum[] mChecksums; 575 private final byte[] mSignature; 576 PerFileChecksum(Checksum[] checksums, byte[] signature)577 PerFileChecksum(Checksum[] checksums, byte[] signature) { 578 mChecksums = checksums; 579 mSignature = signature; 580 } 581 getChecksums()582 Checksum[] getChecksums() { 583 return this.mChecksums; 584 } 585 getSignature()586 byte[] getSignature() { 587 return this.mSignature; 588 } 589 } 590 591 @GuardedBy("mLock") 592 private final ArrayMap<String, PerFileChecksum> mChecksums = new ArrayMap<>(); 593 594 @GuardedBy("mLock") 595 private boolean mSessionApplied; 596 @GuardedBy("mLock") 597 private boolean mSessionReady; 598 @GuardedBy("mLock") 599 private boolean mSessionFailed; 600 @GuardedBy("mLock") 601 private int mSessionErrorCode = PackageManager.INSTALL_UNKNOWN; 602 @GuardedBy("mLock") 603 private String mSessionErrorMessage; 604 605 @GuardedBy("mLock") 606 private boolean mHasAppMetadataFile = false; 607 608 @Nullable 609 final StagedSession mStagedSession; 610 611 /** 612 * The callback to run when pre-reboot verification has ended. Used by {@link #abandon()} 613 * to delay session clean-up until it is safe to do so. 614 */ 615 @GuardedBy("mLock") 616 @Nullable 617 private Runnable mPendingAbandonCallback; 618 619 @VisibleForTesting 620 public class StagedSession implements StagingManager.StagedSession { 621 @Override getChildSessions()622 public List<StagingManager.StagedSession> getChildSessions() { 623 if (!params.isMultiPackage) { 624 return Collections.EMPTY_LIST; 625 } 626 synchronized (mLock) { 627 int size = mChildSessions.size(); 628 List<StagingManager.StagedSession> childSessions = new ArrayList<>(size); 629 for (int i = 0; i < size; ++i) { 630 childSessions.add(mChildSessions.valueAt(i).mStagedSession); 631 } 632 return childSessions; 633 } 634 } 635 636 @Override sessionParams()637 public SessionParams sessionParams() { 638 return params; 639 } 640 641 @Override isMultiPackage()642 public boolean isMultiPackage() { 643 return params.isMultiPackage; 644 } 645 646 @Override isApexSession()647 public boolean isApexSession() { 648 return (params.installFlags & PackageManager.INSTALL_APEX) != 0; 649 } 650 651 @Override sessionId()652 public int sessionId() { 653 return sessionId; 654 } 655 656 @Override containsApexSession()657 public boolean containsApexSession() { 658 return sessionContains((s) -> s.isApexSession()); 659 } 660 661 @Override getPackageName()662 public String getPackageName() { 663 return PackageInstallerSession.this.getPackageName(); 664 } 665 666 @Override setSessionReady()667 public void setSessionReady() { 668 PackageInstallerSession.this.setSessionReady(); 669 } 670 671 @Override setSessionFailed(int errorCode, String errorMessage)672 public void setSessionFailed(int errorCode, String errorMessage) { 673 PackageInstallerSession.this.setSessionFailed(errorCode, errorMessage); 674 } 675 676 @Override setSessionApplied()677 public void setSessionApplied() { 678 PackageInstallerSession.this.setSessionApplied(); 679 } 680 681 @Override containsApkSession()682 public boolean containsApkSession() { 683 return PackageInstallerSession.this.containsApkSession(); 684 } 685 686 /** 687 * Installs apks of staged session while skipping the verification process for a committed 688 * and ready session. 689 * 690 * @return a CompletableFuture that will be completed when installation completes. 691 */ 692 @Override installSession()693 public CompletableFuture<Void> installSession() { 694 assertCallerIsOwnerOrRootOrSystem(); 695 assertNotChild("StagedSession#installSession"); 696 Preconditions.checkArgument(isCommitted() && isSessionReady()); 697 return install(); 698 } 699 700 @Override hasParentSessionId()701 public boolean hasParentSessionId() { 702 return PackageInstallerSession.this.hasParentSessionId(); 703 } 704 705 @Override getParentSessionId()706 public int getParentSessionId() { 707 return PackageInstallerSession.this.getParentSessionId(); 708 } 709 710 @Override isCommitted()711 public boolean isCommitted() { 712 return PackageInstallerSession.this.isCommitted(); 713 } 714 715 @Override isInTerminalState()716 public boolean isInTerminalState() { 717 return PackageInstallerSession.this.isInTerminalState(); 718 } 719 720 @Override isDestroyed()721 public boolean isDestroyed() { 722 return PackageInstallerSession.this.isDestroyed(); 723 } 724 725 @Override getCommittedMillis()726 public long getCommittedMillis() { 727 return PackageInstallerSession.this.getCommittedMillis(); 728 } 729 730 @Override sessionContains(Predicate<StagingManager.StagedSession> filter)731 public boolean sessionContains(Predicate<StagingManager.StagedSession> filter) { 732 return PackageInstallerSession.this.sessionContains(s -> filter.test(s.mStagedSession)); 733 } 734 735 @Override isSessionReady()736 public boolean isSessionReady() { 737 return PackageInstallerSession.this.isSessionReady(); 738 } 739 740 @Override isSessionApplied()741 public boolean isSessionApplied() { 742 return PackageInstallerSession.this.isSessionApplied(); 743 } 744 745 @Override isSessionFailed()746 public boolean isSessionFailed() { 747 return PackageInstallerSession.this.isSessionFailed(); 748 } 749 750 @Override abandon()751 public void abandon() { 752 PackageInstallerSession.this.abandon(); 753 } 754 755 /** 756 * Resumes verification process for non-final committed staged session. 757 * 758 * Useful if a device gets rebooted before verification is complete and we need to restart 759 * the verification. 760 */ 761 @Override verifySession()762 public void verifySession() { 763 assertCallerIsOwnerOrRootOrSystem(); 764 if (isCommittedAndNotInTerminalState()) { 765 verify(); 766 } 767 } 768 isCommittedAndNotInTerminalState()769 private boolean isCommittedAndNotInTerminalState() { 770 String errorMsg = null; 771 if (!isCommitted()) { 772 errorMsg = TextUtils.formatSimple("The session %d should be committed", sessionId); 773 } else if (isSessionApplied()) { 774 errorMsg = TextUtils.formatSimple("The session %d has applied", sessionId); 775 } else if (isSessionFailed()) { 776 synchronized (PackageInstallerSession.this.mLock) { 777 errorMsg = TextUtils.formatSimple("The session %d has failed with error: %s", 778 sessionId, PackageInstallerSession.this.mSessionErrorMessage); 779 } 780 } 781 if (errorMsg != null) { 782 Slog.e(TAG, "verifySession error: " + errorMsg); 783 setSessionFailed(INSTALL_FAILED_INTERNAL_ERROR, errorMsg); 784 onSessionVerificationFailure(INSTALL_FAILED_INTERNAL_ERROR, errorMsg); 785 return false; 786 } 787 return true; 788 } 789 } 790 791 /** 792 * Path to the validated base APK for this session, which may point at an 793 * APK inside the session (when the session defines the base), or it may 794 * point at the existing base APK (when adding splits to an existing app). 795 * <p> 796 * This is used when confirming permissions, since we can't fully stage the 797 * session inside an ASEC before confirming with user. 798 */ 799 @GuardedBy("mLock") 800 private File mResolvedBaseFile; 801 802 @GuardedBy("mLock") 803 private final List<File> mResolvedStagedFiles = new ArrayList<>(); 804 @GuardedBy("mLock") 805 private final List<File> mResolvedInheritedFiles = new ArrayList<>(); 806 @GuardedBy("mLock") 807 private final List<String> mResolvedInstructionSets = new ArrayList<>(); 808 @GuardedBy("mLock") 809 private final List<String> mResolvedNativeLibPaths = new ArrayList<>(); 810 811 @GuardedBy("mLock") 812 private final Set<IntentSender> mUnarchivalListeners = new ArraySet<>(); 813 814 @GuardedBy("mLock") 815 private File mInheritedFilesBase; 816 @GuardedBy("mLock") 817 private boolean mVerityFoundForApks; 818 819 /** 820 * Both flags should be guarded with mLock whenever changes need to be in lockstep. 821 * Ok to check without mLock in case the proper check is done later, e.g. status callbacks 822 * for DataLoaders with deferred processing. 823 */ 824 private volatile boolean mDestroyed = false; 825 private volatile boolean mDataLoaderFinished = false; 826 827 @GuardedBy("mLock") 828 private IncrementalFileStorages mIncrementalFileStorages; 829 830 @GuardedBy("mLock") 831 private PackageLite mPackageLite; 832 833 /** 834 * Keep the target sdk of a validated apk. 835 */ 836 @GuardedBy("mLock") 837 private int mValidatedTargetSdk = INVALID_TARGET_SDK_VERSION; 838 839 @UnarchivalStatus 840 private int mUnarchivalStatus = UNARCHIVAL_STATUS_UNSET; 841 842 private static final FileFilter sAddedApkFilter = new FileFilter() { 843 @Override 844 public boolean accept(File file) { 845 // Installers can't stage directories, so it's fine to ignore 846 // entries like "lost+found". 847 if (file.isDirectory()) return false; 848 if (file.getName().endsWith(REMOVE_MARKER_EXTENSION)) return false; 849 if (file.getName().endsWith(V4Signature.EXT)) return false; 850 if (isAppMetadata(file)) return false; 851 if (DexMetadataHelper.isDexMetadataFile(file)) return false; 852 if (VerityUtils.isFsveritySignatureFile(file)) return false; 853 if (ApkChecksums.isDigestOrDigestSignatureFile(file)) return false; 854 return true; 855 } 856 }; 857 private static final FileFilter sAddedFilter = new FileFilter() { 858 @Override 859 public boolean accept(File file) { 860 // Installers can't stage directories, so it's fine to ignore 861 // entries like "lost+found". 862 if (file.isDirectory()) return false; 863 if (file.getName().endsWith(REMOVE_MARKER_EXTENSION)) return false; 864 return true; 865 } 866 }; 867 private static final FileFilter sRemovedFilter = new FileFilter() { 868 @Override 869 public boolean accept(File file) { 870 if (file.isDirectory()) return false; 871 if (!file.getName().endsWith(REMOVE_MARKER_EXTENSION)) return false; 872 return true; 873 } 874 }; 875 isDataLoaderInstallation(SessionParams params)876 static boolean isDataLoaderInstallation(SessionParams params) { 877 return params.dataLoaderParams != null; 878 } 879 isSystemDataLoaderInstallation(SessionParams params)880 static boolean isSystemDataLoaderInstallation(SessionParams params) { 881 if (!isDataLoaderInstallation(params)) { 882 return false; 883 } 884 return SYSTEM_DATA_LOADER_PACKAGE.equals( 885 params.dataLoaderParams.getComponentName().getPackageName()); 886 } 887 isArchivedInstallation(int installFlags)888 static boolean isArchivedInstallation(int installFlags) { 889 return (installFlags & PackageManager.INSTALL_ARCHIVED) != 0; 890 } 891 892 private final Handler.Callback mHandlerCallback = new Handler.Callback() { 893 @Override 894 public boolean handleMessage(Message msg) { 895 switch (msg.what) { 896 case MSG_ON_SESSION_SEALED: 897 handleSessionSealed(); 898 break; 899 case MSG_STREAM_VALIDATE_AND_COMMIT: 900 handleStreamValidateAndCommit(); 901 break; 902 case MSG_INSTALL: 903 handleInstall(); 904 break; 905 case MSG_ON_PACKAGE_INSTALLED: 906 final SomeArgs args = (SomeArgs) msg.obj; 907 final String packageName = (String) args.arg1; 908 final String message = (String) args.arg2; 909 final Bundle extras = (Bundle) args.arg3; 910 final IntentSender statusReceiver = (IntentSender) args.arg4; 911 final int returnCode = args.argi1; 912 final boolean isPreapproval = args.argi2 == 1; 913 args.recycle(); 914 915 sendOnPackageInstalled(mContext, statusReceiver, sessionId, 916 isInstallerDeviceOwnerOrAffiliatedProfileOwner(), userId, 917 packageName, returnCode, isPreapproval, message, extras); 918 919 break; 920 case MSG_SESSION_VALIDATION_FAILURE: 921 final int error = msg.arg1; 922 final String detailMessage = (String) msg.obj; 923 onSessionValidationFailure(error, detailMessage); 924 break; 925 case MSG_PRE_APPROVAL_REQUEST: 926 handlePreapprovalRequest(); 927 break; 928 } 929 930 return true; 931 } 932 }; 933 isDataLoaderInstallation()934 private boolean isDataLoaderInstallation() { 935 return isDataLoaderInstallation(this.params); 936 } 937 isStreamingInstallation()938 private boolean isStreamingInstallation() { 939 return isDataLoaderInstallation() && params.dataLoaderParams.getType() == STREAMING; 940 } 941 isIncrementalInstallation()942 private boolean isIncrementalInstallation() { 943 return isDataLoaderInstallation() && params.dataLoaderParams.getType() == INCREMENTAL; 944 } 945 isSystemDataLoaderInstallation()946 private boolean isSystemDataLoaderInstallation() { 947 return isSystemDataLoaderInstallation(this.params); 948 } 949 isArchivedInstallation()950 private boolean isArchivedInstallation() { 951 return isArchivedInstallation(this.params.installFlags); 952 } 953 954 /** 955 * @return {@code true} iff the installing is app an device owner or affiliated profile owner. 956 */ isInstallerDeviceOwnerOrAffiliatedProfileOwner()957 private boolean isInstallerDeviceOwnerOrAffiliatedProfileOwner() { 958 assertNotLocked("isInstallerDeviceOwnerOrAffiliatedProfileOwner"); 959 if (userId != UserHandle.getUserId(getInstallerUid())) { 960 return false; 961 } 962 DevicePolicyManagerInternal dpmi = 963 LocalServices.getService(DevicePolicyManagerInternal.class); 964 // It may wait for a long time to finish {@code dpmi.canSilentlyInstallPackage}. 965 // Please don't acquire mLock before calling {@code dpmi.canSilentlyInstallPackage}. 966 return dpmi != null && dpmi.canSilentlyInstallPackage( 967 getInstallSource().mInstallerPackageName, mInstallerUid); 968 } 969 isEmergencyInstallerEnabled(String packageName, Computer snapshot, int userId, int installerUid)970 static boolean isEmergencyInstallerEnabled(String packageName, Computer snapshot, int userId, 971 int installerUid) { 972 final PackageStateInternal ps = snapshot.getPackageStateInternal(packageName); 973 if (ps == null || ps.getPkg() == null || !ps.isSystem()) { 974 return false; 975 } 976 int uid = UserHandle.getUid(userId, ps.getAppId()); 977 String emergencyInstaller = ps.getPkg().getEmergencyInstaller(); 978 if (emergencyInstaller == null || !ArrayUtils.contains( 979 snapshot.getPackagesForUid(installerUid), emergencyInstaller)) { 980 return false; 981 } 982 // Only system installers can have an emergency installer 983 if (PackageManager.PERMISSION_GRANTED 984 != snapshot.checkUidPermission(Manifest.permission.INSTALL_PACKAGES, uid) 985 && PackageManager.PERMISSION_GRANTED 986 != snapshot.checkUidPermission(Manifest.permission.INSTALL_PACKAGE_UPDATES, uid) 987 && PackageManager.PERMISSION_GRANTED 988 != snapshot.checkUidPermission(Manifest.permission.INSTALL_SELF_UPDATES, uid)) { 989 return false; 990 } 991 return (snapshot.checkUidPermission(Manifest.permission.EMERGENCY_INSTALL_PACKAGES, 992 installerUid) == PackageManager.PERMISSION_GRANTED); 993 } 994 995 private static final int USER_ACTION_NOT_NEEDED = 0; 996 private static final int USER_ACTION_REQUIRED = 1; 997 private static final int USER_ACTION_PENDING_APK_PARSING = 2; 998 private static final int USER_ACTION_REQUIRED_UPDATE_OWNER_REMINDER = 3; 999 1000 @IntDef({ 1001 USER_ACTION_NOT_NEEDED, 1002 USER_ACTION_REQUIRED, 1003 USER_ACTION_PENDING_APK_PARSING, 1004 USER_ACTION_REQUIRED_UPDATE_OWNER_REMINDER, 1005 }) 1006 @interface UserActionRequirement {} 1007 1008 /** 1009 * Checks if the permissions still need to be confirmed. 1010 * 1011 * <p>This is dependant on the identity of the installer, hence this cannot be cached if the 1012 * installer might still {@link #transfer(String) change}. 1013 * 1014 * @return {@code true} iff we need to ask to confirm the permissions? 1015 */ 1016 @UserActionRequirement computeUserActionRequirement()1017 private int computeUserActionRequirement() { 1018 final String packageName; 1019 final boolean hasDeviceAdminReceiver; 1020 synchronized (mLock) { 1021 if (mPermissionsManuallyAccepted) { 1022 return USER_ACTION_NOT_NEEDED; 1023 } 1024 // For pre-pappvoal case, the mPackageName would be null. 1025 if (mPackageName != null) { 1026 packageName = mPackageName; 1027 } else if (mPreapprovalRequested.get() && mPreapprovalDetails != null) { 1028 packageName = mPreapprovalDetails.getPackageName(); 1029 } else { 1030 packageName = null; 1031 } 1032 hasDeviceAdminReceiver = mHasDeviceAdminReceiver; 1033 } 1034 1035 // For the below cases, force user action prompt 1036 // 1. installFlags includes INSTALL_FORCE_PERMISSION_PROMPT 1037 // 2. params.requireUserAction is USER_ACTION_REQUIRED 1038 final boolean forceUserActionPrompt = 1039 (params.installFlags & PackageManager.INSTALL_FORCE_PERMISSION_PROMPT) != 0 1040 || params.requireUserAction == SessionParams.USER_ACTION_REQUIRED; 1041 final int userActionNotTypicallyNeededResponse = forceUserActionPrompt 1042 ? USER_ACTION_REQUIRED 1043 : USER_ACTION_NOT_NEEDED; 1044 1045 // It is safe to access mInstallerUid and mInstallSource without lock 1046 // because they are immutable after sealing. 1047 final Computer snapshot = mPm.snapshotComputer(); 1048 final boolean isInstallPermissionGranted = 1049 (snapshot.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES, 1050 mInstallerUid) == PackageManager.PERMISSION_GRANTED); 1051 final boolean isSelfUpdatePermissionGranted = 1052 (snapshot.checkUidPermission(android.Manifest.permission.INSTALL_SELF_UPDATES, 1053 mInstallerUid) == PackageManager.PERMISSION_GRANTED); 1054 final boolean isUpdatePermissionGranted = 1055 (snapshot.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGE_UPDATES, 1056 mInstallerUid) == PackageManager.PERMISSION_GRANTED); 1057 final boolean isUpdateWithoutUserActionPermissionGranted = (snapshot.checkUidPermission( 1058 android.Manifest.permission.UPDATE_PACKAGES_WITHOUT_USER_ACTION, mInstallerUid) 1059 == PackageManager.PERMISSION_GRANTED); 1060 final boolean isInstallDpcPackagesPermissionGranted = (snapshot.checkUidPermission( 1061 android.Manifest.permission.INSTALL_DPC_PACKAGES, mInstallerUid) 1062 == PackageManager.PERMISSION_GRANTED); 1063 // Also query the package uid for archived packages, so that the user confirmation 1064 // dialog can be displayed for updating archived apps. 1065 final int targetPackageUid = snapshot.getPackageUid(packageName, 1066 PackageManager.MATCH_ARCHIVED_PACKAGES, userId); 1067 final boolean isUpdate = targetPackageUid != -1 || isApexSession(); 1068 final InstallSourceInfo existingInstallSourceInfo = isUpdate 1069 ? snapshot.getInstallSourceInfo(packageName, userId) 1070 : null; 1071 final String existingInstallerPackageName = existingInstallSourceInfo != null 1072 ? existingInstallSourceInfo.getInstallingPackageName() 1073 : null; 1074 final String existingUpdateOwnerPackageName = existingInstallSourceInfo != null 1075 ? existingInstallSourceInfo.getUpdateOwnerPackageName() 1076 : null; 1077 final boolean isInstallerOfRecord = isUpdate 1078 && Objects.equals(existingInstallerPackageName, getInstallerPackageName()); 1079 final boolean isUpdateOwner = TextUtils.equals(existingUpdateOwnerPackageName, 1080 getInstallerPackageName()); 1081 final boolean isSelfUpdate = targetPackageUid == mInstallerUid; 1082 final boolean isEmergencyInstall = 1083 isEmergencyInstallerEnabled(packageName, snapshot, userId, mInstallerUid); 1084 final boolean isPermissionGranted = isInstallPermissionGranted 1085 || (isUpdatePermissionGranted && isUpdate) 1086 || (isSelfUpdatePermissionGranted && isSelfUpdate) 1087 || (isInstallDpcPackagesPermissionGranted && hasDeviceAdminReceiver); 1088 final boolean isInstallerRoot = (mInstallerUid == Process.ROOT_UID); 1089 final boolean isInstallerSystem = (mInstallerUid == Process.SYSTEM_UID); 1090 final boolean isInstallerShell = (mInstallerUid == Process.SHELL_UID); 1091 final boolean isFromManagedUserOrProfile = 1092 (params.installFlags & PackageManager.INSTALL_FROM_MANAGED_USER_OR_PROFILE) != 0; 1093 final boolean isUpdateOwnershipEnforcementEnabled = 1094 mPm.isUpdateOwnershipEnforcementAvailable() 1095 && existingUpdateOwnerPackageName != null; 1096 // For an installation that un-archives an app, if the installer doesn't have the 1097 // INSTALL_PACKAGES permission, the user should have already been prompted to confirm the 1098 // un-archive request. There's no need for another confirmation during the installation. 1099 final boolean isInstallUnarchive = 1100 (params.installFlags & PackageManager.INSTALL_UNARCHIVE) != 0; 1101 1102 // Device owners and affiliated profile owners are allowed to silently install packages, so 1103 // the permission check is waived if the installer is the device owner. 1104 final boolean noUserActionNecessary = isInstallerRoot || isInstallerSystem 1105 || isInstallerDeviceOwnerOrAffiliatedProfileOwner() || isEmergencyInstall 1106 || isInstallUnarchive; 1107 1108 if (noUserActionNecessary) { 1109 return userActionNotTypicallyNeededResponse; 1110 } 1111 1112 if (isUpdateOwnershipEnforcementEnabled 1113 && !isApexSession() 1114 && !isUpdateOwner 1115 && !isInstallerShell 1116 // We don't enforce the update ownership for the managed user and profile. 1117 && !isFromManagedUserOrProfile) { 1118 return USER_ACTION_REQUIRED_UPDATE_OWNER_REMINDER; 1119 } 1120 1121 if (isPermissionGranted) { 1122 return userActionNotTypicallyNeededResponse; 1123 } 1124 1125 if (snapshot.isInstallDisabledForPackage(getInstallerPackageName(), mInstallerUid, 1126 userId)) { 1127 // show the installer to account for device policy or unknown sources use cases 1128 return USER_ACTION_REQUIRED; 1129 } 1130 1131 if (params.requireUserAction == SessionParams.USER_ACTION_NOT_REQUIRED 1132 && isUpdateWithoutUserActionPermissionGranted 1133 && ((isUpdateOwnershipEnforcementEnabled ? isUpdateOwner 1134 : isInstallerOfRecord) || isSelfUpdate)) { 1135 return USER_ACTION_PENDING_APK_PARSING; 1136 } 1137 1138 return USER_ACTION_REQUIRED; 1139 } 1140 updateUserActionRequirement(int requirement)1141 private void updateUserActionRequirement(int requirement) { 1142 synchronized (mLock) { 1143 mUserActionRequirement = requirement; 1144 } 1145 } 1146 1147 @SuppressWarnings("GuardedBy" /*mPm.mInstaller is {@code final} field*/) PackageInstallerSession(PackageInstallerService.InternalCallback callback, Context context, PackageManagerService pm, PackageSessionProvider sessionProvider, SilentUpdatePolicy silentUpdatePolicy, Looper looper, StagingManager stagingManager, int sessionId, int userId, int installerUid, @NonNull InstallSource installSource, SessionParams params, long createdMillis, long committedMillis, File stageDir, String stageCid, InstallationFile[] files, ArrayMap<String, PerFileChecksum> checksums, boolean prepared, boolean committed, boolean destroyed, boolean sealed, @Nullable int[] childSessionIds, int parentSessionId, boolean isReady, boolean isFailed, boolean isApplied, int sessionErrorCode, String sessionErrorMessage, DomainSet preVerifiedDomains)1148 public PackageInstallerSession(PackageInstallerService.InternalCallback callback, 1149 Context context, PackageManagerService pm, 1150 PackageSessionProvider sessionProvider, 1151 SilentUpdatePolicy silentUpdatePolicy, Looper looper, StagingManager stagingManager, 1152 int sessionId, int userId, int installerUid, @NonNull InstallSource installSource, 1153 SessionParams params, long createdMillis, long committedMillis, 1154 File stageDir, String stageCid, InstallationFile[] files, 1155 ArrayMap<String, PerFileChecksum> checksums, 1156 boolean prepared, boolean committed, boolean destroyed, boolean sealed, 1157 @Nullable int[] childSessionIds, int parentSessionId, boolean isReady, 1158 boolean isFailed, boolean isApplied, int sessionErrorCode, 1159 String sessionErrorMessage, DomainSet preVerifiedDomains) { 1160 mCallback = callback; 1161 mContext = context; 1162 mPm = pm; 1163 mInstaller = (mPm != null) ? mPm.mInstaller : null; 1164 mSessionProvider = sessionProvider; 1165 mSilentUpdatePolicy = silentUpdatePolicy; 1166 mHandler = new Handler(looper, mHandlerCallback); 1167 mStagingManager = stagingManager; 1168 1169 this.sessionId = sessionId; 1170 this.userId = userId; 1171 mOriginalInstallerUid = installerUid; 1172 mInstallerUid = installerUid; 1173 mInstallSource = Objects.requireNonNull(installSource); 1174 mOriginalInstallerPackageName = mInstallSource.mInstallerPackageName; 1175 this.params = params; 1176 this.createdMillis = createdMillis; 1177 this.updatedMillis = createdMillis; 1178 this.committedMillis = committedMillis; 1179 this.stageDir = stageDir; 1180 this.stageCid = stageCid; 1181 this.mShouldBeSealed = sealed; 1182 if (childSessionIds != null) { 1183 for (int childSessionId : childSessionIds) { 1184 // Null values will be resolved to actual object references in 1185 // #onAfterSessionRead later. 1186 mChildSessions.put(childSessionId, null); 1187 } 1188 } 1189 this.mParentSessionId = parentSessionId; 1190 1191 if (files != null) { 1192 mFiles.ensureCapacity(files.length); 1193 for (int i = 0, size = files.length; i < size; ++i) { 1194 InstallationFile file = files[i]; 1195 if (!mFiles.add(new FileEntry(i, file))) { 1196 throw new IllegalArgumentException( 1197 "Trying to add a duplicate installation file"); 1198 } 1199 } 1200 } 1201 1202 if (checksums != null) { 1203 mChecksums.putAll(checksums); 1204 } 1205 1206 if (!params.isMultiPackage && (stageDir == null) == (stageCid == null)) { 1207 throw new IllegalArgumentException( 1208 "Exactly one of stageDir or stageCid stage must be set"); 1209 } 1210 1211 mPrepared = prepared; 1212 mCommitted.set(committed); 1213 mDestroyed = destroyed; 1214 mSessionReady = isReady; 1215 mSessionApplied = isApplied; 1216 mSessionFailed = isFailed; 1217 mSessionErrorCode = sessionErrorCode; 1218 mSessionErrorMessage = 1219 sessionErrorMessage != null ? sessionErrorMessage : ""; 1220 mStagedSession = params.isStaged ? new StagedSession() : null; 1221 mPreVerifiedDomains = preVerifiedDomains; 1222 1223 if (isDataLoaderInstallation()) { 1224 if (isApexSession()) { 1225 throw new IllegalArgumentException( 1226 "DataLoader installation of APEX modules is not allowed."); 1227 } 1228 1229 if (isSystemDataLoaderInstallation() && mContext.checkCallingOrSelfPermission( 1230 Manifest.permission.USE_SYSTEM_DATA_LOADERS) 1231 != PackageManager.PERMISSION_GRANTED) { 1232 throw new SecurityException("You need the " 1233 + "com.android.permission.USE_SYSTEM_DATA_LOADERS permission " 1234 + "to use system data loaders"); 1235 } 1236 } 1237 1238 if (isIncrementalInstallation() && !IncrementalManager.isAllowed()) { 1239 throw new IllegalArgumentException("Incremental installation not allowed."); 1240 } 1241 1242 if (isArchivedInstallation()) { 1243 if (params.mode != SessionParams.MODE_FULL_INSTALL) { 1244 throw new IllegalArgumentException( 1245 "Archived installation can only be full install."); 1246 } 1247 if (!isStreamingInstallation() || !isSystemDataLoaderInstallation()) { 1248 throw new IllegalArgumentException( 1249 "Archived installation can only use Streaming System DataLoader."); 1250 } 1251 } 1252 } 1253 createHistoricalSession()1254 PackageInstallerHistoricalSession createHistoricalSession() { 1255 final float progress; 1256 final float clientProgress; 1257 synchronized (mProgressLock) { 1258 progress = mProgress; 1259 clientProgress = mClientProgress; 1260 } 1261 synchronized (mLock) { 1262 return new PackageInstallerHistoricalSession(sessionId, userId, mOriginalInstallerUid, 1263 mOriginalInstallerPackageName, mInstallSource, mInstallerUid, createdMillis, 1264 updatedMillis, committedMillis, stageDir, stageCid, clientProgress, progress, 1265 isCommitted(), isPreapprovalRequested(), mSealed, mPermissionsManuallyAccepted, 1266 mStageDirInUse, mDestroyed, mFds.size(), mBridges.size(), mFinalStatus, 1267 mFinalMessage, params, mParentSessionId, getChildSessionIdsLocked(), 1268 mSessionApplied, mSessionFailed, mSessionReady, mSessionErrorCode, 1269 mSessionErrorMessage, mPreapprovalDetails, mPreVerifiedDomains, mPackageName); 1270 } 1271 } 1272 1273 /** 1274 * Returns {@code true} if the {@link SessionInfo} object should be produced with potentially 1275 * sensitive data scrubbed from its fields. 1276 * 1277 * @param callingUid the uid of the caller; the recipient of the {@link SessionInfo} that may 1278 * need to be scrubbed 1279 */ shouldScrubData(int callingUid)1280 private boolean shouldScrubData(int callingUid) { 1281 return !(callingUid < Process.FIRST_APPLICATION_UID || getInstallerUid() == callingUid); 1282 } 1283 1284 /** 1285 * Generates a {@link SessionInfo} object for the provided uid. This may result in some fields 1286 * that may contain sensitive info being filtered. 1287 * 1288 * @param includeIcon true if the icon should be included in the object 1289 * @param callingUid the uid of the caller; the recipient of the {@link SessionInfo} that may 1290 * need to be scrubbed 1291 * @see #shouldScrubData(int) 1292 */ generateInfoForCaller(boolean includeIcon, int callingUid)1293 public SessionInfo generateInfoForCaller(boolean includeIcon, int callingUid) { 1294 return generateInfoInternal(includeIcon, shouldScrubData(callingUid)); 1295 } 1296 1297 /** 1298 * Generates a {@link SessionInfo} object to ensure proper hiding of sensitive fields. 1299 * 1300 * @param includeIcon true if the icon should be included in the object 1301 * @see #generateInfoForCaller(boolean, int) 1302 */ generateInfoScrubbed(boolean includeIcon)1303 public SessionInfo generateInfoScrubbed(boolean includeIcon) { 1304 return generateInfoInternal(includeIcon, true /*scrubData*/); 1305 } 1306 generateInfoInternal(boolean includeIcon, boolean scrubData)1307 private SessionInfo generateInfoInternal(boolean includeIcon, boolean scrubData) { 1308 final SessionInfo info = new SessionInfo(); 1309 final float progress; 1310 synchronized (mProgressLock) { 1311 progress = mProgress; 1312 } 1313 synchronized (mLock) { 1314 info.sessionId = sessionId; 1315 info.userId = userId; 1316 info.installerPackageName = mInstallSource.mInstallerPackageName; 1317 info.installerAttributionTag = mInstallSource.mInstallerAttributionTag; 1318 info.resolvedBaseCodePath = null; 1319 if (mContext.checkCallingOrSelfPermission( 1320 Manifest.permission.READ_INSTALLED_SESSION_PATHS) 1321 == PackageManager.PERMISSION_GRANTED) { 1322 File file = mResolvedBaseFile; 1323 if (file == null) { 1324 // Try to guess mResolvedBaseFile file. 1325 final List<File> addedFiles = getAddedApksLocked(); 1326 if (addedFiles.size() > 0) { 1327 file = addedFiles.get(0); 1328 } 1329 } 1330 if (file != null) { 1331 info.resolvedBaseCodePath = file.getAbsolutePath(); 1332 } 1333 } 1334 info.progress = progress; 1335 info.sealed = mSealed; 1336 info.isCommitted = isCommitted(); 1337 info.isPreapprovalRequested = isPreapprovalRequested(); 1338 info.active = mActiveCount.get() > 0; 1339 1340 info.mode = params.mode; 1341 info.installReason = params.installReason; 1342 info.installScenario = params.installScenario; 1343 info.sizeBytes = params.sizeBytes; 1344 info.appPackageName = mPreapprovalDetails != null ? mPreapprovalDetails.getPackageName() 1345 : mPackageName != null ? mPackageName : params.appPackageName; 1346 if (includeIcon) { 1347 info.appIcon = mPreapprovalDetails != null && mPreapprovalDetails.getIcon() != null 1348 ? mPreapprovalDetails.getIcon() : params.appIcon; 1349 } 1350 info.appLabel = 1351 mPreapprovalDetails != null ? mPreapprovalDetails.getLabel() : params.appLabel; 1352 1353 info.installLocation = params.installLocation; 1354 if (!scrubData) { 1355 info.originatingUri = params.originatingUri; 1356 } 1357 info.originatingUid = params.originatingUid; 1358 if (!scrubData) { 1359 info.referrerUri = params.referrerUri; 1360 } 1361 info.grantedRuntimePermissions = params.getLegacyGrantedRuntimePermissions(); 1362 info.whitelistedRestrictedPermissions = params.whitelistedRestrictedPermissions; 1363 info.autoRevokePermissionsMode = params.autoRevokePermissionsMode; 1364 info.installFlags = params.installFlags; 1365 info.rollbackLifetimeMillis = params.rollbackLifetimeMillis; 1366 info.rollbackImpactLevel = params.rollbackImpactLevel; 1367 info.isMultiPackage = params.isMultiPackage; 1368 info.isStaged = params.isStaged; 1369 info.rollbackDataPolicy = params.rollbackDataPolicy; 1370 info.parentSessionId = mParentSessionId; 1371 info.childSessionIds = getChildSessionIdsLocked(); 1372 info.isSessionApplied = mSessionApplied; 1373 info.isSessionReady = mSessionReady; 1374 info.isSessionFailed = mSessionFailed; 1375 info.setSessionErrorCode(mSessionErrorCode, mSessionErrorMessage); 1376 info.createdMillis = createdMillis; 1377 info.updatedMillis = updatedMillis; 1378 info.requireUserAction = params.requireUserAction; 1379 info.installerUid = mInstallerUid; 1380 info.packageSource = params.packageSource; 1381 info.applicationEnabledSettingPersistent = params.applicationEnabledSettingPersistent; 1382 info.pendingUserActionReason = userActionRequirementToReason(mUserActionRequirement); 1383 } 1384 return info; 1385 } 1386 isPrepared()1387 public boolean isPrepared() { 1388 synchronized (mLock) { 1389 return mPrepared; 1390 } 1391 } 1392 isSealed()1393 public boolean isSealed() { 1394 synchronized (mLock) { 1395 return mSealed; 1396 } 1397 } 1398 1399 /** @hide */ isPreapprovalRequested()1400 boolean isPreapprovalRequested() { 1401 return mPreapprovalRequested.get(); 1402 } 1403 1404 /** {@hide} */ isCommitted()1405 boolean isCommitted() { 1406 return mCommitted.get(); 1407 } 1408 1409 /** {@hide} */ isDestroyed()1410 boolean isDestroyed() { 1411 synchronized (mLock) { 1412 return mDestroyed; 1413 } 1414 } 1415 isInTerminalState()1416 private boolean isInTerminalState() { 1417 synchronized (mLock) { 1418 return mSessionApplied || mSessionFailed; 1419 } 1420 } 1421 1422 /** Returns true if a staged session has reached a final state and can be forgotten about */ isStagedAndInTerminalState()1423 public boolean isStagedAndInTerminalState() { 1424 return params.isStaged && isInTerminalState(); 1425 } 1426 assertNotLocked(String cookie)1427 private void assertNotLocked(String cookie) { 1428 if (Thread.holdsLock(mLock)) { 1429 throw new IllegalStateException(cookie + " is holding mLock"); 1430 } 1431 } 1432 assertSealed(String cookie)1433 private void assertSealed(String cookie) { 1434 if (!isSealed()) { 1435 throw new IllegalStateException(cookie + " before sealing"); 1436 } 1437 } 1438 1439 @GuardedBy("mLock") assertPreparedAndNotPreapprovalRequestedLocked(String cookie)1440 private void assertPreparedAndNotPreapprovalRequestedLocked(String cookie) { 1441 assertPreparedAndNotSealedLocked(cookie); 1442 if (isPreapprovalRequested()) { 1443 throw new IllegalStateException(cookie + " not allowed after requesting"); 1444 } 1445 } 1446 1447 @GuardedBy("mLock") assertPreparedAndNotSealedLocked(String cookie)1448 private void assertPreparedAndNotSealedLocked(String cookie) { 1449 assertPreparedAndNotCommittedOrDestroyedLocked(cookie); 1450 if (mSealed) { 1451 throw new SecurityException(cookie + " not allowed after sealing"); 1452 } 1453 } 1454 1455 @GuardedBy("mLock") assertPreparedAndNotCommittedOrDestroyedLocked(String cookie)1456 private void assertPreparedAndNotCommittedOrDestroyedLocked(String cookie) { 1457 assertPreparedAndNotDestroyedLocked(cookie); 1458 if (isCommitted()) { 1459 throw new SecurityException(cookie + " not allowed after commit"); 1460 } 1461 } 1462 1463 @GuardedBy("mLock") assertPreparedAndNotDestroyedLocked(String cookie)1464 private void assertPreparedAndNotDestroyedLocked(String cookie) { 1465 if (!mPrepared) { 1466 throw new IllegalStateException(cookie + " before prepared"); 1467 } 1468 if (mDestroyed) { 1469 throw new SecurityException(cookie + " not allowed after destruction"); 1470 } 1471 } 1472 1473 @GuardedBy("mProgressLock") setClientProgressLocked(float progress)1474 private void setClientProgressLocked(float progress) { 1475 // Always publish first staging movement 1476 final boolean forcePublish = (mClientProgress == 0); 1477 mClientProgress = progress; 1478 computeProgressLocked(forcePublish); 1479 } 1480 1481 @Override setClientProgress(float progress)1482 public void setClientProgress(float progress) { 1483 assertCallerIsOwnerOrRoot(); 1484 synchronized (mProgressLock) { 1485 setClientProgressLocked(progress); 1486 } 1487 } 1488 1489 @Override addClientProgress(float progress)1490 public void addClientProgress(float progress) { 1491 assertCallerIsOwnerOrRoot(); 1492 synchronized (mProgressLock) { 1493 setClientProgressLocked(mClientProgress + progress); 1494 } 1495 } 1496 1497 @GuardedBy("mProgressLock") computeProgressLocked(boolean forcePublish)1498 private void computeProgressLocked(boolean forcePublish) { 1499 if (!isIncrementalInstallation() || !isCommitted()) { 1500 mProgress = MathUtils.constrain(mClientProgress * 0.8f, 0f, 0.8f) 1501 + MathUtils.constrain(mInternalProgress * 0.2f, 0f, 0.2f); 1502 } else { 1503 // For incremental, publish regular install progress before the session is committed, 1504 // but publish incremental progress afterwards. 1505 if (mIncrementalProgress - mProgress >= 0.01) { 1506 // It takes some time for data loader to write to incremental file system, so at the 1507 // beginning of the commit, the incremental progress might be very small. 1508 // Wait till the incremental progress is larger than what's already displayed. 1509 // This way we don't see the progress ring going backwards. 1510 mProgress = mIncrementalProgress; 1511 } 1512 } 1513 1514 // Only publish meaningful progress changes. 1515 if (forcePublish || (mProgress - mReportedProgress) >= 0.01) { 1516 mReportedProgress = mProgress; 1517 mCallback.onSessionProgressChanged(this, mProgress); 1518 } 1519 } 1520 1521 @Override getNames()1522 public String[] getNames() { 1523 assertCallerIsOwnerRootOrVerifier(); 1524 synchronized (mLock) { 1525 assertPreparedAndNotDestroyedLocked("getNames"); 1526 String[] names; 1527 if (!isCommitted()) { 1528 names = getNamesLocked(); 1529 } else { 1530 names = getStageDirContentsLocked(); 1531 } 1532 return ArrayUtils.removeString(names, APP_METADATA_FILE_NAME); 1533 } 1534 } 1535 1536 @GuardedBy("mLock") getStageDirContentsLocked()1537 private String[] getStageDirContentsLocked() { 1538 if (stageDir == null) { 1539 return EmptyArray.STRING; 1540 } 1541 String[] result = stageDir.list(); 1542 if (result == null) { 1543 return EmptyArray.STRING; 1544 } 1545 return result; 1546 } 1547 1548 @GuardedBy("mLock") getNamesLocked()1549 private String[] getNamesLocked() { 1550 if (!isDataLoaderInstallation()) { 1551 return getStageDirContentsLocked(); 1552 } 1553 1554 InstallationFile[] files = getInstallationFilesLocked(); 1555 String[] result = new String[files.length]; 1556 for (int i = 0, size = files.length; i < size; ++i) { 1557 result[i] = files[i].getName(); 1558 } 1559 return result; 1560 } 1561 1562 @GuardedBy("mLock") getInstallationFilesLocked()1563 private InstallationFile[] getInstallationFilesLocked() { 1564 final InstallationFile[] result = new InstallationFile[mFiles.size()]; 1565 for (FileEntry fileEntry : mFiles) { 1566 result[fileEntry.getIndex()] = fileEntry.getFile(); 1567 } 1568 return result; 1569 } 1570 filterFiles(File parent, String[] names, FileFilter filter)1571 private static ArrayList<File> filterFiles(File parent, String[] names, FileFilter filter) { 1572 ArrayList<File> result = new ArrayList<>(names.length); 1573 for (String name : names) { 1574 File file = new File(parent, name); 1575 if (filter.accept(file)) { 1576 result.add(file); 1577 } 1578 } 1579 return result; 1580 } 1581 1582 @GuardedBy("mLock") getAddedApksLocked()1583 private List<File> getAddedApksLocked() { 1584 String[] names = getNamesLocked(); 1585 return filterFiles(stageDir, names, sAddedApkFilter); 1586 } 1587 1588 @GuardedBy("mLock") enableFsVerityToAddedApksWithIdsig()1589 private void enableFsVerityToAddedApksWithIdsig() throws PackageManagerException { 1590 try { 1591 List<File> files = getAddedApksLocked(); 1592 for (var file : files) { 1593 if (new File(file.getPath() + V4Signature.EXT).exists()) { 1594 VerityUtils.setUpFsverity(file.getPath()); 1595 } 1596 } 1597 } catch (IOException e) { 1598 throw new PrepareFailure(PackageManager.INSTALL_FAILED_BAD_SIGNATURE, 1599 "Failed to enable fs-verity to verify with idsig: " + e); 1600 } 1601 } 1602 1603 @GuardedBy("mLock") getAddedApkLitesLocked()1604 private List<ApkLite> getAddedApkLitesLocked() throws PackageManagerException { 1605 if (!isArchivedInstallation()) { 1606 List<File> files = getAddedApksLocked(); 1607 final List<ApkLite> result = new ArrayList<>(files.size()); 1608 1609 final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); 1610 for (int i = 0, size = files.size(); i < size; ++i) { 1611 final ParseResult<ApkLite> parseResult = ApkLiteParseUtils.parseApkLite( 1612 input.reset(), files.get(i), 1613 ParsingPackageUtils.PARSE_COLLECT_CERTIFICATES); 1614 if (parseResult.isError()) { 1615 throw new PackageManagerException(parseResult.getErrorCode(), 1616 parseResult.getErrorMessage(), parseResult.getException()); 1617 } 1618 result.add(parseResult.getResult()); 1619 } 1620 1621 return result; 1622 } 1623 1624 InstallationFile[] files = getInstallationFilesLocked(); 1625 final List<ApkLite> result = new ArrayList<>(files.length); 1626 1627 for (int i = 0, size = files.length; i < size; ++i) { 1628 File file = new File(stageDir, files[i].getName()); 1629 if (!sAddedApkFilter.accept(file)) { 1630 continue; 1631 } 1632 1633 final Metadata metadata; 1634 try { 1635 metadata = Metadata.fromByteArray(files[i].getMetadata()); 1636 } catch (IOException e) { 1637 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, 1638 "Failed to ", e); 1639 } 1640 if (metadata.getMode() != Metadata.ARCHIVED) { 1641 throw new PackageManagerException(INSTALL_FAILED_VERIFICATION_FAILURE, 1642 "File metadata is not for ARCHIVED package: " + file); 1643 } 1644 1645 var archPkg = metadata.getArchivedPackage(); 1646 if (archPkg == null) { 1647 throw new PackageManagerException(INSTALL_FAILED_VERIFICATION_FAILURE, 1648 "Metadata does not contain ArchivedPackage: " + file); 1649 } 1650 if (archPkg.packageName == null || archPkg.signingDetails == null) { 1651 throw new PackageManagerException(INSTALL_FAILED_VERIFICATION_FAILURE, 1652 "ArchivedPackage does not contain required info: " + file); 1653 } 1654 result.add(new ApkLite(file.getAbsolutePath(), archPkg)); 1655 } 1656 return result; 1657 } 1658 1659 @GuardedBy("mLock") getRemovedFilesLocked()1660 private List<File> getRemovedFilesLocked() { 1661 String[] names = getNamesLocked(); 1662 return filterFiles(stageDir, names, sRemovedFilter); 1663 } 1664 1665 @Override setChecksums(String name, @NonNull Checksum[] checksums, @Nullable byte[] signature)1666 public void setChecksums(String name, @NonNull Checksum[] checksums, 1667 @Nullable byte[] signature) { 1668 if (checksums.length == 0) { 1669 return; 1670 } 1671 1672 final String initiatingPackageName = getInstallSource().mInitiatingPackageName; 1673 final String installerPackageName; 1674 if (!isInstalledByAdb(initiatingPackageName)) { 1675 installerPackageName = initiatingPackageName; 1676 } else { 1677 installerPackageName = getInstallSource().mInstallerPackageName; 1678 } 1679 if (TextUtils.isEmpty(installerPackageName)) { 1680 throw new IllegalStateException("Installer package is empty."); 1681 } 1682 1683 final AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class); 1684 appOps.checkPackage(Binder.getCallingUid(), installerPackageName); 1685 1686 final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class); 1687 final AndroidPackage callingInstaller = pmi.getPackage(installerPackageName); 1688 if (callingInstaller == null) { 1689 throw new IllegalStateException("Can't obtain calling installer's package."); 1690 } 1691 1692 if (signature != null && signature.length != 0) { 1693 try { 1694 Certificate[] ignored = ApkChecksums.verifySignature(checksums, signature); 1695 } catch (IOException | NoSuchAlgorithmException | SignatureException e) { 1696 throw new IllegalArgumentException("Can't verify signature: " + e.getMessage(), e); 1697 } 1698 } 1699 1700 for (Checksum checksum : checksums) { 1701 if (checksum.getValue() == null 1702 || checksum.getValue().length > Checksum.MAX_CHECKSUM_SIZE_BYTES) { 1703 throw new IllegalArgumentException("Invalid checksum."); 1704 } 1705 } 1706 1707 assertCallerIsOwnerOrRoot(); 1708 synchronized (mLock) { 1709 assertPreparedAndNotCommittedOrDestroyedLocked("addChecksums"); 1710 1711 if (mChecksums.containsKey(name)) { 1712 throw new IllegalStateException("Duplicate checksums."); 1713 } 1714 1715 mChecksums.put(name, new PerFileChecksum(checksums, signature)); 1716 } 1717 } 1718 1719 @Override requestChecksums(@onNull String name, @Checksum.TypeMask int optional, @Checksum.TypeMask int required, @Nullable List trustedInstallers, @NonNull IOnChecksumsReadyListener onChecksumsReadyListener)1720 public void requestChecksums(@NonNull String name, @Checksum.TypeMask int optional, 1721 @Checksum.TypeMask int required, @Nullable List trustedInstallers, 1722 @NonNull IOnChecksumsReadyListener onChecksumsReadyListener) { 1723 assertCallerIsOwnerRootOrVerifier(); 1724 final File file = new File(stageDir, name); 1725 final String installerPackageName = PackageManagerServiceUtils.isInstalledByAdb( 1726 getInstallSource().mInitiatingPackageName) 1727 ? getInstallSource().mInstallerPackageName 1728 : getInstallSource().mInitiatingPackageName; 1729 try { 1730 mPm.requestFileChecksums(file, installerPackageName, optional, required, 1731 trustedInstallers, onChecksumsReadyListener); 1732 } catch (FileNotFoundException e) { 1733 throw new ParcelableException(e); 1734 } 1735 } 1736 1737 @Override removeSplit(String splitName)1738 public void removeSplit(String splitName) { 1739 if (isDataLoaderInstallation()) { 1740 throw new IllegalStateException( 1741 "Cannot remove splits in a data loader installation session."); 1742 } 1743 if (TextUtils.isEmpty(params.appPackageName)) { 1744 throw new IllegalStateException("Must specify package name to remove a split"); 1745 } 1746 1747 assertCallerIsOwnerOrRoot(); 1748 synchronized (mLock) { 1749 assertPreparedAndNotCommittedOrDestroyedLocked("removeSplit"); 1750 1751 try { 1752 createRemoveSplitMarkerLocked(splitName); 1753 } catch (IOException e) { 1754 throw ExceptionUtils.wrap(e); 1755 } 1756 } 1757 } 1758 getRemoveMarkerName(String name)1759 private static String getRemoveMarkerName(String name) { 1760 final String markerName = name + REMOVE_MARKER_EXTENSION; 1761 if (!FileUtils.isValidExtFilename(markerName)) { 1762 throw new IllegalArgumentException("Invalid marker: " + markerName); 1763 } 1764 return markerName; 1765 } 1766 1767 @GuardedBy("mLock") createRemoveSplitMarkerLocked(String splitName)1768 private void createRemoveSplitMarkerLocked(String splitName) throws IOException { 1769 try { 1770 final File target = new File(stageDir, getRemoveMarkerName(splitName)); 1771 target.createNewFile(); 1772 Os.chmod(target.getAbsolutePath(), 0 /*mode*/); 1773 } catch (ErrnoException e) { 1774 throw e.rethrowAsIOException(); 1775 } 1776 } 1777 assertShellOrSystemCalling(String operation)1778 private void assertShellOrSystemCalling(String operation) { 1779 switch (Binder.getCallingUid()) { 1780 case android.os.Process.SHELL_UID: 1781 case android.os.Process.ROOT_UID: 1782 case android.os.Process.SYSTEM_UID: 1783 break; 1784 default: 1785 throw new SecurityException(operation + " only supported from shell or system"); 1786 } 1787 } 1788 assertCanWrite(boolean reverseMode)1789 private void assertCanWrite(boolean reverseMode) { 1790 if (isDataLoaderInstallation()) { 1791 throw new IllegalStateException( 1792 "Cannot write regular files in a data loader installation session."); 1793 } 1794 assertCallerIsOwnerOrRoot(); 1795 synchronized (mLock) { 1796 assertPreparedAndNotSealedLocked("assertCanWrite"); 1797 } 1798 if (reverseMode) { 1799 assertShellOrSystemCalling("Reverse mode"); 1800 } 1801 } 1802 getTmpAppMetadataFile()1803 private File getTmpAppMetadataFile() { 1804 return new File(Environment.getDataAppDirectory(params.volumeUuid), 1805 sessionId + "-" + APP_METADATA_FILE_NAME); 1806 } 1807 getStagedAppMetadataFile()1808 private File getStagedAppMetadataFile() { 1809 return new File(stageDir, APP_METADATA_FILE_NAME); 1810 } 1811 isAppMetadata(String name)1812 private static boolean isAppMetadata(String name) { 1813 return name.endsWith(APP_METADATA_FILE_NAME); 1814 } 1815 isAppMetadata(File file)1816 private static boolean isAppMetadata(File file) { 1817 return isAppMetadata(file.getName()); 1818 } 1819 1820 @Override getAppMetadataFd()1821 public ParcelFileDescriptor getAppMetadataFd() { 1822 assertCallerIsOwnerOrRoot(); 1823 synchronized (mLock) { 1824 assertPreparedAndNotCommittedOrDestroyedLocked("getAppMetadataFd"); 1825 if (!mHasAppMetadataFile) { 1826 return null; 1827 } 1828 try { 1829 return openReadInternalLocked(APP_METADATA_FILE_NAME); 1830 } catch (IOException e) { 1831 throw ExceptionUtils.wrap(e); 1832 } 1833 } 1834 } 1835 1836 @Override removeAppMetadata()1837 public void removeAppMetadata() { 1838 synchronized (mLock) { 1839 if (mHasAppMetadataFile) { 1840 getStagedAppMetadataFile().delete(); 1841 mHasAppMetadataFile = false; 1842 } 1843 } 1844 } 1845 getAppMetadataSizeLimit()1846 static long getAppMetadataSizeLimit() { 1847 final long token = Binder.clearCallingIdentity(); 1848 try { 1849 return DeviceConfig.getLong(NAMESPACE_PACKAGE_MANAGER_SERVICE, 1850 PROPERTY_APP_METADATA_BYTE_SIZE_LIMIT, DEFAULT_APP_METADATA_BYTE_SIZE_LIMIT); 1851 } finally { 1852 Binder.restoreCallingIdentity(token); 1853 } 1854 } 1855 1856 @Override openWriteAppMetadata()1857 public ParcelFileDescriptor openWriteAppMetadata() { 1858 assertCallerIsOwnerOrRoot(); 1859 synchronized (mLock) { 1860 assertPreparedAndNotSealedLocked("openWriteAppMetadata"); 1861 } 1862 try { 1863 ParcelFileDescriptor fd = doWriteInternal(APP_METADATA_FILE_NAME, /* offsetBytes= */ 0, 1864 /* lengthBytes= */ -1, null); 1865 synchronized (mLock) { 1866 mHasAppMetadataFile = true; 1867 } 1868 return fd; 1869 } catch (IOException e) { 1870 throw ExceptionUtils.wrap(e); 1871 } 1872 } 1873 1874 @Override openWrite(String name, long offsetBytes, long lengthBytes)1875 public ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes) { 1876 assertCanWrite(false); 1877 try { 1878 return doWriteInternal(name, offsetBytes, lengthBytes, null); 1879 } catch (IOException e) { 1880 throw ExceptionUtils.wrap(e); 1881 } 1882 } 1883 1884 @Override write(String name, long offsetBytes, long lengthBytes, ParcelFileDescriptor fd)1885 public void write(String name, long offsetBytes, long lengthBytes, 1886 ParcelFileDescriptor fd) { 1887 assertCanWrite(fd != null); 1888 try { 1889 doWriteInternal(name, offsetBytes, lengthBytes, fd); 1890 } catch (IOException e) { 1891 throw ExceptionUtils.wrap(e); 1892 } 1893 } 1894 1895 @Override stageViaHardLink(String path)1896 public void stageViaHardLink(String path) { 1897 final int callingUid = Binder.getCallingUid(); 1898 if (callingUid != Process.SYSTEM_UID) { 1899 throw new SecurityException("link() can only be run by the system"); 1900 } 1901 1902 final File target = new File(path); 1903 final File source = new File(stageDir, target.getName()); 1904 var sourcePath = source.getAbsolutePath(); 1905 try { 1906 try { 1907 Os.link(path, sourcePath); 1908 // Grant READ access for APK to be read successfully 1909 Os.chmod(sourcePath, DEFAULT_FILE_ACCESS_MODE); 1910 } catch (ErrnoException e) { 1911 e.rethrowAsIOException(); 1912 } 1913 if (!SELinux.restorecon(source)) { 1914 throw new IOException("Can't relabel file: " + source); 1915 } 1916 } catch (IOException e) { 1917 try { 1918 Os.unlink(sourcePath); 1919 } catch (Exception ignored) { 1920 Slog.d(TAG, "Failed to unlink session file: " + sourcePath); 1921 } 1922 1923 throw ExceptionUtils.wrap(e); 1924 } 1925 } 1926 openTargetInternal(String path, int flags, int mode)1927 private ParcelFileDescriptor openTargetInternal(String path, int flags, int mode) 1928 throws IOException, ErrnoException { 1929 // TODO: this should delegate to DCS so the system process avoids 1930 // holding open FDs into containers. 1931 final FileDescriptor fd = Os.open(path, flags, mode); 1932 return new ParcelFileDescriptor(fd); 1933 } 1934 createRevocableFdInternal(RevocableFileDescriptor fd, ParcelFileDescriptor pfd)1935 private ParcelFileDescriptor createRevocableFdInternal(RevocableFileDescriptor fd, 1936 ParcelFileDescriptor pfd) throws IOException { 1937 int releasedFdInt = pfd.detachFd(); 1938 FileDescriptor releasedFd = new FileDescriptor(); 1939 releasedFd.setInt$(releasedFdInt); 1940 fd.init(mContext, releasedFd); 1941 return fd.getRevocableFileDescriptor(); 1942 } 1943 doWriteInternal(String name, long offsetBytes, long lengthBytes, ParcelFileDescriptor incomingFd)1944 private ParcelFileDescriptor doWriteInternal(String name, long offsetBytes, long lengthBytes, 1945 ParcelFileDescriptor incomingFd) throws IOException { 1946 // Quick validity check of state, and allocate a pipe for ourselves. We 1947 // then do heavy disk allocation outside the lock, but this open pipe 1948 // will block any attempted install transitions. 1949 final RevocableFileDescriptor fd; 1950 final FileBridge bridge; 1951 synchronized (mLock) { 1952 if (PackageInstaller.ENABLE_REVOCABLE_FD) { 1953 fd = new RevocableFileDescriptor(); 1954 bridge = null; 1955 mFds.add(fd); 1956 } else { 1957 fd = null; 1958 bridge = new FileBridge(); 1959 mBridges.add(bridge); 1960 } 1961 } 1962 1963 try { 1964 // Use installer provided name for now; we always rename later 1965 if (!FileUtils.isValidExtFilename(name)) { 1966 throw new IllegalArgumentException("Invalid name: " + name); 1967 } 1968 final File target; 1969 final long identity = Binder.clearCallingIdentity(); 1970 try { 1971 target = new File(stageDir, name); 1972 } finally { 1973 Binder.restoreCallingIdentity(identity); 1974 } 1975 1976 // If file is app metadata then set permission to 0640 to deny user read access since it 1977 // might contain sensitive information. 1978 int mode = name.equals(APP_METADATA_FILE_NAME) 1979 ? APP_METADATA_FILE_ACCESS_MODE : DEFAULT_FILE_ACCESS_MODE; 1980 ParcelFileDescriptor targetPfd = openTargetInternal(target.getAbsolutePath(), 1981 O_CREAT | O_WRONLY, mode); 1982 Os.chmod(target.getAbsolutePath(), mode); 1983 1984 // If caller specified a total length, allocate it for them. Free up 1985 // cache space to grow, if needed. 1986 if (stageDir != null && lengthBytes > 0) { 1987 mContext.getSystemService(StorageManager.class).allocateBytes( 1988 targetPfd.getFileDescriptor(), lengthBytes, 1989 InstallLocationUtils.translateAllocateFlags(params.installFlags)); 1990 } 1991 1992 if (offsetBytes > 0) { 1993 Os.lseek(targetPfd.getFileDescriptor(), offsetBytes, OsConstants.SEEK_SET); 1994 } 1995 1996 if (incomingFd != null) { 1997 // In "reverse" mode, we're streaming data ourselves from the 1998 // incoming FD, which means we never have to hand out our 1999 // sensitive internal FD. We still rely on a "bridge" being 2000 // inserted above to hold the session active. 2001 try { 2002 final Int64Ref last = new Int64Ref(0); 2003 FileUtils.copy(incomingFd.getFileDescriptor(), targetPfd.getFileDescriptor(), 2004 lengthBytes, null, Runnable::run, 2005 (long progress) -> { 2006 if (params.sizeBytes > 0) { 2007 final long delta = progress - last.value; 2008 last.value = progress; 2009 synchronized (mProgressLock) { 2010 setClientProgressLocked(mClientProgress 2011 + (float) delta / (float) params.sizeBytes); 2012 } 2013 } 2014 }); 2015 } finally { 2016 IoUtils.closeQuietly(targetPfd); 2017 IoUtils.closeQuietly(incomingFd); 2018 2019 // We're done here, so remove the "bridge" that was holding 2020 // the session active. 2021 synchronized (mLock) { 2022 if (PackageInstaller.ENABLE_REVOCABLE_FD) { 2023 mFds.remove(fd); 2024 } else { 2025 bridge.forceClose(); 2026 mBridges.remove(bridge); 2027 } 2028 } 2029 } 2030 return null; 2031 } else if (PackageInstaller.ENABLE_REVOCABLE_FD) { 2032 return createRevocableFdInternal(fd, targetPfd); 2033 } else { 2034 bridge.setTargetFile(targetPfd); 2035 bridge.start(); 2036 return bridge.getClientSocket(); 2037 } 2038 2039 } catch (ErrnoException e) { 2040 throw e.rethrowAsIOException(); 2041 } 2042 } 2043 2044 @Override openRead(String name)2045 public ParcelFileDescriptor openRead(String name) { 2046 if (isDataLoaderInstallation()) { 2047 throw new IllegalStateException( 2048 "Cannot read regular files in a data loader installation session."); 2049 } 2050 assertCallerIsOwnerOrRoot(); 2051 synchronized (mLock) { 2052 assertPreparedAndNotCommittedOrDestroyedLocked("openRead"); 2053 try { 2054 return openReadInternalLocked(name); 2055 } catch (IOException e) { 2056 throw ExceptionUtils.wrap(e); 2057 } 2058 } 2059 } 2060 2061 @GuardedBy("mLock") openReadInternalLocked(String name)2062 private ParcelFileDescriptor openReadInternalLocked(String name) throws IOException { 2063 try { 2064 if (!FileUtils.isValidExtFilename(name)) { 2065 throw new IllegalArgumentException("Invalid name: " + name); 2066 } 2067 final File target = new File(stageDir, name); 2068 final FileDescriptor targetFd = Os.open(target.getAbsolutePath(), O_RDONLY, 0); 2069 return new ParcelFileDescriptor(targetFd); 2070 } catch (ErrnoException e) { 2071 throw e.rethrowAsIOException(); 2072 } 2073 } 2074 2075 /** 2076 * Check if the caller is the owner of this session or a verifier. 2077 * Otherwise throw a {@link SecurityException}. 2078 */ assertCallerIsOwnerRootOrVerifier()2079 private void assertCallerIsOwnerRootOrVerifier() { 2080 final int callingUid = Binder.getCallingUid(); 2081 if (callingUid == Process.ROOT_UID || callingUid == mInstallerUid) { 2082 return; 2083 } 2084 if (isSealed() && mContext.checkCallingOrSelfPermission( 2085 android.Manifest.permission.PACKAGE_VERIFICATION_AGENT) 2086 == PackageManager.PERMISSION_GRANTED) { 2087 return; 2088 } 2089 throw new SecurityException("Session does not belong to uid " + callingUid); 2090 } 2091 2092 /** 2093 * Check if the caller is the owner of this session. Otherwise throw a 2094 * {@link SecurityException}. 2095 */ assertCallerIsOwnerOrRoot()2096 private void assertCallerIsOwnerOrRoot() { 2097 final int callingUid = Binder.getCallingUid(); 2098 if (callingUid != Process.ROOT_UID && callingUid != mInstallerUid) { 2099 throw new SecurityException("Session does not belong to uid " + callingUid); 2100 } 2101 } 2102 2103 /** 2104 * Check if the caller is the owner of this session. Otherwise throw a 2105 * {@link SecurityException}. 2106 */ assertCallerIsOwnerOrRootOrSystem()2107 private void assertCallerIsOwnerOrRootOrSystem() { 2108 final int callingUid = Binder.getCallingUid(); 2109 if (callingUid != Process.ROOT_UID && callingUid != mInstallerUid 2110 && callingUid != Process.SYSTEM_UID) { 2111 throw new SecurityException("Session does not belong to uid " + callingUid); 2112 } 2113 } 2114 2115 /** 2116 * If anybody is reading or writing data of the session, throw an {@link SecurityException}. 2117 */ 2118 @GuardedBy("mLock") assertNoWriteFileTransfersOpenLocked()2119 private void assertNoWriteFileTransfersOpenLocked() { 2120 // Verify that all writers are hands-off 2121 for (RevocableFileDescriptor fd : mFds) { 2122 if (!fd.isRevoked()) { 2123 throw new SecurityException("Files still open"); 2124 } 2125 } 2126 for (FileBridge bridge : mBridges) { 2127 if (!bridge.isClosed()) { 2128 throw new SecurityException("Files still open"); 2129 } 2130 } 2131 } 2132 2133 @Override commit(@onNull IntentSender statusReceiver, boolean forTransfer)2134 public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) { 2135 assertNotChild("commit"); 2136 boolean throwsExceptionCommitImmutableCheck = CompatChanges.isChangeEnabled( 2137 THROW_EXCEPTION_COMMIT_WITH_IMMUTABLE_PENDING_INTENT, Binder.getCallingUid()); 2138 if (throwsExceptionCommitImmutableCheck && statusReceiver.isImmutable()) { 2139 throw new IllegalArgumentException( 2140 "The commit() status receiver should come from a mutable PendingIntent"); 2141 } 2142 2143 if (!markAsSealed(statusReceiver, forTransfer)) { 2144 return; 2145 } 2146 if (isMultiPackage()) { 2147 synchronized (mLock) { 2148 boolean sealFailed = false; 2149 for (int i = mChildSessions.size() - 1; i >= 0; --i) { 2150 // seal all children, regardless if any of them fail; we'll throw/return 2151 // as appropriate once all children have been processed 2152 if (!mChildSessions.valueAt(i).markAsSealed(null, forTransfer)) { 2153 sealFailed = true; 2154 } 2155 } 2156 if (sealFailed) { 2157 return; 2158 } 2159 } 2160 } 2161 2162 synchronized (mLock) { 2163 if (mHasAppMetadataFile) { 2164 File appMetadataFile = getStagedAppMetadataFile(); 2165 long sizeLimit = getAppMetadataSizeLimit(); 2166 if (appMetadataFile.length() > sizeLimit) { 2167 appMetadataFile.delete(); 2168 mHasAppMetadataFile = false; 2169 throw new IllegalArgumentException( 2170 "App metadata size exceeds the maximum allowed limit of " + sizeLimit); 2171 } 2172 if (isIncrementalInstallation()) { 2173 // Incremental requires stageDir to be empty so move the app metadata file to a 2174 // temporary location and move back after commit. 2175 appMetadataFile.renameTo(getTmpAppMetadataFile()); 2176 } 2177 } 2178 } 2179 2180 dispatchSessionSealed(); 2181 } 2182 2183 @Override seal()2184 public void seal() { 2185 assertNotChild("seal"); 2186 assertCallerIsOwnerOrRoot(); 2187 try { 2188 sealInternal(); 2189 for (var child : getChildSessions()) { 2190 child.sealInternal(); 2191 } 2192 } catch (PackageManagerException e) { 2193 throw new IllegalStateException("Package is not valid", e); 2194 } 2195 } 2196 sealInternal()2197 private void sealInternal() throws PackageManagerException { 2198 synchronized (mLock) { 2199 sealLocked(); 2200 } 2201 } 2202 2203 @Override fetchPackageNames()2204 public List<String> fetchPackageNames() { 2205 assertNotChild("fetchPackageNames"); 2206 assertCallerIsOwnerOrRoot(); 2207 var sessions = getSelfOrChildSessions(); 2208 var result = new ArrayList<String>(sessions.size()); 2209 for (var s : sessions) { 2210 result.add(s.fetchPackageName()); 2211 } 2212 return result; 2213 } 2214 fetchPackageName()2215 private String fetchPackageName() { 2216 assertSealed("fetchPackageName"); 2217 synchronized (mLock) { 2218 final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); 2219 final List<File> addedFiles = getAddedApksLocked(); 2220 for (File addedFile : addedFiles) { 2221 final ParseResult<ApkLite> result = 2222 ApkLiteParseUtils.parseApkLite(input.reset(), addedFile, 0); 2223 if (result.isError()) { 2224 throw new IllegalStateException( 2225 "Can't parse package for session=" + sessionId, result.getException()); 2226 } 2227 final ApkLite apk = result.getResult(); 2228 var packageName = apk.getPackageName(); 2229 if (packageName != null) { 2230 return packageName; 2231 } 2232 } 2233 throw new IllegalStateException("Can't fetch package name for session=" + sessionId); 2234 } 2235 } 2236 2237 /** 2238 * Kicks off the install flow. The first step is to persist 'sealed' flags 2239 * to prevent mutations of hard links created later. 2240 */ dispatchSessionSealed()2241 private void dispatchSessionSealed() { 2242 mHandler.obtainMessage(MSG_ON_SESSION_SEALED).sendToTarget(); 2243 } 2244 handleSessionSealed()2245 private void handleSessionSealed() { 2246 assertSealed("dispatchSessionSealed"); 2247 // Persist the fact that we've sealed ourselves to prevent 2248 // mutations of any hard links we create. 2249 mCallback.onSessionSealedBlocking(this); 2250 dispatchStreamValidateAndCommit(); 2251 } 2252 dispatchStreamValidateAndCommit()2253 private void dispatchStreamValidateAndCommit() { 2254 mHandler.obtainMessage(MSG_STREAM_VALIDATE_AND_COMMIT).sendToTarget(); 2255 } 2256 2257 @WorkerThread handleStreamValidateAndCommit()2258 private void handleStreamValidateAndCommit() { 2259 try { 2260 // This will track whether the session and any children were validated and are ready to 2261 // progress to the next phase of install 2262 boolean allSessionsReady = true; 2263 for (PackageInstallerSession child : getChildSessions()) { 2264 allSessionsReady &= child.streamValidateAndCommit(); 2265 } 2266 if (allSessionsReady && streamValidateAndCommit()) { 2267 mHandler.obtainMessage(MSG_INSTALL).sendToTarget(); 2268 } 2269 } catch (PackageManagerException e) { 2270 String msg = ExceptionUtils.getCompleteMessage(e); 2271 destroy(msg); 2272 dispatchSessionFinished(e.error, msg, null); 2273 maybeFinishChildSessions(e.error, msg); 2274 } 2275 } 2276 2277 @WorkerThread handlePreapprovalRequest()2278 private void handlePreapprovalRequest() { 2279 /** 2280 * Stops the process if the session needs user action. When the user answers the yes, 2281 * {@link #setPermissionsResult(boolean)} is called and then 2282 * {@link #MSG_PRE_APPROVAL_REQUEST} is handled to come back here to check again. 2283 */ 2284 if (sendPendingUserActionIntentIfNeeded(/* forPreapproval= */true)) { 2285 return; 2286 } 2287 2288 dispatchSessionPreapproved(); 2289 } 2290 2291 private final class FileSystemConnector extends 2292 IPackageInstallerSessionFileSystemConnector.Stub { 2293 final Set<String> mAddedFiles = new ArraySet<>(); 2294 FileSystemConnector(List<InstallationFileParcel> addedFiles)2295 FileSystemConnector(List<InstallationFileParcel> addedFiles) { 2296 for (InstallationFileParcel file : addedFiles) { 2297 mAddedFiles.add(file.name); 2298 } 2299 } 2300 2301 @Override writeData(String name, long offsetBytes, long lengthBytes, ParcelFileDescriptor incomingFd)2302 public void writeData(String name, long offsetBytes, long lengthBytes, 2303 ParcelFileDescriptor incomingFd) { 2304 if (incomingFd == null) { 2305 throw new IllegalArgumentException("incomingFd can't be null"); 2306 } 2307 if (!mAddedFiles.contains(name)) { 2308 throw new SecurityException("File name is not in the list of added files."); 2309 } 2310 try { 2311 doWriteInternal(name, offsetBytes, lengthBytes, incomingFd); 2312 } catch (IOException e) { 2313 throw ExceptionUtils.wrap(e); 2314 } 2315 } 2316 } 2317 2318 /** 2319 * Returns whether or not a package can be installed while Secure FRP is enabled. 2320 * <p> 2321 * Only callers with the INSTALL_PACKAGES permission are allowed to install. However, 2322 * prevent the package installer from installing anything because, while it has the 2323 * permission, it will allows packages to be installed from anywhere. 2324 */ isSecureFrpInstallAllowed(Context context, int callingUid)2325 private static boolean isSecureFrpInstallAllowed(Context context, int callingUid) { 2326 final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class); 2327 final String[] systemInstaller = pmi.getKnownPackageNames( 2328 KnownPackages.PACKAGE_INSTALLER, UserHandle.USER_SYSTEM); 2329 final AndroidPackage callingInstaller = pmi.getPackage(callingUid); 2330 if (callingInstaller != null 2331 && ArrayUtils.contains(systemInstaller, callingInstaller.getPackageName())) { 2332 // don't allow the system package installer to install while under secure FRP 2333 return false; 2334 } 2335 2336 // require caller to hold the INSTALL_PACKAGES permission 2337 return context.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES) 2338 == PackageManager.PERMISSION_GRANTED; 2339 } 2340 isInstallationAllowed(PackageStateInternal psi)2341 private boolean isInstallationAllowed(PackageStateInternal psi) { 2342 if (psi == null || psi.getPkg() == null) { 2343 return true; 2344 } 2345 if (psi.getPkg().isUpdatableSystem()) { 2346 return true; 2347 } 2348 if (mOriginalInstallerUid == Process.ROOT_UID) { 2349 Slog.w(TAG, "Overriding updatableSystem because the installer is root: " 2350 + psi.getPackageName()); 2351 return true; 2352 } 2353 return false; 2354 } 2355 2356 /** 2357 * Check if this package can be installed archived. 2358 */ isArchivedInstallationAllowed(PackageStateInternal psi)2359 private static boolean isArchivedInstallationAllowed(PackageStateInternal psi) { 2360 if (psi == null) { 2361 return true; 2362 } 2363 return false; 2364 } 2365 2366 /** 2367 * Checks if the package can be installed on IncFs. 2368 */ isIncrementalInstallationAllowed(PackageStateInternal psi)2369 private static boolean isIncrementalInstallationAllowed(PackageStateInternal psi) { 2370 if (psi == null || psi.getPkg() == null) { 2371 return true; 2372 } 2373 return !psi.isSystem() && !psi.isUpdatedSystemApp(); 2374 } 2375 2376 /** 2377 * If this was not already called, the session will be sealed. 2378 * 2379 * This method may be called multiple times to update the status receiver validate caller 2380 * permissions. 2381 */ markAsSealed(@ullable IntentSender statusReceiver, boolean forTransfer)2382 private boolean markAsSealed(@Nullable IntentSender statusReceiver, boolean forTransfer) { 2383 Preconditions.checkState(statusReceiver != null || hasParentSessionId(), 2384 "statusReceiver can't be null for the root session"); 2385 assertCallerIsOwnerOrRoot(); 2386 2387 synchronized (mLock) { 2388 assertPreparedAndNotDestroyedLocked("commit of session " + sessionId); 2389 assertNoWriteFileTransfersOpenLocked(); 2390 2391 boolean isSecureFrpEnabled; 2392 if (android.security.Flags.frpEnforcement()) { 2393 PersistentDataBlockManager pdbManager = 2394 mContext.getSystemService(PersistentDataBlockManager.class); 2395 if (pdbManager == null) { 2396 // Some devices may not support FRP. In that case, we can't block the install 2397 // accordingly. 2398 isSecureFrpEnabled = false; 2399 } else { 2400 isSecureFrpEnabled = pdbManager.isFactoryResetProtectionActive(); 2401 } 2402 } else { 2403 isSecureFrpEnabled = Global.getInt(mContext.getContentResolver(), 2404 Global.SECURE_FRP_MODE, 0) == 1; 2405 } 2406 2407 if (isSecureFrpEnabled 2408 && !isSecureFrpInstallAllowed(mContext, Binder.getCallingUid())) { 2409 throw new SecurityException("Can't install packages while in secure FRP"); 2410 } 2411 2412 if (forTransfer) { 2413 mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, null); 2414 if (mInstallerUid == mOriginalInstallerUid) { 2415 throw new IllegalArgumentException("Session has not been transferred"); 2416 } 2417 } else { 2418 if (mInstallerUid != mOriginalInstallerUid) { 2419 throw new IllegalArgumentException("Session has been transferred"); 2420 } 2421 } 2422 2423 setRemoteStatusReceiver(statusReceiver); 2424 2425 // After updating the observer, we can skip re-sealing. 2426 if (mSealed) { 2427 return true; 2428 } 2429 2430 try { 2431 sealLocked(); 2432 } catch (PackageManagerException e) { 2433 return false; 2434 } 2435 } 2436 2437 return true; 2438 } 2439 2440 /** 2441 * Returns true if the session is successfully validated and committed. Returns false if the 2442 * dataloader could not be prepared. This can be called multiple times so long as no 2443 * exception is thrown. 2444 * @throws PackageManagerException on an unrecoverable error. 2445 */ 2446 @WorkerThread streamValidateAndCommit()2447 private boolean streamValidateAndCommit() throws PackageManagerException { 2448 // TODO(patb): since the work done here for a parent session in a multi-package install is 2449 // mostly superficial, consider splitting this method for the parent and 2450 // single / child sessions. 2451 try { 2452 synchronized (mLock) { 2453 if (isCommitted()) { 2454 return true; 2455 } 2456 // Read transfers from the original owner stay open, but as the session's data 2457 // cannot be modified anymore, there is no leak of information. For staged sessions, 2458 // further validation is performed by the staging manager. 2459 if (!params.isMultiPackage) { 2460 if (!prepareDataLoaderLocked()) { 2461 return false; 2462 } 2463 2464 if (isApexSession()) { 2465 validateApexInstallLocked(); 2466 } else { 2467 validateApkInstallLocked(); 2468 } 2469 } 2470 if (mDestroyed) { 2471 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, 2472 "Session destroyed"); 2473 } 2474 if (!isIncrementalInstallation()) { 2475 synchronized (mProgressLock) { 2476 // For non-incremental installs, client staging is fully done at this point 2477 mClientProgress = 1f; 2478 computeProgressLocked(true); 2479 } 2480 } 2481 2482 // This ongoing commit should keep session active, even though client 2483 // will probably close their end. 2484 mActiveCount.incrementAndGet(); 2485 2486 if (!mCommitted.compareAndSet(false /*expect*/, true /*update*/)) { 2487 throw new PackageManagerException( 2488 INSTALL_FAILED_INTERNAL_ERROR, 2489 TextUtils.formatSimple( 2490 "The mCommitted of session %d should be false originally", 2491 sessionId)); 2492 } 2493 committedMillis = System.currentTimeMillis(); 2494 } 2495 return true; 2496 } catch (PackageManagerException e) { 2497 throw e; 2498 } catch (Throwable e) { 2499 // Convert all exceptions into package manager exceptions as only those are handled 2500 // in the code above. 2501 throw new PackageManagerException(e); 2502 } 2503 } 2504 2505 @GuardedBy("mLock") getChildSessionsLocked()2506 private @NonNull List<PackageInstallerSession> getChildSessionsLocked() { 2507 List<PackageInstallerSession> childSessions = Collections.EMPTY_LIST; 2508 if (isMultiPackage()) { 2509 int size = mChildSessions.size(); 2510 childSessions = new ArrayList<>(size); 2511 for (int i = 0; i < size; ++i) { 2512 childSessions.add(mChildSessions.valueAt(i)); 2513 } 2514 } 2515 return childSessions; 2516 } 2517 getChildSessions()2518 @NonNull List<PackageInstallerSession> getChildSessions() { 2519 synchronized (mLock) { 2520 return getChildSessionsLocked(); 2521 } 2522 } 2523 2524 @NonNull getSelfOrChildSessions()2525 private List<PackageInstallerSession> getSelfOrChildSessions() { 2526 return isMultiPackage() ? getChildSessions() : Collections.singletonList(this); 2527 } 2528 2529 /** 2530 * Seal the session to prevent further modification. 2531 * 2532 * <p>The session will be sealed after calling this method even if it failed. 2533 * 2534 * @throws PackageManagerException if the session was sealed but something went wrong. If the 2535 * session was sealed this is the only possible exception. 2536 */ 2537 @GuardedBy("mLock") sealLocked()2538 private void sealLocked() 2539 throws PackageManagerException { 2540 try { 2541 assertNoWriteFileTransfersOpenLocked(); 2542 assertPreparedAndNotDestroyedLocked("sealing of session " + sessionId); 2543 mSealed = true; 2544 } catch (Throwable e) { 2545 // Convert all exceptions into package manager exceptions as only those are handled 2546 // in the code above. 2547 throw onSessionValidationFailure(new PackageManagerException(e)); 2548 } 2549 } 2550 onSessionValidationFailure(PackageManagerException e)2551 private PackageManagerException onSessionValidationFailure(PackageManagerException e) { 2552 onSessionValidationFailure(e.error, ExceptionUtils.getCompleteMessage(e)); 2553 return e; 2554 } 2555 onSessionValidationFailure(int error, String detailMessage)2556 private void onSessionValidationFailure(int error, String detailMessage) { 2557 // Session is sealed but could not be validated, we need to destroy it. 2558 destroyInternal("Failed to validate session, error: " + error + ", " + detailMessage); 2559 // Dispatch message to remove session from PackageInstallerService. 2560 dispatchSessionFinished(error, detailMessage, null); 2561 } 2562 onSessionVerificationFailure(int error, String msg)2563 private void onSessionVerificationFailure(int error, String msg) { 2564 Slog.e(TAG, "Failed to verify session " + sessionId); 2565 // Dispatch message to remove session from PackageInstallerService. 2566 dispatchSessionFinished(error, msg, null); 2567 maybeFinishChildSessions(error, msg); 2568 } 2569 onSystemDataLoaderUnrecoverable()2570 private void onSystemDataLoaderUnrecoverable() { 2571 final String packageName = getPackageName(); 2572 if (TextUtils.isEmpty(packageName)) { 2573 // The package has not been installed. 2574 return; 2575 } 2576 mHandler.post(() -> { 2577 if (mPm.deletePackageX(packageName, 2578 PackageManager.VERSION_CODE_HIGHEST, UserHandle.USER_SYSTEM, 2579 PackageManager.DELETE_ALL_USERS, true /*removedBySystem*/) 2580 != PackageManager.DELETE_SUCCEEDED) { 2581 Slog.e(TAG, "Failed to uninstall package with failed dataloader: " + packageName); 2582 } 2583 }); 2584 } 2585 2586 /** 2587 * If session should be sealed, then it's sealed to prevent further modification. 2588 * If the session can't be sealed then it's destroyed. 2589 * 2590 * Additionally for staged APEX/APK sessions read+validate the package and populate req'd 2591 * fields. 2592 * 2593 * <p> This is meant to be called after all of the sessions are loaded and added to 2594 * PackageInstallerService 2595 * 2596 * @param allSessions All sessions loaded by PackageInstallerService, guaranteed to be 2597 * immutable by the caller during the method call. Used to resolve child 2598 * sessions Ids to actual object reference. 2599 */ 2600 @AnyThread onAfterSessionRead(SparseArray<PackageInstallerSession> allSessions)2601 void onAfterSessionRead(SparseArray<PackageInstallerSession> allSessions) { 2602 synchronized (mLock) { 2603 // Resolve null values to actual object references 2604 for (int i = mChildSessions.size() - 1; i >= 0; --i) { 2605 int childSessionId = mChildSessions.keyAt(i); 2606 PackageInstallerSession childSession = allSessions.get(childSessionId); 2607 if (childSession != null) { 2608 mChildSessions.setValueAt(i, childSession); 2609 } else { 2610 Slog.e(TAG, "Child session not existed: " + childSessionId); 2611 mChildSessions.removeAt(i); 2612 } 2613 } 2614 2615 if (!mShouldBeSealed || isStagedAndInTerminalState()) { 2616 return; 2617 } 2618 try { 2619 sealLocked(); 2620 2621 // Session that are staged, committed and not multi package will be installed or 2622 // restart verification during this boot. As such, we need populate all the fields 2623 // for successful installation. 2624 if (isMultiPackage() || !isStaged() || !isCommitted()) { 2625 return; 2626 } 2627 final PackageInstallerSession root = hasParentSessionId() 2628 ? allSessions.get(getParentSessionId()) 2629 : this; 2630 if (root != null && !root.isStagedAndInTerminalState()) { 2631 if (isApexSession()) { 2632 validateApexInstallLocked(); 2633 } else { 2634 validateApkInstallLocked(); 2635 } 2636 } 2637 } catch (PackageManagerException e) { 2638 Slog.e(TAG, "Package not valid", e); 2639 } 2640 } 2641 } 2642 2643 /** Update the timestamp of when the staged session last changed state */ markUpdated()2644 public void markUpdated() { 2645 synchronized (mLock) { 2646 this.updatedMillis = System.currentTimeMillis(); 2647 } 2648 } 2649 2650 @Override transfer(String packageName)2651 public void transfer(String packageName) { 2652 Preconditions.checkArgument(!TextUtils.isEmpty(packageName)); 2653 final Computer snapshot = mPm.snapshotComputer(); 2654 ApplicationInfo newOwnerAppInfo = snapshot.getApplicationInfo(packageName, 0, userId); 2655 if (newOwnerAppInfo == null) { 2656 throw new ParcelableException(new PackageManager.NameNotFoundException(packageName)); 2657 } 2658 2659 if (PackageManager.PERMISSION_GRANTED != snapshot.checkUidPermission( 2660 Manifest.permission.INSTALL_PACKAGES, newOwnerAppInfo.uid)) { 2661 throw new SecurityException("Destination package " + packageName + " does not have " 2662 + "the " + Manifest.permission.INSTALL_PACKAGES + " permission"); 2663 } 2664 2665 // Only install flags that can be verified by the app the session is transferred to are 2666 // allowed. The parameters can be read via PackageInstaller.SessionInfo. 2667 if (!params.areHiddenOptionsSet()) { 2668 throw new SecurityException("Can only transfer sessions that use public options"); 2669 } 2670 2671 synchronized (mLock) { 2672 assertCallerIsOwnerOrRoot(); 2673 assertPreparedAndNotSealedLocked("transfer"); 2674 2675 try { 2676 sealLocked(); 2677 } catch (PackageManagerException e) { 2678 throw new IllegalStateException("Package is not valid", e); 2679 } 2680 2681 mInstallerUid = newOwnerAppInfo.uid; 2682 mInstallSource = InstallSource.create(packageName, null /* originatingPackageName */, 2683 packageName, mInstallerUid, packageName, null /* installerAttributionTag */, 2684 params.packageSource); 2685 } 2686 } 2687 2688 @WorkerThread checkUserActionRequirement( PackageInstallerSession session, IntentSender target)2689 private static boolean checkUserActionRequirement( 2690 PackageInstallerSession session, IntentSender target) { 2691 if (session.isMultiPackage()) { 2692 return false; 2693 } 2694 2695 @UserActionRequirement int userActionRequirement = USER_ACTION_NOT_NEEDED; 2696 // TODO(b/159331446): Move this to makeSessionActiveForInstall and update javadoc 2697 userActionRequirement = session.computeUserActionRequirement(); 2698 session.updateUserActionRequirement(userActionRequirement); 2699 if (userActionRequirement == USER_ACTION_REQUIRED 2700 || userActionRequirement == USER_ACTION_REQUIRED_UPDATE_OWNER_REMINDER) { 2701 session.sendPendingUserActionIntent(target); 2702 return true; 2703 } 2704 2705 if (!session.isApexSession() && userActionRequirement == USER_ACTION_PENDING_APK_PARSING) { 2706 if (!isTargetSdkConditionSatisfied(session)) { 2707 session.sendPendingUserActionIntent(target); 2708 return true; 2709 } 2710 2711 if (session.params.requireUserAction == SessionParams.USER_ACTION_NOT_REQUIRED) { 2712 if (!session.mSilentUpdatePolicy.isSilentUpdateAllowed( 2713 session.getInstallerPackageName(), session.getPackageName())) { 2714 // Fall back to the non-silent update if a repeated installation is invoked 2715 // within the throttle time. 2716 session.sendPendingUserActionIntent(target); 2717 return true; 2718 } 2719 session.mSilentUpdatePolicy.track(session.getInstallerPackageName(), 2720 session.getPackageName()); 2721 } 2722 } 2723 2724 return false; 2725 } 2726 2727 /** 2728 * Checks if the app being installed has a targetSdk more than the minimum required for a 2729 * silent install. See {@link SessionParams#setRequireUserAction(int)} for details about the 2730 * targetSdk requirement. 2731 * @param session Current install session 2732 * @return true if the targetSdk of the app being installed is more than the minimum required, 2733 * resulting in a silent install, false otherwise. 2734 */ isTargetSdkConditionSatisfied(PackageInstallerSession session)2735 private static boolean isTargetSdkConditionSatisfied(PackageInstallerSession session) { 2736 final int validatedTargetSdk; 2737 final String packageName; 2738 synchronized (session.mLock) { 2739 validatedTargetSdk = session.mValidatedTargetSdk; 2740 packageName = session.mPackageName; 2741 } 2742 2743 ApplicationInfo appInfo = new ApplicationInfo(); 2744 appInfo.packageName = packageName; 2745 appInfo.targetSdkVersion = validatedTargetSdk; 2746 2747 IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface( 2748 ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)); 2749 try { 2750 // Using manually constructed AppInfo to check if a change is enabled may not work 2751 // in the future. 2752 return validatedTargetSdk != INVALID_TARGET_SDK_VERSION 2753 && platformCompat.isChangeEnabled(SILENT_INSTALL_ALLOWED, appInfo); 2754 } catch (RemoteException e) { 2755 Log.e(TAG, "Failed to get a response from PLATFORM_COMPAT_SERVICE", e); 2756 return false; 2757 } 2758 } 2759 userActionRequirementToReason( @serActionRequirement int requirement)2760 private static @UserActionReason int userActionRequirementToReason( 2761 @UserActionRequirement int requirement) { 2762 switch (requirement) { 2763 case USER_ACTION_REQUIRED_UPDATE_OWNER_REMINDER: 2764 return PackageInstaller.REASON_REMIND_OWNERSHIP; 2765 default: 2766 return PackageInstaller.REASON_CONFIRM_PACKAGE_CHANGE; 2767 } 2768 } 2769 2770 /** 2771 * Find out any session needs user action. 2772 * 2773 * @return true if the session set requires user action for the installation, otherwise false. 2774 */ 2775 @WorkerThread sendPendingUserActionIntentIfNeeded(boolean forPreapproval)2776 private boolean sendPendingUserActionIntentIfNeeded(boolean forPreapproval) { 2777 // To support pre-approval request of atomic install, we allow child session to handle 2778 // the result by itself since it has the status receiver. 2779 if (isCommitted()) { 2780 assertNotChild("PackageInstallerSession#sendPendingUserActionIntentIfNeeded"); 2781 } 2782 // Since there are separate status receivers for session preapproval and commit, 2783 // check whether user action is requested for session preapproval or commit 2784 final IntentSender statusReceiver = forPreapproval ? getPreapprovalRemoteStatusReceiver() 2785 : getRemoteStatusReceiver(); 2786 return sessionContains(s -> checkUserActionRequirement(s, statusReceiver)); 2787 } 2788 2789 @WorkerThread handleInstall()2790 private void handleInstall() { 2791 if (isInstallerDeviceOwnerOrAffiliatedProfileOwner()) { 2792 DevicePolicyEventLogger 2793 .createEvent(DevicePolicyEnums.INSTALL_PACKAGE) 2794 .setAdmin(getInstallSource().mInstallerPackageName) 2795 .write(); 2796 } 2797 2798 /** 2799 * Stops the installation of the whole session set if one session needs user action 2800 * in its belong session set. When the user answers the yes, 2801 * {@link #setPermissionsResult(boolean)} is called and then {@link #MSG_INSTALL} is 2802 * handled to come back here to check again. 2803 * 2804 * {@code mUserActionRequired} is used to track when user action is required for an 2805 * install. Since control may come back here more than 1 time, we must ensure that it's 2806 * value is not overwritten. 2807 */ 2808 boolean wasUserActionIntentSent = 2809 sendPendingUserActionIntentIfNeeded(/* forPreapproval= */false); 2810 if (mUserActionRequired == null) { 2811 mUserActionRequired = wasUserActionIntentSent; 2812 } 2813 if (wasUserActionIntentSent) { 2814 // Commit was keeping session marked as active until now; release 2815 // that extra refcount so session appears idle. 2816 deactivate(); 2817 return; 2818 } else if (mUserActionRequired) { 2819 // If user action is required, control comes back here when the user allows 2820 // the installation. At this point, the session is marked active once again, 2821 // since installation is in progress. 2822 activate(); 2823 } 2824 2825 if (mVerificationInProgress) { 2826 Slog.w(TAG, "Verification is already in progress for session " + sessionId); 2827 return; 2828 } 2829 mVerificationInProgress = true; 2830 2831 if (params.isStaged) { 2832 mStagedSession.verifySession(); 2833 } else { 2834 verify(); 2835 } 2836 } 2837 verify()2838 private void verify() { 2839 try { 2840 List<PackageInstallerSession> children = getChildSessions(); 2841 if (isMultiPackage()) { 2842 for (PackageInstallerSession child : children) { 2843 child.prepareInheritedFiles(); 2844 child.parseApkAndExtractNativeLibraries(); 2845 } 2846 } else { 2847 prepareInheritedFiles(); 2848 parseApkAndExtractNativeLibraries(); 2849 } 2850 verifyNonStaged(); 2851 } catch (PackageManagerException e) { 2852 final String completeMsg = ExceptionUtils.getCompleteMessage(e); 2853 final String errorMsg = PackageManager.installStatusToString(e.error, completeMsg); 2854 setSessionFailed(e.error, errorMsg); 2855 onSessionVerificationFailure(e.error, errorMsg); 2856 } 2857 } 2858 getRemoteStatusReceiver()2859 private IntentSender getRemoteStatusReceiver() { 2860 synchronized (mLock) { 2861 return mRemoteStatusReceiver; 2862 } 2863 } 2864 setRemoteStatusReceiver(IntentSender remoteStatusReceiver)2865 private void setRemoteStatusReceiver(IntentSender remoteStatusReceiver) { 2866 synchronized (mLock) { 2867 mRemoteStatusReceiver = remoteStatusReceiver; 2868 } 2869 } 2870 getPreapprovalRemoteStatusReceiver()2871 private IntentSender getPreapprovalRemoteStatusReceiver() { 2872 synchronized (mLock) { 2873 return mPreapprovalRemoteStatusReceiver; 2874 } 2875 } 2876 setPreapprovalRemoteStatusReceiver(IntentSender remoteStatusReceiver)2877 private void setPreapprovalRemoteStatusReceiver(IntentSender remoteStatusReceiver) { 2878 synchronized (mLock) { 2879 mPreapprovalRemoteStatusReceiver = remoteStatusReceiver; 2880 } 2881 } 2882 2883 /** 2884 * Prepares staged directory with any inherited APKs. 2885 */ prepareInheritedFiles()2886 private void prepareInheritedFiles() throws PackageManagerException { 2887 if (isApexSession() || params.mode != SessionParams.MODE_INHERIT_EXISTING) { 2888 return; 2889 } 2890 synchronized (mLock) { 2891 if (mStageDirInUse) { 2892 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, 2893 "Session files in use"); 2894 } 2895 if (mDestroyed) { 2896 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, 2897 "Session destroyed"); 2898 } 2899 if (!mSealed) { 2900 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, 2901 "Session not sealed"); 2902 } 2903 // Inherit any packages and native libraries from existing install that 2904 // haven't been overridden. 2905 try { 2906 final List<File> fromFiles = mResolvedInheritedFiles; 2907 final File toDir = stageDir; 2908 final String tempPackageName = toDir.getName(); 2909 2910 if (LOGD) Slog.d(TAG, "Inherited files: " + mResolvedInheritedFiles); 2911 if (!mResolvedInheritedFiles.isEmpty() && mInheritedFilesBase == null) { 2912 throw new IllegalStateException("mInheritedFilesBase == null"); 2913 } 2914 2915 if (isLinkPossible(fromFiles, toDir)) { 2916 if (!mResolvedInstructionSets.isEmpty()) { 2917 final File oatDir = new File(toDir, "oat"); 2918 createOatDirs(tempPackageName, mResolvedInstructionSets, oatDir); 2919 } 2920 // pre-create lib dirs for linking if necessary 2921 if (!mResolvedNativeLibPaths.isEmpty()) { 2922 for (String libPath : mResolvedNativeLibPaths) { 2923 // "/lib/arm64" -> ["lib", "arm64"] 2924 final int splitIndex = libPath.lastIndexOf('/'); 2925 if (splitIndex < 0 || splitIndex >= libPath.length() - 1) { 2926 Slog.e(TAG, 2927 "Skipping native library creation for linking due" 2928 + " to invalid path: " + libPath); 2929 continue; 2930 } 2931 final String libDirPath = libPath.substring(1, splitIndex); 2932 final File libDir = new File(toDir, libDirPath); 2933 if (!libDir.exists()) { 2934 NativeLibraryHelper.createNativeLibrarySubdir(libDir); 2935 } 2936 final String archDirPath = libPath.substring(splitIndex + 1); 2937 NativeLibraryHelper.createNativeLibrarySubdir( 2938 new File(libDir, archDirPath)); 2939 } 2940 } 2941 linkFiles(tempPackageName, fromFiles, toDir, mInheritedFilesBase); 2942 } else { 2943 // TODO: this should delegate to DCS so the system process 2944 // avoids holding open FDs into containers. 2945 copyFiles(fromFiles, toDir); 2946 } 2947 } catch (IOException e) { 2948 throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE, 2949 "Failed to inherit existing install", e); 2950 } 2951 } 2952 } 2953 2954 @GuardedBy("mLock") markStageDirInUseLocked()2955 private void markStageDirInUseLocked() throws PackageManagerException { 2956 if (mDestroyed) { 2957 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, 2958 "Session destroyed"); 2959 } 2960 // Set this flag to prevent abandon() from deleting staging files when verification or 2961 // installation is about to start. 2962 mStageDirInUse = true; 2963 } 2964 parseApkAndExtractNativeLibraries()2965 private void parseApkAndExtractNativeLibraries() throws PackageManagerException { 2966 synchronized (mLock) { 2967 if (mStageDirInUse) { 2968 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, 2969 "Session files in use"); 2970 } 2971 if (mDestroyed) { 2972 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, 2973 "Session destroyed"); 2974 } 2975 if (!mSealed) { 2976 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, 2977 "Session not sealed"); 2978 } 2979 if (mPackageName == null) { 2980 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, 2981 "Session no package name"); 2982 } 2983 if (mSigningDetails == null) { 2984 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, 2985 "Session no signing data"); 2986 } 2987 if (mResolvedBaseFile == null) { 2988 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, 2989 "Session no resolved base file"); 2990 } 2991 final PackageLite result; 2992 if (!isApexSession()) { 2993 // For mode inherit existing, it would link/copy existing files to stage dir in 2994 // prepareInheritedFiles(). Therefore, we need to parse the complete package in 2995 // stage dir here. 2996 // Besides, PackageLite may be null for staged sessions that don't complete 2997 // pre-reboot verification. 2998 result = getOrParsePackageLiteLocked(stageDir, /* flags */ 0); 2999 } else { 3000 result = getOrParsePackageLiteLocked(mResolvedBaseFile, /* flags */ 0); 3001 } 3002 if (result != null) { 3003 mPackageLite = result; 3004 if (!isApexSession()) { 3005 synchronized (mProgressLock) { 3006 mInternalProgress = 0.5f; 3007 computeProgressLocked(true); 3008 } 3009 extractNativeLibraries( 3010 mPackageLite, stageDir, params.abiOverride, mayInheritNativeLibs()); 3011 } 3012 } 3013 } 3014 } 3015 verifyNonStaged()3016 private void verifyNonStaged() 3017 throws PackageManagerException { 3018 synchronized (mLock) { 3019 markStageDirInUseLocked(); 3020 } 3021 mSessionProvider.getSessionVerifier().verify(this, (error, msg) -> { 3022 mHandler.post(() -> { 3023 if (dispatchPendingAbandonCallback()) { 3024 // No need to continue if abandoned 3025 return; 3026 } 3027 if (error == INSTALL_SUCCEEDED) { 3028 onVerificationComplete(); 3029 } else { 3030 onSessionVerificationFailure(error, msg); 3031 } 3032 }); 3033 }); 3034 } 3035 3036 private static class InstallResult { 3037 public final PackageInstallerSession session; 3038 public final Bundle extras; InstallResult(PackageInstallerSession session, Bundle extras)3039 InstallResult(PackageInstallerSession session, Bundle extras) { 3040 this.session = session; 3041 this.extras = extras; 3042 } 3043 } 3044 3045 /** 3046 * Stages installs and do cleanup accordingly depending on whether the installation is 3047 * successful or not. 3048 * 3049 * @return a future that will be completed when the whole process is completed. 3050 */ install()3051 private CompletableFuture<Void> install() { 3052 // `futures` either contains only one session (`this`) or contains one parent session 3053 // (`this`) and n-1 child sessions. 3054 List<CompletableFuture<InstallResult>> futures = installNonStaged(); 3055 CompletableFuture<InstallResult>[] arr = new CompletableFuture[futures.size()]; 3056 return CompletableFuture.allOf(futures.toArray(arr)).whenComplete((r, t) -> { 3057 if (t == null) { 3058 setSessionApplied(); 3059 var multiPackageWarnings = new ArrayList<String>(); 3060 if (isMultiPackage()) { 3061 // This is a parent session. Collect warnings from children. 3062 for (CompletableFuture<InstallResult> f : futures) { 3063 InstallResult result = f.join(); 3064 if (result.session != this && result.extras != null) { 3065 ArrayList<String> childWarnings = result.extras.getStringArrayList( 3066 PackageInstaller.EXTRA_WARNINGS); 3067 if (!ArrayUtils.isEmpty(childWarnings)) { 3068 multiPackageWarnings.addAll(childWarnings); 3069 } 3070 } 3071 } 3072 } 3073 for (CompletableFuture<InstallResult> f : futures) { 3074 InstallResult result = f.join(); 3075 Bundle extras = result.extras; 3076 if (isMultiPackage() && result.session == this 3077 && !multiPackageWarnings.isEmpty()) { 3078 if (extras == null) { 3079 extras = new Bundle(); 3080 } 3081 extras.putStringArrayList( 3082 PackageInstaller.EXTRA_WARNINGS, multiPackageWarnings); 3083 } 3084 result.session.dispatchSessionFinished( 3085 INSTALL_SUCCEEDED, "Session installed", extras); 3086 } 3087 } else { 3088 PackageManagerException e = (PackageManagerException) t.getCause(); 3089 setSessionFailed(e.error, 3090 PackageManager.installStatusToString(e.error, e.getMessage())); 3091 dispatchSessionFinished(e.error, e.getMessage(), null); 3092 maybeFinishChildSessions(e.error, e.getMessage()); 3093 } 3094 }); 3095 } 3096 3097 /** 3098 * Stages sessions (including child sessions if any) for install. 3099 * 3100 * @return a list of futures to indicate the install results of each session. 3101 */ 3102 private List<CompletableFuture<InstallResult>> installNonStaged() { 3103 try { 3104 List<CompletableFuture<InstallResult>> futures = new ArrayList<>(); 3105 CompletableFuture<InstallResult> future = new CompletableFuture<>(); 3106 futures.add(future); 3107 final InstallingSession installingSession = createInstallingSession(future); 3108 if (isMultiPackage()) { 3109 final List<PackageInstallerSession> childSessions = getChildSessions(); 3110 List<InstallingSession> installingChildSessions = 3111 new ArrayList<>(childSessions.size()); 3112 for (int i = 0; i < childSessions.size(); ++i) { 3113 final PackageInstallerSession session = childSessions.get(i); 3114 future = new CompletableFuture<>(); 3115 futures.add(future); 3116 final InstallingSession installingChildSession = 3117 session.createInstallingSession(future); 3118 if (installingChildSession != null) { 3119 installingChildSessions.add(installingChildSession); 3120 } 3121 } 3122 if (!installingChildSessions.isEmpty()) { 3123 Objects.requireNonNull(installingSession).installStage(installingChildSessions); 3124 } 3125 } else if (installingSession != null) { 3126 installingSession.installStage(); 3127 } 3128 3129 return futures; 3130 } catch (PackageManagerException e) { 3131 List<CompletableFuture<InstallResult>> futures = new ArrayList<>(); 3132 futures.add(CompletableFuture.failedFuture(e)); 3133 return futures; 3134 } 3135 } 3136 3137 private void sendPendingUserActionIntent(IntentSender target) { 3138 // User needs to confirm installation; 3139 // give installer an intent they can use to involve 3140 // user. 3141 final boolean isPreapproval = isPreapprovalRequested() && !isCommitted(); 3142 final Intent intent = new Intent( 3143 isPreapproval ? PackageInstaller.ACTION_CONFIRM_PRE_APPROVAL 3144 : PackageInstaller.ACTION_CONFIRM_INSTALL); 3145 intent.setPackage(mPm.getPackageInstallerPackageName()); 3146 intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId); 3147 sendOnUserActionRequired(mContext, target, sessionId, intent); 3148 } 3149 3150 @WorkerThread 3151 private void onVerificationComplete() { 3152 if (isStaged()) { 3153 mStagingManager.commitSession(mStagedSession); 3154 sendUpdateToRemoteStatusReceiver(INSTALL_SUCCEEDED, "Session staged", 3155 /* extras= */ null, /* forPreapproval= */ false); 3156 return; 3157 } 3158 install(); 3159 } 3160 3161 /** 3162 * Stages this session for install and returns a 3163 * {@link InstallingSession} representing this new staged state. 3164 * 3165 * @param future a future that will be completed when this session is completed. 3166 */ 3167 @Nullable 3168 private InstallingSession createInstallingSession(CompletableFuture<InstallResult> future) 3169 throws PackageManagerException { 3170 synchronized (mLock) { 3171 if (!mSealed) { 3172 throw new PackageManagerException( 3173 INSTALL_FAILED_INTERNAL_ERROR, "Session not sealed"); 3174 } 3175 markStageDirInUseLocked(); 3176 } 3177 3178 if (isMultiPackage()) { 3179 // Always treat parent session as success for it has nothing to install 3180 future.complete(new InstallResult(this, null)); 3181 } else if (isApexSession() && params.isStaged) { 3182 // Staged apex sessions have been handled by apexd 3183 future.complete(new InstallResult(this, null)); 3184 return null; 3185 } 3186 3187 final IPackageInstallObserver2 localObserver = new IPackageInstallObserver2.Stub() { 3188 @Override 3189 public void onUserActionRequired(Intent intent) { 3190 throw new IllegalStateException(); 3191 } 3192 3193 @Override 3194 public void onPackageInstalled(String basePackageName, int returnCode, String msg, 3195 Bundle extras) { 3196 if (returnCode == INSTALL_SUCCEEDED) { 3197 future.complete(new InstallResult(PackageInstallerSession.this, extras)); 3198 } else { 3199 future.completeExceptionally(new PackageManagerException(returnCode, msg)); 3200 } 3201 } 3202 }; 3203 3204 final UserHandle user; 3205 if ((params.installFlags & PackageManager.INSTALL_ALL_USERS) != 0) { 3206 user = UserHandle.ALL; 3207 } else { 3208 user = new UserHandle(userId); 3209 } 3210 3211 if (params.isStaged) { 3212 params.installFlags |= INSTALL_STAGED; 3213 } 3214 3215 if (!isMultiPackage() && !isApexSession()) { 3216 synchronized (mLock) { 3217 // This shouldn't be null, but have this code path just in case. 3218 if (mPackageLite == null) { 3219 Slog.wtf(TAG, "Session: " + sessionId + ". Don't have a valid PackageLite."); 3220 } 3221 mPackageLite = getOrParsePackageLiteLocked(stageDir, /* flags */ 0); 3222 } 3223 } 3224 3225 synchronized (mLock) { 3226 return new InstallingSession(sessionId, stageDir, localObserver, params, mInstallSource, 3227 user, mSigningDetails, mInstallerUid, mPackageLite, mPreVerifiedDomains, mPm, 3228 mHasAppMetadataFile); 3229 } 3230 } 3231 3232 @GuardedBy("mLock") 3233 private PackageLite getOrParsePackageLiteLocked(File packageFile, int flags) 3234 throws PackageManagerException { 3235 if (mPackageLite != null) { 3236 return mPackageLite; 3237 } 3238 3239 final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); 3240 final ParseResult<PackageLite> result = 3241 ApkLiteParseUtils.parsePackageLite(input, packageFile, flags); 3242 if (result.isError()) { 3243 throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, 3244 result.getErrorMessage(), result.getException()); 3245 } 3246 return result.getResult(); 3247 } 3248 3249 private static void maybeRenameFile(File from, File to) throws PackageManagerException { 3250 if (!from.equals(to)) { 3251 if (!from.renameTo(to)) { 3252 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, 3253 "Could not rename file " + from + " to " + to); 3254 } 3255 } 3256 } 3257 3258 private void logDataLoaderInstallationSession(int returnCode) { 3259 // Skip logging the side-loaded app installations, as those are private and aren't reported 3260 // anywhere; app stores already have a record of the installation and that's why reporting 3261 // it here is fine 3262 final String packageName = getPackageName(); 3263 final String packageNameToLog = 3264 (params.installFlags & PackageManager.INSTALL_FROM_ADB) == 0 ? packageName : ""; 3265 final long currentTimestamp = System.currentTimeMillis(); 3266 final int packageUid; 3267 if (returnCode != INSTALL_SUCCEEDED) { 3268 // Package didn't install; no valid uid 3269 packageUid = INVALID_UID; 3270 } else { 3271 packageUid = mPm.snapshotComputer().getPackageUid(packageName, 0, userId); 3272 } 3273 FrameworkStatsLog.write(FrameworkStatsLog.PACKAGE_INSTALLER_V2_REPORTED, 3274 isIncrementalInstallation(), 3275 packageNameToLog, 3276 currentTimestamp - createdMillis, 3277 returnCode, 3278 getApksSize(packageName), 3279 packageUid); 3280 } 3281 3282 private long getApksSize(String packageName) { 3283 final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class); 3284 final PackageStateInternal ps = pmi.getPackageStateInternal(packageName); 3285 if (ps == null) { 3286 return 0; 3287 } 3288 final File apkDirOrPath = ps.getPath(); 3289 if (apkDirOrPath == null) { 3290 return 0; 3291 } 3292 if (apkDirOrPath.isFile() && apkDirOrPath.getName().toLowerCase().endsWith(".apk")) { 3293 return apkDirOrPath.length(); 3294 } 3295 if (!apkDirOrPath.isDirectory()) { 3296 return 0; 3297 } 3298 final File[] files = apkDirOrPath.listFiles(); 3299 long apksSize = 0; 3300 for (int i = 0; i < files.length; i++) { 3301 if (files[i].getName().toLowerCase().endsWith(".apk")) { 3302 apksSize += files[i].length(); 3303 } 3304 } 3305 return apksSize; 3306 } 3307 3308 /** 3309 * Returns true if the session should attempt to inherit any existing native libraries already 3310 * extracted at the current install location. This is necessary to prevent double loading of 3311 * native libraries already loaded by the running app. 3312 */ 3313 private boolean mayInheritNativeLibs() { 3314 return SystemProperties.getBoolean(PROPERTY_NAME_INHERIT_NATIVE, true) && 3315 params.mode == SessionParams.MODE_INHERIT_EXISTING && 3316 (params.installFlags & PackageManager.DONT_KILL_APP) != 0; 3317 } 3318 3319 /** 3320 * Returns true if the session is installing an APEX package. 3321 */ 3322 boolean isApexSession() { 3323 return (params.installFlags & PackageManager.INSTALL_APEX) != 0; 3324 } 3325 3326 boolean sessionContains(Predicate<PackageInstallerSession> filter) { 3327 if (!isMultiPackage()) { 3328 return filter.test(this); 3329 } 3330 final List<PackageInstallerSession> childSessions; 3331 synchronized (mLock) { 3332 childSessions = getChildSessionsLocked(); 3333 } 3334 for (PackageInstallerSession child: childSessions) { 3335 if (filter.test(child)) { 3336 return true; 3337 } 3338 } 3339 return false; 3340 } 3341 3342 boolean containsApkSession() { 3343 return sessionContains((s) -> !s.isApexSession()); 3344 } 3345 3346 /** 3347 * Validate apex install. 3348 * <p> 3349 * Sets {@link #mResolvedBaseFile} for RollbackManager to use. Sets {@link #mPackageName} for 3350 * StagingManager to use. 3351 */ 3352 @GuardedBy("mLock") 3353 private void validateApexInstallLocked() 3354 throws PackageManagerException { 3355 final List<File> addedFiles = getAddedApksLocked(); 3356 if (addedFiles.isEmpty()) { 3357 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, 3358 TextUtils.formatSimple("Session: %d. No packages staged in %s", sessionId, 3359 stageDir.getAbsolutePath())); 3360 } 3361 3362 if (ArrayUtils.size(addedFiles) > 1) { 3363 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, 3364 "Too many files for apex install"); 3365 } 3366 3367 File addedFile = addedFiles.get(0); // there is only one file 3368 3369 // Ensure file name has proper suffix 3370 final String sourceName = addedFile.getName(); 3371 final String targetName = sourceName.endsWith(APEX_FILE_EXTENSION) 3372 ? sourceName 3373 : sourceName + APEX_FILE_EXTENSION; 3374 if (!FileUtils.isValidExtFilename(targetName)) { 3375 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, 3376 "Invalid filename: " + targetName); 3377 } 3378 3379 final File targetFile = new File(stageDir, targetName); 3380 resolveAndStageFileLocked(addedFile, targetFile, null); 3381 mResolvedBaseFile = targetFile; 3382 3383 // Populate package name of the apex session 3384 mPackageName = null; 3385 final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); 3386 final ParseResult<ApkLite> ret = ApkLiteParseUtils.parseApkLite(input.reset(), 3387 mResolvedBaseFile, ParsingPackageUtils.PARSE_COLLECT_CERTIFICATES); 3388 if (ret.isError()) { 3389 throw new PackageManagerException(ret.getErrorCode(), ret.getErrorMessage(), 3390 ret.getException()); 3391 } 3392 final ApkLite apk = ret.getResult(); 3393 3394 if (mPackageName == null) { 3395 mPackageName = apk.getPackageName(); 3396 mVersionCode = apk.getLongVersionCode(); 3397 } 3398 3399 mSigningDetails = apk.getSigningDetails(); 3400 mHasDeviceAdminReceiver = apk.isHasDeviceAdminReceiver(); 3401 } 3402 3403 /** 3404 * Validate install by confirming that all application packages are have 3405 * consistent package name, version code, and signing certificates. 3406 * <p> 3407 * Clears and populates {@link #mResolvedBaseFile}, 3408 * {@link #mResolvedStagedFiles}, and {@link #mResolvedInheritedFiles}. 3409 * <p> 3410 * Renames package files in stage to match split names defined inside. 3411 * <p> 3412 * Note that upgrade compatibility is still performed by 3413 * {@link PackageManagerService}. 3414 * @return a {@link PackageLite} representation of the validated APK(s). 3415 */ 3416 @GuardedBy("mLock") 3417 private PackageLite validateApkInstallLocked() throws PackageManagerException { 3418 ApkLite baseApk = null; 3419 final PackageLite packageLite; 3420 mPackageLite = null; 3421 mPackageName = null; 3422 mVersionCode = -1; 3423 mSigningDetails = SigningDetails.UNKNOWN; 3424 3425 mResolvedBaseFile = null; 3426 mResolvedStagedFiles.clear(); 3427 mResolvedInheritedFiles.clear(); 3428 3429 final PackageInfo pkgInfo = mPm.snapshotComputer().getPackageInfo( 3430 params.appPackageName, PackageManager.GET_SIGNATURES 3431 | PackageManager.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES /*flags*/, userId); 3432 3433 // Partial installs must be consistent with existing install 3434 if (params.mode == SessionParams.MODE_INHERIT_EXISTING 3435 && (pkgInfo == null || pkgInfo.applicationInfo == null)) { 3436 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, 3437 "Missing existing base package"); 3438 } 3439 3440 // Default to require only if existing base apk has fs-verity signature. 3441 mVerityFoundForApks = PackageManagerServiceUtils.isApkVerityEnabled() 3442 && params.mode == SessionParams.MODE_INHERIT_EXISTING 3443 && VerityUtils.hasFsverity(pkgInfo.applicationInfo.getBaseCodePath()) 3444 && (new File(VerityUtils.getFsveritySignatureFilePath( 3445 pkgInfo.applicationInfo.getBaseCodePath()))).exists(); 3446 3447 final List<File> removedFiles = getRemovedFilesLocked(); 3448 final List<String> removeSplitList = new ArrayList<>(); 3449 if (!removedFiles.isEmpty()) { 3450 for (File removedFile : removedFiles) { 3451 final String fileName = removedFile.getName(); 3452 final String splitName = fileName.substring( 3453 0, fileName.length() - REMOVE_MARKER_EXTENSION.length()); 3454 removeSplitList.add(splitName); 3455 } 3456 } 3457 3458 // Needs to happen before the first v4 signature verification, which happens in 3459 // getAddedApkLitesLocked. 3460 if (android.security.Flags.extendVbChainToUpdatedApk()) { 3461 if (!isIncrementalInstallation()) { 3462 enableFsVerityToAddedApksWithIdsig(); 3463 } 3464 } 3465 3466 final List<ApkLite> addedFiles = getAddedApkLitesLocked(); 3467 if (addedFiles.isEmpty() 3468 && (removeSplitList.size() == 0 || mHasAppMetadataFile)) { 3469 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, 3470 TextUtils.formatSimple("Session: %d. No packages staged in %s", sessionId, 3471 stageDir.getAbsolutePath())); 3472 } 3473 3474 // Verify that all staged packages are internally consistent 3475 final ArraySet<String> stagedSplits = new ArraySet<>(); 3476 final ArraySet<String> stagedSplitTypes = new ArraySet<>(); 3477 final ArraySet<String> requiredSplitTypes = new ArraySet<>(); 3478 final ArrayMap<String, ApkLite> splitApks = new ArrayMap<>(); 3479 final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); 3480 for (ApkLite apk : addedFiles) { 3481 if (!stagedSplits.add(apk.getSplitName())) { 3482 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, 3483 "Split " + apk.getSplitName() + " was defined multiple times"); 3484 } 3485 3486 if (!apk.isUpdatableSystem()) { 3487 if (mOriginalInstallerUid == Process.ROOT_UID) { 3488 Slog.w(TAG, "Overriding updatableSystem because the installer is root for: " 3489 + apk.getPackageName()); 3490 } else { 3491 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, 3492 "Non updatable system package can't be installed or updated"); 3493 } 3494 } 3495 3496 // Use first package to define unknown values 3497 if (mPackageName == null) { 3498 mPackageName = apk.getPackageName(); 3499 mVersionCode = apk.getLongVersionCode(); 3500 } 3501 if (mSigningDetails == SigningDetails.UNKNOWN) { 3502 mSigningDetails = apk.getSigningDetails(); 3503 } 3504 mHasDeviceAdminReceiver = apk.isHasDeviceAdminReceiver(); 3505 3506 assertApkConsistentLocked(String.valueOf(apk), apk); 3507 3508 // Take this opportunity to enforce uniform naming 3509 final String targetName = ApkLiteParseUtils.splitNameToFileName(apk); 3510 if (!FileUtils.isValidExtFilename(targetName)) { 3511 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, 3512 "Invalid filename: " + targetName); 3513 } 3514 3515 // Yell loudly if installers drop attribute installLocation when apps explicitly set. 3516 if (apk.getInstallLocation() != PackageInfo.INSTALL_LOCATION_UNSPECIFIED) { 3517 final String installerPackageName = getInstallerPackageName(); 3518 if (installerPackageName != null 3519 && (params.installLocation != apk.getInstallLocation())) { 3520 Slog.wtf(TAG, installerPackageName 3521 + " drops manifest attribute android:installLocation in " + targetName 3522 + " for " + mPackageName); 3523 } 3524 } 3525 3526 final File targetFile = new File(stageDir, targetName); 3527 if (!isArchivedInstallation()) { 3528 final File sourceFile = new File(apk.getPath()); 3529 resolveAndStageFileLocked(sourceFile, targetFile, apk.getSplitName()); 3530 } 3531 3532 // Base is coming from session 3533 if (apk.getSplitName() == null) { 3534 mResolvedBaseFile = targetFile; 3535 baseApk = apk; 3536 } else { 3537 splitApks.put(apk.getSplitName(), apk); 3538 } 3539 3540 // Collect the requiredSplitTypes and staged splitTypes 3541 CollectionUtils.addAll(requiredSplitTypes, apk.getRequiredSplitTypes()); 3542 CollectionUtils.addAll(stagedSplitTypes, apk.getSplitTypes()); 3543 } 3544 3545 if (removeSplitList.size() > 0) { 3546 if (pkgInfo == null) { 3547 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, 3548 "Missing existing base package for " + mPackageName); 3549 } 3550 3551 // validate split names marked for removal 3552 for (String splitName : removeSplitList) { 3553 if (!ArrayUtils.contains(pkgInfo.splitNames, splitName)) { 3554 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, 3555 "Split not found: " + splitName); 3556 } 3557 } 3558 3559 // ensure we've got appropriate package name, version code and signatures 3560 if (mPackageName == null) { 3561 mPackageName = pkgInfo.packageName; 3562 mVersionCode = pkgInfo.getLongVersionCode(); 3563 } 3564 if (mSigningDetails == SigningDetails.UNKNOWN) { 3565 mSigningDetails = unsafeGetCertsWithoutVerification( 3566 pkgInfo.applicationInfo.sourceDir); 3567 } 3568 } 3569 3570 final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class); 3571 final PackageStateInternal existingPkgSetting = pmi.getPackageStateInternal(mPackageName); 3572 3573 if (!isInstallationAllowed(existingPkgSetting)) { 3574 throw new PackageManagerException( 3575 PackageManager.INSTALL_FAILED_SESSION_INVALID, 3576 "Installation of this package is not allowed."); 3577 } 3578 3579 if (isArchivedInstallation()) { 3580 if (!isArchivedInstallationAllowed(existingPkgSetting)) { 3581 throw new PackageManagerException( 3582 PackageManager.INSTALL_FAILED_SESSION_INVALID, 3583 "Archived installation of this package is not allowed."); 3584 } 3585 3586 if (!mPm.mInstallerService.mPackageArchiver.verifySupportsUnarchival( 3587 getInstallSource().mInstallerPackageName, userId)) { 3588 throw new PackageManagerException( 3589 PackageManager.INSTALL_FAILED_SESSION_INVALID, 3590 "Installer has to support unarchival in order to install archived " 3591 + "packages."); 3592 } 3593 } 3594 3595 File stagedAppMetadataFile = isIncrementalInstallation() 3596 ? getTmpAppMetadataFile() : getStagedAppMetadataFile(); 3597 if (mHasAppMetadataFile && !stagedAppMetadataFile.exists()) { 3598 throw new PackageManagerException(INSTALL_FAILED_SESSION_INVALID, 3599 "App metadata file expected but not found in " + stageDir.getAbsolutePath()); 3600 } 3601 3602 if (isIncrementalInstallation()) { 3603 if (!isIncrementalInstallationAllowed(existingPkgSetting)) { 3604 throw new PackageManagerException( 3605 PackageManager.INSTALL_FAILED_SESSION_INVALID, 3606 "Incremental installation of this package is not allowed."); 3607 } 3608 // Since we moved the staged app metadata file so that incfs can be initialized, lets 3609 // now move it back. 3610 if (mHasAppMetadataFile) { 3611 File appMetadataFile = getTmpAppMetadataFile(); 3612 final IncrementalFileStorages incrementalFileStorages = 3613 getIncrementalFileStorages(); 3614 try { 3615 incrementalFileStorages.makeFile(APP_METADATA_FILE_NAME, 3616 Files.readAllBytes(appMetadataFile.toPath()), 3617 APP_METADATA_FILE_ACCESS_MODE); 3618 } catch (IOException e) { 3619 Slog.e(TAG, "Failed to write app metadata to incremental storage", e); 3620 } finally { 3621 appMetadataFile.delete(); 3622 } 3623 } 3624 } 3625 3626 if (mInstallerUid != mOriginalInstallerUid) { 3627 // Session has been transferred, check package name. 3628 if (TextUtils.isEmpty(mPackageName) || !mPackageName.equals( 3629 mOriginalInstallerPackageName)) { 3630 throw new PackageManagerException(PackageManager.INSTALL_FAILED_PACKAGE_CHANGED, 3631 "Can only transfer sessions that update the original installer"); 3632 } 3633 } 3634 3635 if (!mChecksums.isEmpty()) { 3636 throw new PackageManagerException( 3637 PackageManager.INSTALL_FAILED_SESSION_INVALID, 3638 "Invalid checksum name(s): " + String.join(",", mChecksums.keySet())); 3639 } 3640 3641 if (params.mode == SessionParams.MODE_FULL_INSTALL) { 3642 // Full installs must include a base package 3643 if (!stagedSplits.contains(null)) { 3644 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, 3645 "Full install must include a base package"); 3646 } else if ((params.installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) { 3647 EventLog.writeEvent(0x534e4554, "219044664"); 3648 3649 // Installing base.apk. Make sure the app is restarted. 3650 params.setDontKillApp(false); 3651 } 3652 if (baseApk.isSplitRequired() && (stagedSplits.size() <= 1 3653 || !stagedSplitTypes.containsAll(requiredSplitTypes))) { 3654 throw new PackageManagerException(INSTALL_FAILED_MISSING_SPLIT, 3655 "Missing split for " + mPackageName); 3656 } 3657 // For mode full install, we compose package lite for future usage instead of 3658 // re-parsing it again and again. 3659 final ParseResult<PackageLite> pkgLiteResult = 3660 ApkLiteParseUtils.composePackageLiteFromApks(input.reset(), stageDir, baseApk, 3661 splitApks, true); 3662 if (pkgLiteResult.isError()) { 3663 throw new PackageManagerException(pkgLiteResult.getErrorCode(), 3664 pkgLiteResult.getErrorMessage(), pkgLiteResult.getException()); 3665 } 3666 mPackageLite = pkgLiteResult.getResult(); 3667 packageLite = mPackageLite; 3668 } else { 3669 final ApplicationInfo appInfo = pkgInfo.applicationInfo; 3670 ParseResult<PackageLite> pkgLiteResult = ApkLiteParseUtils.parsePackageLite( 3671 input.reset(), new File(appInfo.getCodePath()), 0); 3672 if (pkgLiteResult.isError()) { 3673 throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, 3674 pkgLiteResult.getErrorMessage(), pkgLiteResult.getException()); 3675 } 3676 final PackageLite existing = pkgLiteResult.getResult(); 3677 packageLite = existing; 3678 assertPackageConsistentLocked("Existing", existing.getPackageName(), 3679 existing.getLongVersionCode()); 3680 final SigningDetails signingDetails = 3681 unsafeGetCertsWithoutVerification(existing.getBaseApkPath()); 3682 if (!mSigningDetails.signaturesMatchExactly(signingDetails)) { 3683 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, 3684 "Existing signatures are inconsistent"); 3685 } 3686 3687 // Inherit base if not overridden. 3688 if (mResolvedBaseFile == null) { 3689 mResolvedBaseFile = new File(appInfo.getBaseCodePath()); 3690 inheritFileLocked(mResolvedBaseFile); 3691 // Collect the requiredSplitTypes from base 3692 CollectionUtils.addAll(requiredSplitTypes, existing.getBaseRequiredSplitTypes()); 3693 } else if ((params.installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) { 3694 EventLog.writeEvent(0x534e4554, "219044664"); 3695 3696 // Installing base.apk. Make sure the app is restarted. 3697 params.setDontKillApp(false); 3698 } 3699 3700 boolean existingSplitReplacedOrRemoved = false; 3701 // Inherit splits if not overridden. 3702 if (!ArrayUtils.isEmpty(existing.getSplitNames())) { 3703 for (int i = 0; i < existing.getSplitNames().length; i++) { 3704 final String splitName = existing.getSplitNames()[i]; 3705 final File splitFile = new File(existing.getSplitApkPaths()[i]); 3706 final boolean splitRemoved = removeSplitList.contains(splitName); 3707 final boolean splitReplaced = stagedSplits.contains(splitName); 3708 if (!splitReplaced && !splitRemoved) { 3709 inheritFileLocked(splitFile); 3710 // Collect the requiredSplitTypes and staged splitTypes from splits 3711 CollectionUtils.addAll(requiredSplitTypes, 3712 existing.getRequiredSplitTypes()[i]); 3713 CollectionUtils.addAll(stagedSplitTypes, existing.getSplitTypes()[i]); 3714 } else { 3715 existingSplitReplacedOrRemoved = true; 3716 } 3717 } 3718 } 3719 if (existingSplitReplacedOrRemoved 3720 && (params.installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) { 3721 // Some splits are being replaced or removed. Make sure the app is restarted. 3722 params.setDontKillApp(false); 3723 } 3724 3725 // Inherit compiled oat directory. 3726 final File packageInstallDir = (new File(appInfo.getBaseCodePath())).getParentFile(); 3727 mInheritedFilesBase = packageInstallDir; 3728 final File oatDir = new File(packageInstallDir, "oat"); 3729 if (oatDir.exists()) { 3730 final File[] archSubdirs = oatDir.listFiles(); 3731 3732 // Keep track of all instruction sets we've seen compiled output for. 3733 // If we're linking (and not copying) inherited files, we can recreate the 3734 // instruction set hierarchy and link compiled output. 3735 if (archSubdirs != null && archSubdirs.length > 0) { 3736 final String[] instructionSets = InstructionSets.getAllDexCodeInstructionSets(); 3737 for (File archSubDir : archSubdirs) { 3738 // Skip any directory that isn't an ISA subdir. 3739 if (!ArrayUtils.contains(instructionSets, archSubDir.getName())) { 3740 continue; 3741 } 3742 3743 File[] files = archSubDir.listFiles(); 3744 if (files == null || files.length == 0) { 3745 continue; 3746 } 3747 3748 mResolvedInstructionSets.add(archSubDir.getName()); 3749 mResolvedInheritedFiles.addAll(Arrays.asList(files)); 3750 } 3751 } 3752 } 3753 3754 // Inherit native libraries for DONT_KILL sessions. 3755 if (mayInheritNativeLibs() && removeSplitList.isEmpty()) { 3756 File[] libDirs = new File[]{ 3757 new File(packageInstallDir, NativeLibraryHelper.LIB_DIR_NAME), 3758 new File(packageInstallDir, NativeLibraryHelper.LIB64_DIR_NAME)}; 3759 for (File libDir : libDirs) { 3760 if (!libDir.exists() || !libDir.isDirectory()) { 3761 continue; 3762 } 3763 final List<String> libDirsToInherit = new ArrayList<>(); 3764 final List<File> libFilesToInherit = new ArrayList<>(); 3765 for (File archSubDir : libDir.listFiles()) { 3766 if (!archSubDir.isDirectory()) { 3767 continue; 3768 } 3769 String relLibPath; 3770 try { 3771 relLibPath = getRelativePath(archSubDir, packageInstallDir); 3772 } catch (IOException e) { 3773 Slog.e(TAG, "Skipping linking of native library directory!", e); 3774 // shouldn't be possible, but let's avoid inheriting these to be safe 3775 libDirsToInherit.clear(); 3776 libFilesToInherit.clear(); 3777 break; 3778 } 3779 3780 File[] files = archSubDir.listFiles(); 3781 if (files == null || files.length == 0) { 3782 continue; 3783 } 3784 3785 libDirsToInherit.add(relLibPath); 3786 libFilesToInherit.addAll(Arrays.asList(files)); 3787 } 3788 for (String subDir : libDirsToInherit) { 3789 if (!mResolvedNativeLibPaths.contains(subDir)) { 3790 mResolvedNativeLibPaths.add(subDir); 3791 } 3792 } 3793 mResolvedInheritedFiles.addAll(libFilesToInherit); 3794 } 3795 } 3796 // For the case of split required, failed if no splits existed 3797 if (packageLite.isSplitRequired()) { 3798 final int existingSplits = ArrayUtils.size(existing.getSplitNames()); 3799 final boolean allSplitsRemoved = (existingSplits == removeSplitList.size()); 3800 final boolean onlyBaseFileStaged = (stagedSplits.size() == 1 3801 && stagedSplits.contains(null)); 3802 if ((allSplitsRemoved && (stagedSplits.isEmpty() || onlyBaseFileStaged)) 3803 || !stagedSplitTypes.containsAll(requiredSplitTypes)) { 3804 throw new PackageManagerException(INSTALL_FAILED_MISSING_SPLIT, 3805 "Missing split for " + mPackageName); 3806 } 3807 } 3808 } 3809 3810 assertPreapprovalDetailsConsistentIfNeededLocked(packageLite, pkgInfo); 3811 3812 if (packageLite.isUseEmbeddedDex()) { 3813 for (File file : mResolvedStagedFiles) { 3814 if (file.getName().endsWith(".apk") 3815 && !DexManager.auditUncompressedDexInApk(file.getPath())) { 3816 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, 3817 "Some dex are not uncompressed and aligned correctly for " 3818 + mPackageName); 3819 } 3820 } 3821 } 3822 3823 final boolean isInstallerShell = (mInstallerUid == Process.SHELL_UID); 3824 if (isInstallerShell && isIncrementalInstallation() && mIncrementalFileStorages != null) { 3825 if (!packageLite.isDebuggable() && !packageLite.isProfileableByShell()) { 3826 mIncrementalFileStorages.disallowReadLogs(); 3827 } 3828 } 3829 3830 // {@link #sendPendingUserActionIntentIfNeeded} needs to use 3831 // {@link PackageLite#getTargetSdk()} 3832 mValidatedTargetSdk = packageLite.getTargetSdk(); 3833 3834 return packageLite; 3835 } 3836 3837 @GuardedBy("mLock") 3838 private void stageFileLocked(File origFile, File targetFile) 3839 throws PackageManagerException { 3840 mResolvedStagedFiles.add(targetFile); 3841 maybeRenameFile(origFile, targetFile); 3842 } 3843 3844 @GuardedBy("mLock") 3845 private void maybeStageFsveritySignatureLocked(File origFile, File targetFile, 3846 boolean fsVerityRequired) throws PackageManagerException { 3847 if (android.security.Flags.deprecateFsvSig()) { 3848 return; 3849 } 3850 final File originalSignature = new File( 3851 VerityUtils.getFsveritySignatureFilePath(origFile.getPath())); 3852 if (originalSignature.exists()) { 3853 final File stagedSignature = new File( 3854 VerityUtils.getFsveritySignatureFilePath(targetFile.getPath())); 3855 stageFileLocked(originalSignature, stagedSignature); 3856 } else if (fsVerityRequired) { 3857 throw new PackageManagerException(INSTALL_FAILED_BAD_SIGNATURE, 3858 "Missing corresponding fs-verity signature to " + origFile); 3859 } 3860 } 3861 3862 @GuardedBy("mLock") 3863 private void maybeStageV4SignatureLocked(File origFile, File targetFile) 3864 throws PackageManagerException { 3865 final File originalSignature = new File(origFile.getPath() + V4Signature.EXT); 3866 if (originalSignature.exists()) { 3867 final File stagedSignature = new File(targetFile.getPath() + V4Signature.EXT); 3868 stageFileLocked(originalSignature, stagedSignature); 3869 } 3870 } 3871 3872 @GuardedBy("mLock") 3873 private void maybeStageDexMetadataLocked(File origFile, File targetFile) 3874 throws PackageManagerException { 3875 final File dexMetadataFile = DexMetadataHelper.findDexMetadataForFile(origFile); 3876 if (dexMetadataFile == null) { 3877 return; 3878 } 3879 3880 if (!FileUtils.isValidExtFilename(dexMetadataFile.getName())) { 3881 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, 3882 "Invalid filename: " + dexMetadataFile); 3883 } 3884 final File targetDexMetadataFile = new File(stageDir, 3885 DexMetadataHelper.buildDexMetadataPathForApk(targetFile.getName())); 3886 3887 stageFileLocked(dexMetadataFile, targetDexMetadataFile); 3888 3889 // Also stage .dm.fsv_sig. .dm may be required to install with fs-verity signature on 3890 // supported on older devices. 3891 maybeStageFsveritySignatureLocked(dexMetadataFile, targetDexMetadataFile, 3892 DexMetadataHelper.isFsVerityRequired()); 3893 } 3894 3895 private IncrementalFileStorages getIncrementalFileStorages() { 3896 synchronized (mLock) { 3897 return mIncrementalFileStorages; 3898 } 3899 } 3900 3901 private void storeBytesToInstallationFile(final String localPath, final String absolutePath, 3902 final byte[] bytes) throws IOException { 3903 final IncrementalFileStorages incrementalFileStorages = getIncrementalFileStorages(); 3904 if (!isIncrementalInstallation() || incrementalFileStorages == null) { 3905 FileUtils.bytesToFile(absolutePath, bytes); 3906 } else { 3907 incrementalFileStorages.makeFile(localPath, bytes, 0777); 3908 } 3909 } 3910 3911 @GuardedBy("mLock") 3912 private void maybeStageDigestsLocked(File origFile, File targetFile, String splitName) 3913 throws PackageManagerException { 3914 final PerFileChecksum perFileChecksum = mChecksums.get(origFile.getName()); 3915 if (perFileChecksum == null) { 3916 return; 3917 } 3918 mChecksums.remove(origFile.getName()); 3919 3920 final Checksum[] checksums = perFileChecksum.getChecksums(); 3921 if (checksums.length == 0) { 3922 return; 3923 } 3924 3925 final String targetDigestsPath = ApkChecksums.buildDigestsPathForApk(targetFile.getName()); 3926 final File targetDigestsFile = new File(stageDir, targetDigestsPath); 3927 try (ByteArrayOutputStream os = new ByteArrayOutputStream()) { 3928 ApkChecksums.writeChecksums(os, checksums); 3929 3930 final byte[] signature = perFileChecksum.getSignature(); 3931 if (signature != null && signature.length > 0) { 3932 Certificate[] ignored = ApkChecksums.verifySignature(checksums, signature); 3933 } 3934 3935 // Storing and staging checksums. 3936 storeBytesToInstallationFile(targetDigestsPath, targetDigestsFile.getAbsolutePath(), 3937 os.toByteArray()); 3938 stageFileLocked(targetDigestsFile, targetDigestsFile); 3939 3940 // Storing and staging signature. 3941 if (signature == null || signature.length == 0) { 3942 return; 3943 } 3944 3945 final String targetDigestsSignaturePath = ApkChecksums.buildSignaturePathForDigests( 3946 targetDigestsPath); 3947 final File targetDigestsSignatureFile = new File(stageDir, targetDigestsSignaturePath); 3948 storeBytesToInstallationFile(targetDigestsSignaturePath, 3949 targetDigestsSignatureFile.getAbsolutePath(), signature); 3950 stageFileLocked(targetDigestsSignatureFile, targetDigestsSignatureFile); 3951 } catch (IOException e) { 3952 throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE, 3953 "Failed to store digests for " + mPackageName, e); 3954 } catch (NoSuchAlgorithmException | SignatureException e) { 3955 throw new PackageManagerException(INSTALL_PARSE_FAILED_NO_CERTIFICATES, 3956 "Failed to verify digests' signature for " + mPackageName, e); 3957 } 3958 } 3959 3960 @GuardedBy("mLock") 3961 private boolean isFsVerityRequiredForApk(File origFile, File targetFile) 3962 throws PackageManagerException { 3963 if (mVerityFoundForApks) { 3964 return true; 3965 } 3966 3967 // We haven't seen .fsv_sig for any APKs. Treat it as not required until we see one. 3968 final File originalSignature = new File( 3969 VerityUtils.getFsveritySignatureFilePath(origFile.getPath())); 3970 if (!originalSignature.exists()) { 3971 return false; 3972 } 3973 mVerityFoundForApks = true; 3974 3975 // When a signature is found, also check any previous staged APKs since they also need to 3976 // have fs-verity signature consistently. 3977 for (File file : mResolvedStagedFiles) { 3978 if (!file.getName().endsWith(".apk")) { 3979 continue; 3980 } 3981 // Ignore the current targeting file. 3982 if (targetFile.getName().equals(file.getName())) { 3983 continue; 3984 } 3985 throw new PackageManagerException(INSTALL_FAILED_BAD_SIGNATURE, 3986 "Previously staged apk is missing fs-verity signature"); 3987 } 3988 return true; 3989 } 3990 3991 @GuardedBy("mLock") 3992 private void resolveAndStageFileLocked(File origFile, File targetFile, String splitName) 3993 throws PackageManagerException { 3994 stageFileLocked(origFile, targetFile); 3995 3996 // Stage APK's fs-verity signature if present. 3997 maybeStageFsveritySignatureLocked(origFile, targetFile, 3998 isFsVerityRequiredForApk(origFile, targetFile)); 3999 // Stage APK's v4 signature if present, and fs-verity is supported. 4000 if (android.security.Flags.extendVbChainToUpdatedApk() 4001 && VerityUtils.isFsVeritySupported()) { 4002 maybeStageV4SignatureLocked(origFile, targetFile); 4003 } 4004 // Stage dex metadata (.dm) and corresponding fs-verity signature if present. 4005 maybeStageDexMetadataLocked(origFile, targetFile); 4006 // Stage checksums (.digests) if present. 4007 maybeStageDigestsLocked(origFile, targetFile, splitName); 4008 } 4009 4010 @GuardedBy("mLock") 4011 private void maybeInheritFsveritySignatureLocked(File origFile) { 4012 // Inherit the fsverity signature file if present. 4013 final File fsveritySignatureFile = new File( 4014 VerityUtils.getFsveritySignatureFilePath(origFile.getPath())); 4015 if (fsveritySignatureFile.exists()) { 4016 mResolvedInheritedFiles.add(fsveritySignatureFile); 4017 } 4018 } 4019 4020 @GuardedBy("mLock") 4021 private void maybeInheritV4SignatureLocked(File origFile) { 4022 // Inherit the v4 signature file if present. 4023 final File v4SignatureFile = new File(origFile.getPath() + V4Signature.EXT); 4024 if (v4SignatureFile.exists()) { 4025 mResolvedInheritedFiles.add(v4SignatureFile); 4026 } 4027 } 4028 4029 @GuardedBy("mLock") 4030 private void inheritFileLocked(File origFile) { 4031 mResolvedInheritedFiles.add(origFile); 4032 4033 maybeInheritFsveritySignatureLocked(origFile); 4034 if (android.security.Flags.extendVbChainToUpdatedApk()) { 4035 maybeInheritV4SignatureLocked(origFile); 4036 } 4037 4038 // Inherit the dex metadata if present. 4039 final File dexMetadataFile = 4040 DexMetadataHelper.findDexMetadataForFile(origFile); 4041 if (dexMetadataFile != null) { 4042 mResolvedInheritedFiles.add(dexMetadataFile); 4043 maybeInheritFsveritySignatureLocked(dexMetadataFile); 4044 } 4045 // Inherit the digests if present. 4046 final File digestsFile = ApkChecksums.findDigestsForFile(origFile); 4047 if (digestsFile != null) { 4048 mResolvedInheritedFiles.add(digestsFile); 4049 4050 final File signatureFile = ApkChecksums.findSignatureForDigests(digestsFile); 4051 if (signatureFile != null) { 4052 mResolvedInheritedFiles.add(signatureFile); 4053 } 4054 } 4055 } 4056 4057 @GuardedBy("mLock") 4058 private void assertApkConsistentLocked(String tag, ApkLite apk) 4059 throws PackageManagerException { 4060 assertPackageConsistentLocked(tag, apk.getPackageName(), apk.getLongVersionCode()); 4061 if (!mSigningDetails.signaturesMatchExactly(apk.getSigningDetails())) { 4062 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, 4063 tag + " signatures are inconsistent"); 4064 } 4065 } 4066 4067 @GuardedBy("mLock") 4068 private void assertPackageConsistentLocked(String tag, String packageName, 4069 long versionCode) throws PackageManagerException { 4070 if (!mPackageName.equals(packageName)) { 4071 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " package " 4072 + packageName + " inconsistent with " + mPackageName); 4073 } 4074 if (params.appPackageName != null && !params.appPackageName.equals(packageName)) { 4075 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag 4076 + " specified package " + params.appPackageName 4077 + " inconsistent with " + packageName); 4078 } 4079 if (mVersionCode != versionCode) { 4080 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag 4081 + " version code " + versionCode + " inconsistent with " 4082 + mVersionCode); 4083 } 4084 } 4085 4086 @GuardedBy("mLock") 4087 private void assertPreapprovalDetailsConsistentIfNeededLocked(@NonNull PackageLite packageLite, 4088 @Nullable PackageInfo info) throws PackageManagerException { 4089 if (mPreapprovalDetails == null || !isPreapprovalRequested()) { 4090 return; 4091 } 4092 4093 if (!TextUtils.equals(mPackageName, mPreapprovalDetails.getPackageName())) { 4094 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, 4095 mPreapprovalDetails + " inconsistent with " + mPackageName); 4096 } 4097 4098 final PackageManager packageManager = mContext.getPackageManager(); 4099 // The given info isn't null only when params.appPackageName is set. 4100 final PackageInfo existingPackageInfo = 4101 info != null ? info : mPm.snapshotComputer().getPackageInfo(mPackageName, 4102 0 /* flags */, userId); 4103 // If the app label in PreapprovalDetails matches the existing one, we treat it as valid. 4104 final CharSequence appLabel = mPreapprovalDetails.getLabel(); 4105 if (existingPackageInfo != null) { 4106 final ApplicationInfo existingAppInfo = existingPackageInfo.applicationInfo; 4107 final CharSequence existingAppLabel = packageManager.getApplicationLabel( 4108 existingAppInfo); 4109 if (TextUtils.equals(appLabel, existingAppLabel)) { 4110 return; 4111 } 4112 } 4113 4114 final PackageInfo packageInfoFromApk = packageManager.getPackageArchiveInfo( 4115 packageLite.getPath(), PackageInfoFlags.of(0)); 4116 if (packageInfoFromApk == null) { 4117 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, 4118 "Failure to obtain package info from APK files."); 4119 } 4120 4121 // In case the app label in PreapprovalDetails from different locale in split APK, 4122 // we check all APK files to find the app label. 4123 final List<String> filePaths = packageLite.getAllApkPaths(); 4124 final ULocale appLocale = mPreapprovalDetails.getLocale(); 4125 final ApplicationInfo appInfo = packageInfoFromApk.applicationInfo; 4126 boolean appLabelMatched = false; 4127 for (int i = filePaths.size() - 1; i >= 0 && !appLabelMatched; i--) { 4128 appLabelMatched |= TextUtils.equals(getAppLabel(filePaths.get(i), appLocale, appInfo), 4129 appLabel); 4130 } 4131 if (!appLabelMatched) { 4132 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, 4133 mPreapprovalDetails + " inconsistent with app label"); 4134 } 4135 } 4136 4137 private CharSequence getAppLabel(String path, ULocale locale, ApplicationInfo appInfo) 4138 throws PackageManagerException { 4139 final Resources pRes = mContext.getResources(); 4140 final AssetManager assetManager = new AssetManager(); 4141 final Configuration config = new Configuration(pRes.getConfiguration()); 4142 final ApkAssets apkAssets; 4143 try { 4144 apkAssets = ApkAssets.loadFromPath(path); 4145 } catch (IOException e) { 4146 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, 4147 "Failure to get resources from package archive " + path); 4148 } 4149 assetManager.setApkAssets(new ApkAssets[]{apkAssets}, false /* invalidateCaches */); 4150 config.setLocale(locale.toLocale()); 4151 final Resources res = new Resources(assetManager, pRes.getDisplayMetrics(), config); 4152 return TextUtils.trimToSize(tryLoadingAppLabel(res, appInfo), MAX_SAFE_LABEL_LENGTH); 4153 } 4154 4155 private CharSequence tryLoadingAppLabel(@NonNull Resources res, @NonNull ApplicationInfo info) { 4156 CharSequence label = null; 4157 // Try to load the label from the package's resources. If an app has not explicitly 4158 // specified any label, just use the package name. 4159 if (info.labelRes != 0) { 4160 try { 4161 label = res.getText(info.labelRes).toString().trim(); 4162 } catch (Resources.NotFoundException ignore) { 4163 } 4164 } 4165 if (label == null) { 4166 label = (info.nonLocalizedLabel != null) 4167 ? info.nonLocalizedLabel : info.packageName; 4168 } 4169 4170 return label; 4171 } 4172 4173 private SigningDetails unsafeGetCertsWithoutVerification(String path) 4174 throws PackageManagerException { 4175 final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); 4176 final ParseResult<SigningDetails> result = 4177 ApkSignatureVerifier.unsafeGetCertsWithoutVerification( 4178 input, path, SigningDetails.SignatureSchemeVersion.JAR); 4179 if (result.isError()) { 4180 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, 4181 "Couldn't obtain signatures from APK : " + path); 4182 } 4183 return result.getResult(); 4184 } 4185 4186 /** 4187 * Determine if creating hard links between source and destination is 4188 * possible. That is, do they all live on the same underlying device. 4189 */ 4190 private static boolean isLinkPossible(List<File> fromFiles, File toDir) { 4191 try { 4192 final StructStat toStat = Os.stat(toDir.getAbsolutePath()); 4193 for (File fromFile : fromFiles) { 4194 final StructStat fromStat = Os.stat(fromFile.getAbsolutePath()); 4195 if (fromStat.st_dev != toStat.st_dev) { 4196 return false; 4197 } 4198 } 4199 } catch (ErrnoException e) { 4200 Slog.w(TAG, "Failed to detect if linking possible: " + e); 4201 return false; 4202 } 4203 return true; 4204 } 4205 4206 /** 4207 * @return the uid of the owner this session 4208 */ 4209 public int getInstallerUid() { 4210 synchronized (mLock) { 4211 return mInstallerUid; 4212 } 4213 } 4214 4215 /** 4216 * @return the package name of this session 4217 */ 4218 @VisibleForTesting(visibility = PACKAGE) 4219 public String getPackageName() { 4220 synchronized (mLock) { 4221 return mPackageName; 4222 } 4223 } 4224 4225 /** 4226 * @return the timestamp of when this session last changed state 4227 */ 4228 public long getUpdatedMillis() { 4229 synchronized (mLock) { 4230 return updatedMillis; 4231 } 4232 } 4233 4234 long getCommittedMillis() { 4235 synchronized (mLock) { 4236 return committedMillis; 4237 } 4238 } 4239 4240 String getInstallerPackageName() { 4241 return getInstallSource().mInstallerPackageName; 4242 } 4243 4244 String getInstallerAttributionTag() { 4245 return getInstallSource().mInstallerAttributionTag; 4246 } 4247 4248 InstallSource getInstallSource() { 4249 synchronized (mLock) { 4250 return mInstallSource; 4251 } 4252 } 4253 4254 SigningDetails getSigningDetails() { 4255 synchronized (mLock) { 4256 return mSigningDetails; 4257 } 4258 } 4259 4260 PackageLite getPackageLite() { 4261 synchronized (mLock) { 4262 return mPackageLite; 4263 } 4264 } 4265 4266 /** 4267 * @return a boolean value indicating whether user action was requested for the install. 4268 * Returns {@code false} if {@code mUserActionRequired} is {@code null} 4269 */ 4270 public boolean getUserActionRequired() { 4271 if (mUserActionRequired != null) { 4272 return mUserActionRequired.booleanValue(); 4273 } 4274 Slog.wtf(TAG, "mUserActionRequired should not be null."); 4275 return false; 4276 } 4277 4278 private static String getRelativePath(File file, File base) throws IOException { 4279 final String pathStr = file.getAbsolutePath(); 4280 final String baseStr = base.getAbsolutePath(); 4281 // Don't allow relative paths. 4282 if (pathStr.contains("/.") ) { 4283 throw new IOException("Invalid path (was relative) : " + pathStr); 4284 } 4285 4286 if (pathStr.startsWith(baseStr)) { 4287 return pathStr.substring(baseStr.length()); 4288 } 4289 4290 throw new IOException("File: " + pathStr + " outside base: " + baseStr); 4291 } 4292 4293 private void createOatDirs(String packageName, List<String> instructionSets, File fromDir) 4294 throws PackageManagerException { 4295 for (String instructionSet : instructionSets) { 4296 try { 4297 mInstaller.createOatDir(packageName, fromDir.getAbsolutePath(), instructionSet); 4298 } catch (InstallerException e) { 4299 throw PackageManagerException.from(e); 4300 } 4301 } 4302 } 4303 4304 private void linkFile(String packageName, String relativePath, String fromBase, String toBase) 4305 throws IOException { 4306 try { 4307 // Try 4308 final IncrementalFileStorages incrementalFileStorages = getIncrementalFileStorages(); 4309 if (incrementalFileStorages != null && incrementalFileStorages.makeLink(relativePath, 4310 fromBase, toBase)) { 4311 return; 4312 } 4313 mInstaller.linkFile(packageName, relativePath, fromBase, toBase); 4314 } catch (InstallerException | IOException e) { 4315 throw new IOException("failed linkOrCreateDir(" + relativePath + ", " 4316 + fromBase + ", " + toBase + ")", e); 4317 } 4318 } 4319 4320 private void linkFiles(String packageName, List<File> fromFiles, File toDir, File fromDir) 4321 throws IOException { 4322 for (File fromFile : fromFiles) { 4323 final String relativePath = getRelativePath(fromFile, fromDir); 4324 final String fromBase = fromDir.getAbsolutePath(); 4325 final String toBase = toDir.getAbsolutePath(); 4326 4327 linkFile(packageName, relativePath, fromBase, toBase); 4328 } 4329 4330 Slog.d(TAG, "Linked " + fromFiles.size() + " files into " + toDir); 4331 } 4332 4333 private static void copyFiles(List<File> fromFiles, File toDir) throws IOException { 4334 // Remove any partial files from previous attempt 4335 for (File file : toDir.listFiles()) { 4336 if (file.getName().endsWith(".tmp")) { 4337 file.delete(); 4338 } 4339 } 4340 4341 for (File fromFile : fromFiles) { 4342 final File tmpFile = File.createTempFile("inherit", ".tmp", toDir); 4343 if (LOGD) Slog.d(TAG, "Copying " + fromFile + " to " + tmpFile); 4344 if (!FileUtils.copyFile(fromFile, tmpFile)) { 4345 throw new IOException("Failed to copy " + fromFile + " to " + tmpFile); 4346 } 4347 try { 4348 Os.chmod(tmpFile.getAbsolutePath(), DEFAULT_FILE_ACCESS_MODE); 4349 } catch (ErrnoException e) { 4350 throw new IOException("Failed to chmod " + tmpFile); 4351 } 4352 final File toFile = new File(toDir, fromFile.getName()); 4353 if (LOGD) Slog.d(TAG, "Renaming " + tmpFile + " to " + toFile); 4354 if (!tmpFile.renameTo(toFile)) { 4355 throw new IOException("Failed to rename " + tmpFile + " to " + toFile); 4356 } 4357 } 4358 Slog.d(TAG, "Copied " + fromFiles.size() + " files into " + toDir); 4359 } 4360 4361 private void extractNativeLibraries(PackageLite packageLite, File packageDir, 4362 String abiOverride, boolean inherit) 4363 throws PackageManagerException { 4364 Objects.requireNonNull(packageLite); 4365 final File libDir = new File(packageDir, NativeLibraryHelper.LIB_DIR_NAME); 4366 if (!inherit) { 4367 // Start from a clean slate 4368 NativeLibraryHelper.removeNativeBinariesFromDirLI(libDir, true); 4369 } 4370 4371 // Skip native libraries processing for archival installation. 4372 if (isArchivedInstallation()) { 4373 return; 4374 } 4375 4376 NativeLibraryHelper.Handle handle = null; 4377 try { 4378 handle = NativeLibraryHelper.Handle.create(packageLite); 4379 final int res = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libDir, 4380 abiOverride, isIncrementalInstallation()); 4381 if (res != INSTALL_SUCCEEDED) { 4382 throw new PackageManagerException(res, 4383 "Failed to extract native libraries, res=" + res); 4384 } 4385 } catch (IOException e) { 4386 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, 4387 "Failed to extract native libraries", e); 4388 } finally { 4389 IoUtils.closeQuietly(handle); 4390 } 4391 } 4392 4393 void setPermissionsResult(boolean accepted) { 4394 if (!isSealed() && !isPreapprovalRequested()) { 4395 throw new SecurityException("Must be sealed to accept permissions"); 4396 } 4397 4398 // To support pre-approval request of atomic install, we allow child session to handle 4399 // the result by itself since it has the status receiver. 4400 final PackageInstallerSession root = hasParentSessionId() && isCommitted() 4401 ? mSessionProvider.getSession(getParentSessionId()) : this; 4402 4403 if (accepted) { 4404 // Mark and kick off another install pass 4405 synchronized (mLock) { 4406 mPermissionsManuallyAccepted = true; 4407 } 4408 root.mHandler.obtainMessage( 4409 isCommitted() ? MSG_INSTALL : MSG_PRE_APPROVAL_REQUEST).sendToTarget(); 4410 } else { 4411 root.destroy("User rejected permissions"); 4412 root.dispatchSessionFinished(INSTALL_FAILED_ABORTED, "User rejected permissions", null); 4413 root.maybeFinishChildSessions(INSTALL_FAILED_ABORTED, "User rejected permissions"); 4414 } 4415 } 4416 4417 public void open() throws IOException { 4418 activate(); 4419 boolean wasPrepared; 4420 synchronized (mLock) { 4421 wasPrepared = mPrepared; 4422 if (!mPrepared) { 4423 if (stageDir != null) { 4424 prepareStageDir(stageDir); 4425 } else if (params.isMultiPackage) { 4426 // it's all ok 4427 } else { 4428 throw new IllegalArgumentException("stageDir must be set"); 4429 } 4430 4431 mPrepared = true; 4432 } 4433 } 4434 4435 if (!wasPrepared) { 4436 mCallback.onSessionPrepared(this); 4437 } 4438 } 4439 4440 private void activate() { 4441 if (mActiveCount.getAndIncrement() == 0) { 4442 mCallback.onSessionActiveChanged(this, true); 4443 } 4444 } 4445 4446 @Override 4447 public void close() { 4448 closeInternal(true); 4449 } 4450 4451 private void closeInternal(boolean checkCaller) { 4452 synchronized (mLock) { 4453 if (checkCaller) { 4454 assertCallerIsOwnerOrRoot(); 4455 } 4456 } 4457 deactivate(); 4458 } 4459 4460 private void deactivate() { 4461 int activeCount; 4462 synchronized (mLock) { 4463 activeCount = mActiveCount.decrementAndGet(); 4464 } 4465 if (activeCount == 0) { 4466 mCallback.onSessionActiveChanged(this, false); 4467 } 4468 } 4469 4470 /** 4471 * Calls dispatchSessionFinished() on all child sessions with the given error code and 4472 * error message to prevent orphaned child sessions. 4473 */ 4474 private void maybeFinishChildSessions(int returnCode, String msg) { 4475 for (PackageInstallerSession child : getChildSessions()) { 4476 child.dispatchSessionFinished(returnCode, msg, null); 4477 } 4478 } 4479 4480 private void assertNotChild(String cookie) { 4481 if (hasParentSessionId()) { 4482 throw new IllegalStateException(cookie + " can't be called on a child session, id=" 4483 + sessionId + " parentId=" + getParentSessionId()); 4484 } 4485 } 4486 4487 /** 4488 * Called when verification has completed. Now it is safe to clean up the session 4489 * if {@link #abandon()} has been called previously. 4490 * 4491 * @return True if this session has been abandoned. 4492 */ 4493 private boolean dispatchPendingAbandonCallback() { 4494 final Runnable callback; 4495 synchronized (mLock) { 4496 if (!mStageDirInUse) { 4497 return false; 4498 } 4499 mStageDirInUse = false; 4500 callback = mPendingAbandonCallback; 4501 mPendingAbandonCallback = null; 4502 } 4503 if (callback != null) { 4504 callback.run(); 4505 return true; 4506 } 4507 return false; 4508 } 4509 4510 @Override 4511 public void abandon() { 4512 final Runnable r; 4513 synchronized (mLock) { 4514 assertNotChild("abandon"); 4515 assertCallerIsOwnerOrRootOrSystem(); 4516 if (isInTerminalState()) { 4517 // Finalized sessions have been properly cleaned up. No need to abandon them. 4518 return; 4519 } 4520 mDestroyed = true; 4521 r = () -> { 4522 assertNotLocked("abandonStaged"); 4523 if (isStaged() && isCommitted()) { 4524 mStagingManager.abortCommittedSession(mStagedSession); 4525 } 4526 destroy("Session was abandoned"); 4527 dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned", null); 4528 maybeFinishChildSessions(INSTALL_FAILED_ABORTED, 4529 "Session was abandoned because the parent session is abandoned"); 4530 }; 4531 if (mStageDirInUse) { 4532 // Verification is ongoing, not safe to clean up the session yet. 4533 mPendingAbandonCallback = r; 4534 mCallback.onSessionChanged(this); 4535 return; 4536 } 4537 } 4538 4539 final long token = Binder.clearCallingIdentity(); 4540 try { 4541 // This will call into StagingManager which might trigger external callbacks 4542 r.run(); 4543 } finally { 4544 Binder.restoreCallingIdentity(token); 4545 } 4546 } 4547 4548 @Override 4549 public boolean isMultiPackage() { 4550 return params.isMultiPackage; 4551 } 4552 4553 @Override 4554 public boolean isStaged() { 4555 return params.isStaged; 4556 } 4557 4558 @Override 4559 public int getInstallFlags() { 4560 return params.installFlags; 4561 } 4562 4563 @android.annotation.EnforcePermission(android.Manifest.permission.USE_INSTALLER_V2) 4564 @Override 4565 public DataLoaderParamsParcel getDataLoaderParams() { 4566 getDataLoaderParams_enforcePermission(); 4567 return params.dataLoaderParams != null ? params.dataLoaderParams.getData() : null; 4568 } 4569 4570 @android.annotation.EnforcePermission(android.Manifest.permission.USE_INSTALLER_V2) 4571 @Override 4572 public void addFile(int location, String name, long lengthBytes, byte[] metadata, 4573 byte[] signature) { 4574 addFile_enforcePermission(); 4575 if (!isDataLoaderInstallation()) { 4576 throw new IllegalStateException( 4577 "Cannot add files to non-data loader installation session."); 4578 } 4579 if (isStreamingInstallation()) { 4580 if (location != LOCATION_DATA_APP) { 4581 throw new IllegalArgumentException( 4582 "Non-incremental installation only supports /data/app placement: " + name); 4583 } 4584 } 4585 if (metadata == null) { 4586 throw new IllegalArgumentException( 4587 "DataLoader installation requires valid metadata: " + name); 4588 } 4589 // Use installer provided name for now; we always rename later 4590 if (!FileUtils.isValidExtFilename(name)) { 4591 throw new IllegalArgumentException("Invalid name: " + name); 4592 } 4593 4594 synchronized (mLock) { 4595 assertCallerIsOwnerOrRoot(); 4596 assertPreparedAndNotSealedLocked("addFile"); 4597 4598 if (!mFiles.add(new FileEntry(mFiles.size(), 4599 new InstallationFile(location, name, lengthBytes, metadata, signature)))) { 4600 throw new IllegalArgumentException("File already added: " + name); 4601 } 4602 } 4603 } 4604 4605 @android.annotation.EnforcePermission(android.Manifest.permission.USE_INSTALLER_V2) 4606 @Override 4607 public void removeFile(int location, String name) { 4608 removeFile_enforcePermission(); 4609 if (!isDataLoaderInstallation()) { 4610 throw new IllegalStateException( 4611 "Cannot add files to non-data loader installation session."); 4612 } 4613 if (TextUtils.isEmpty(params.appPackageName)) { 4614 throw new IllegalStateException("Must specify package name to remove a split"); 4615 } 4616 4617 synchronized (mLock) { 4618 assertCallerIsOwnerOrRoot(); 4619 assertPreparedAndNotSealedLocked("removeFile"); 4620 4621 if (!mFiles.add(new FileEntry(mFiles.size(), 4622 new InstallationFile(location, getRemoveMarkerName(name), -1, null, null)))) { 4623 throw new IllegalArgumentException("File already removed: " + name); 4624 } 4625 } 4626 } 4627 4628 /** 4629 * Makes sure files are present in staging location. 4630 * @return if the image is ready for installation 4631 */ 4632 @GuardedBy("mLock") 4633 private boolean prepareDataLoaderLocked() 4634 throws PackageManagerException { 4635 if (!isDataLoaderInstallation()) { 4636 return true; 4637 } 4638 if (mDataLoaderFinished) { 4639 return true; 4640 } 4641 4642 final List<InstallationFileParcel> addedFiles = new ArrayList<>(); 4643 final List<String> removedFiles = new ArrayList<>(); 4644 4645 final InstallationFile[] files = getInstallationFilesLocked(); 4646 for (InstallationFile file : files) { 4647 if (sAddedFilter.accept(new File(this.stageDir, file.getName()))) { 4648 addedFiles.add(file.getData()); 4649 continue; 4650 } 4651 if (sRemovedFilter.accept(new File(this.stageDir, file.getName()))) { 4652 String name = file.getName().substring( 4653 0, file.getName().length() - REMOVE_MARKER_EXTENSION.length()); 4654 removedFiles.add(name); 4655 } 4656 } 4657 4658 final DataLoaderParams params = this.params.dataLoaderParams; 4659 final boolean manualStartAndDestroy = !isIncrementalInstallation(); 4660 final boolean systemDataLoader = isSystemDataLoaderInstallation(); 4661 final IDataLoaderStatusListener statusListener = new IDataLoaderStatusListener.Stub() { 4662 @Override 4663 public void onStatusChanged(int dataLoaderId, int status) { 4664 switch (status) { 4665 case IDataLoaderStatusListener.DATA_LOADER_BINDING: 4666 case IDataLoaderStatusListener.DATA_LOADER_STOPPED: 4667 case IDataLoaderStatusListener.DATA_LOADER_DESTROYED: 4668 return; 4669 } 4670 4671 if (mDestroyed || mDataLoaderFinished) { 4672 switch (status) { 4673 case IDataLoaderStatusListener.DATA_LOADER_UNRECOVERABLE: 4674 if (systemDataLoader) { 4675 onSystemDataLoaderUnrecoverable(); 4676 } 4677 return; 4678 } 4679 return; 4680 } 4681 try { 4682 switch (status) { 4683 case IDataLoaderStatusListener.DATA_LOADER_BOUND: { 4684 if (manualStartAndDestroy) { 4685 FileSystemControlParcel control = new FileSystemControlParcel(); 4686 control.callback = new FileSystemConnector(addedFiles); 4687 getDataLoader(dataLoaderId).create(dataLoaderId, params.getData(), 4688 control, this); 4689 } 4690 4691 break; 4692 } 4693 case IDataLoaderStatusListener.DATA_LOADER_CREATED: { 4694 if (manualStartAndDestroy) { 4695 // IncrementalFileStorages will call start after all files are 4696 // created in IncFS. 4697 getDataLoader(dataLoaderId).start(dataLoaderId); 4698 } 4699 break; 4700 } 4701 case IDataLoaderStatusListener.DATA_LOADER_STARTED: { 4702 getDataLoader(dataLoaderId).prepareImage( 4703 dataLoaderId, 4704 addedFiles.toArray( 4705 new InstallationFileParcel[addedFiles.size()]), 4706 removedFiles.toArray(new String[removedFiles.size()])); 4707 break; 4708 } 4709 case IDataLoaderStatusListener.DATA_LOADER_IMAGE_READY: { 4710 mDataLoaderFinished = true; 4711 if (hasParentSessionId()) { 4712 mSessionProvider.getSession( 4713 getParentSessionId()).dispatchSessionSealed(); 4714 } else { 4715 dispatchSessionSealed(); 4716 } 4717 if (manualStartAndDestroy) { 4718 getDataLoader(dataLoaderId).destroy(dataLoaderId); 4719 } 4720 break; 4721 } 4722 case IDataLoaderStatusListener.DATA_LOADER_IMAGE_NOT_READY: { 4723 mDataLoaderFinished = true; 4724 dispatchSessionValidationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE, 4725 "Failed to prepare image."); 4726 if (manualStartAndDestroy) { 4727 getDataLoader(dataLoaderId).destroy(dataLoaderId); 4728 } 4729 break; 4730 } 4731 case IDataLoaderStatusListener.DATA_LOADER_UNAVAILABLE: { 4732 // Don't fail or commit the session. Allow caller to commit again. 4733 sendPendingStreaming(mContext, getRemoteStatusReceiver(), sessionId, 4734 "DataLoader unavailable"); 4735 break; 4736 } 4737 case IDataLoaderStatusListener.DATA_LOADER_UNRECOVERABLE: 4738 throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE, 4739 "DataLoader reported unrecoverable failure."); 4740 } 4741 } catch (PackageManagerException e) { 4742 mDataLoaderFinished = true; 4743 dispatchSessionValidationFailure(e.error, ExceptionUtils.getCompleteMessage(e)); 4744 } catch (RemoteException e) { 4745 // In case of streaming failure we don't want to fail or commit the session. 4746 // Just return from this method and allow caller to commit again. 4747 sendPendingStreaming(mContext, getRemoteStatusReceiver(), sessionId, 4748 e.getMessage()); 4749 } 4750 } 4751 }; 4752 4753 if (!manualStartAndDestroy) { 4754 final PerUidReadTimeouts[] perUidReadTimeouts = 4755 mPm.getPerUidReadTimeouts(mPm.snapshotComputer()); 4756 4757 final StorageHealthCheckParams healthCheckParams = new StorageHealthCheckParams(); 4758 healthCheckParams.blockedTimeoutMs = INCREMENTAL_STORAGE_BLOCKED_TIMEOUT_MS; 4759 healthCheckParams.unhealthyTimeoutMs = INCREMENTAL_STORAGE_UNHEALTHY_TIMEOUT_MS; 4760 healthCheckParams.unhealthyMonitoringMs = INCREMENTAL_STORAGE_UNHEALTHY_MONITORING_MS; 4761 4762 final IStorageHealthListener healthListener = new IStorageHealthListener.Stub() { 4763 @Override 4764 public void onHealthStatus(int storageId, int status) { 4765 if (mDestroyed || mDataLoaderFinished) { 4766 return; 4767 } 4768 4769 switch (status) { 4770 case IStorageHealthListener.HEALTH_STATUS_OK: 4771 break; 4772 case IStorageHealthListener.HEALTH_STATUS_READS_PENDING: 4773 case IStorageHealthListener.HEALTH_STATUS_BLOCKED: 4774 if (systemDataLoader) { 4775 // It's OK for ADB data loader to wait for pages. 4776 break; 4777 } 4778 // fallthrough 4779 case IStorageHealthListener.HEALTH_STATUS_UNHEALTHY: 4780 // Even ADB installation can't wait for missing pages for too long. 4781 mDataLoaderFinished = true; 4782 dispatchSessionValidationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE, 4783 "Image is missing pages required for installation."); 4784 break; 4785 } 4786 } 4787 }; 4788 4789 try { 4790 final PackageInfo pkgInfo = mPm.snapshotComputer() 4791 .getPackageInfo(this.params.appPackageName, 0, userId); 4792 final File inheritedDir = 4793 (pkgInfo != null && pkgInfo.applicationInfo != null) ? new File( 4794 pkgInfo.applicationInfo.getCodePath()).getParentFile() : null; 4795 4796 if (mIncrementalFileStorages == null) { 4797 mIncrementalFileStorages = IncrementalFileStorages.initialize(mContext, 4798 stageDir, inheritedDir, params, statusListener, healthCheckParams, 4799 healthListener, addedFiles, perUidReadTimeouts, 4800 new IPackageLoadingProgressCallback.Stub() { 4801 @Override 4802 public void onPackageLoadingProgressChanged(float progress) { 4803 synchronized (mProgressLock) { 4804 mIncrementalProgress = progress; 4805 computeProgressLocked(true); 4806 } 4807 } 4808 }); 4809 } else { 4810 // Retrying commit. 4811 mIncrementalFileStorages.startLoading(params, statusListener, healthCheckParams, 4812 healthListener, perUidReadTimeouts); 4813 } 4814 return false; 4815 } catch (IOException e) { 4816 throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE, e.getMessage(), 4817 e.getCause()); 4818 } 4819 } 4820 4821 final long bindDelayMs = 0; 4822 if (!getDataLoaderManager().bindToDataLoader(sessionId, params.getData(), bindDelayMs, 4823 statusListener)) { 4824 throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE, 4825 "Failed to initialize data loader"); 4826 } 4827 4828 return false; 4829 } 4830 4831 private DataLoaderManager getDataLoaderManager() throws PackageManagerException { 4832 DataLoaderManager dataLoaderManager = mContext.getSystemService(DataLoaderManager.class); 4833 if (dataLoaderManager == null) { 4834 throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE, 4835 "Failed to find data loader manager service"); 4836 } 4837 return dataLoaderManager; 4838 } 4839 4840 private IDataLoader getDataLoader(int dataLoaderId) throws PackageManagerException { 4841 IDataLoader dataLoader = getDataLoaderManager().getDataLoader(dataLoaderId); 4842 if (dataLoader == null) { 4843 throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE, 4844 "Failure to obtain data loader"); 4845 } 4846 return dataLoader; 4847 } 4848 4849 private void dispatchSessionValidationFailure(int error, String detailMessage) { 4850 mHandler.obtainMessage(MSG_SESSION_VALIDATION_FAILURE, error, -1, 4851 detailMessage).sendToTarget(); 4852 } 4853 4854 @GuardedBy("mLock") 4855 private int[] getChildSessionIdsLocked() { 4856 int size = mChildSessions.size(); 4857 if (size == 0) { 4858 return EMPTY_CHILD_SESSION_ARRAY; 4859 } 4860 final int[] childSessionIds = new int[size]; 4861 for (int i = 0; i < size; ++i) { 4862 childSessionIds[i] = mChildSessions.keyAt(i); 4863 } 4864 return childSessionIds; 4865 } 4866 4867 @Override 4868 public int[] getChildSessionIds() { 4869 synchronized (mLock) { 4870 return getChildSessionIdsLocked(); 4871 } 4872 } 4873 4874 private boolean canBeAddedAsChild(int parentCandidate) { 4875 synchronized (mLock) { 4876 return (!hasParentSessionId() || mParentSessionId == parentCandidate) 4877 && !isCommitted() 4878 && !mDestroyed; 4879 } 4880 } 4881 4882 private void acquireTransactionLock() { 4883 if (!mTransactionLock.compareAndSet(false, true)) { 4884 throw new UnsupportedOperationException("Concurrent access not supported"); 4885 } 4886 } 4887 4888 private void releaseTransactionLock() { 4889 mTransactionLock.compareAndSet(true, false); 4890 } 4891 4892 @Override 4893 public void addChildSessionId(int childSessionId) { 4894 if (!params.isMultiPackage) { 4895 throw new IllegalStateException("Single-session " + sessionId + " can't have child."); 4896 } 4897 4898 final PackageInstallerSession childSession = mSessionProvider.getSession(childSessionId); 4899 if (childSession == null) { 4900 throw new IllegalStateException("Unable to add child session " + childSessionId 4901 + " as it does not exist."); 4902 } 4903 if (childSession.params.isMultiPackage) { 4904 throw new IllegalStateException("Multi-session " + childSessionId 4905 + " can't be a child."); 4906 } 4907 if (params.isStaged != childSession.params.isStaged) { 4908 throw new IllegalStateException("Multipackage Inconsistency: session " 4909 + childSession.sessionId + " and session " + sessionId 4910 + " have inconsistent staged settings"); 4911 } 4912 if (params.getEnableRollback() != childSession.params.getEnableRollback()) { 4913 throw new IllegalStateException("Multipackage Inconsistency: session " 4914 + childSession.sessionId + " and session " + sessionId 4915 + " have inconsistent rollback settings"); 4916 } 4917 boolean hasAPK = containsApkSession() || !childSession.isApexSession(); 4918 boolean hasAPEX = sessionContains(s -> s.isApexSession()) || childSession.isApexSession(); 4919 if (!params.isStaged && hasAPK && hasAPEX) { 4920 throw new IllegalStateException("Mix of APK and APEX is not supported for " 4921 + "non-staged multi-package session"); 4922 } 4923 4924 try { 4925 acquireTransactionLock(); 4926 childSession.acquireTransactionLock(); 4927 4928 if (!childSession.canBeAddedAsChild(sessionId)) { 4929 throw new IllegalStateException("Unable to add child session " + childSessionId 4930 + " as it is in an invalid state."); 4931 } 4932 synchronized (mLock) { 4933 assertCallerIsOwnerOrRoot(); 4934 assertPreparedAndNotSealedLocked("addChildSessionId"); 4935 4936 final int indexOfSession = mChildSessions.indexOfKey(childSessionId); 4937 if (indexOfSession >= 0) { 4938 return; 4939 } 4940 childSession.setParentSessionId(this.sessionId); 4941 mChildSessions.put(childSessionId, childSession); 4942 } 4943 } finally { 4944 releaseTransactionLock(); 4945 childSession.releaseTransactionLock(); 4946 } 4947 } 4948 4949 @Override 4950 public void removeChildSessionId(int sessionId) { 4951 synchronized (mLock) { 4952 assertCallerIsOwnerOrRoot(); 4953 assertPreparedAndNotSealedLocked("removeChildSessionId"); 4954 4955 final int indexOfSession = mChildSessions.indexOfKey(sessionId); 4956 if (indexOfSession < 0) { 4957 // not added in the first place; no-op 4958 return; 4959 } 4960 PackageInstallerSession session = mChildSessions.valueAt(indexOfSession); 4961 try { 4962 acquireTransactionLock(); 4963 session.acquireTransactionLock(); 4964 session.setParentSessionId(SessionInfo.INVALID_ID); 4965 mChildSessions.removeAt(indexOfSession); 4966 } finally { 4967 releaseTransactionLock(); 4968 session.releaseTransactionLock(); 4969 } 4970 } 4971 } 4972 4973 /** 4974 * Sets the parent session ID if not already set. 4975 * If {@link SessionInfo#INVALID_ID} is passed, it will be unset. 4976 */ 4977 void setParentSessionId(int parentSessionId) { 4978 synchronized (mLock) { 4979 if (parentSessionId != SessionInfo.INVALID_ID 4980 && mParentSessionId != SessionInfo.INVALID_ID) { 4981 throw new IllegalStateException("The parent of " + sessionId + " is" + " already" 4982 + "set to " + mParentSessionId); 4983 } 4984 this.mParentSessionId = parentSessionId; 4985 } 4986 } 4987 4988 boolean hasParentSessionId() { 4989 synchronized (mLock) { 4990 return mParentSessionId != SessionInfo.INVALID_ID; 4991 } 4992 } 4993 4994 @Override 4995 public int getParentSessionId() { 4996 synchronized (mLock) { 4997 return mParentSessionId; 4998 } 4999 } 5000 5001 private void dispatchSessionFinished(int returnCode, String msg, Bundle extras) { 5002 // Session can be marked as finished due to user rejecting pre approval or commit request, 5003 // any internal error or after successful completion. As such, check whether 5004 // the session is in the preapproval stage or the commit stage. 5005 sendUpdateToRemoteStatusReceiver(returnCode, msg, extras, 5006 /* forPreapproval= */ isPreapprovalRequested() && !isCommitted()); 5007 5008 synchronized (mLock) { 5009 mFinalStatus = returnCode; 5010 mFinalMessage = msg; 5011 } 5012 5013 final boolean success = (returnCode == INSTALL_SUCCEEDED); 5014 5015 // Send broadcast to default launcher only if it's a new install 5016 // TODO(b/144270665): Secure the usage of this broadcast. 5017 final boolean isNewInstall = extras == null || !extras.getBoolean(Intent.EXTRA_REPLACING); 5018 if (success && isNewInstall && mPm.mInstallerService.okToSendBroadcasts()) { 5019 mPm.sendSessionCommitBroadcast(generateInfoScrubbed(true /*icon*/), userId); 5020 } 5021 5022 mCallback.onSessionFinished(this, success); 5023 if (isDataLoaderInstallation()) { 5024 logDataLoaderInstallationSession(returnCode); 5025 } 5026 } 5027 5028 private void sendUpdateToRemoteStatusReceiver(int returnCode, String msg, Bundle extras, 5029 boolean forPreapproval) { 5030 final IntentSender statusReceiver = forPreapproval ? getPreapprovalRemoteStatusReceiver() 5031 : getRemoteStatusReceiver(); 5032 if (statusReceiver != null) { 5033 // Execute observer.onPackageInstalled on different thread as we don't want callers 5034 // inside the system server have to worry about catching the callbacks while they are 5035 // calling into the session 5036 final SomeArgs args = SomeArgs.obtain(); 5037 args.arg1 = getPackageName(); 5038 args.arg2 = msg; 5039 args.arg3 = extras; 5040 args.arg4 = statusReceiver; 5041 args.argi1 = returnCode; 5042 args.argi2 = isPreapprovalRequested() && !isCommitted() ? 1 : 0; 5043 mHandler.obtainMessage(MSG_ON_PACKAGE_INSTALLED, args).sendToTarget(); 5044 } 5045 } 5046 5047 private void dispatchSessionPreapproved() { 5048 final IntentSender target = getPreapprovalRemoteStatusReceiver(); 5049 final Intent intent = new Intent(); 5050 intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId); 5051 intent.putExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_SUCCESS); 5052 intent.putExtra(PackageInstaller.EXTRA_PRE_APPROVAL, true); 5053 try { 5054 final BroadcastOptions options = BroadcastOptions.makeBasic(); 5055 options.setPendingIntentBackgroundActivityLaunchAllowed(false); 5056 target.sendIntent(mContext, 0 /* code */, intent, null /* onFinished */, 5057 null /* handler */, null /* requiredPermission */, options.toBundle()); 5058 } catch (IntentSender.SendIntentException ignored) { 5059 } 5060 } 5061 5062 @Override 5063 public void requestUserPreapproval(@NonNull PreapprovalDetails details, 5064 @NonNull IntentSender statusReceiver) { 5065 validatePreapprovalRequest(details, statusReceiver); 5066 5067 if (!mPm.isPreapprovalRequestAvailable()) { 5068 sendUpdateToRemoteStatusReceiver(INSTALL_FAILED_PRE_APPROVAL_NOT_AVAILABLE, 5069 "Request user pre-approval is currently not available.", /* extras= */null, 5070 /* preapproval= */true); 5071 return; 5072 } 5073 5074 dispatchPreapprovalRequest(); 5075 } 5076 5077 /** 5078 * Validates whether the necessary information (e.g., PreapprovalDetails) are provided. 5079 */ 5080 private void validatePreapprovalRequest(@NonNull PreapprovalDetails details, 5081 @NonNull IntentSender statusReceiver) { 5082 assertCallerIsOwnerOrRoot(); 5083 if (isMultiPackage()) { 5084 throw new IllegalStateException( 5085 "Session " + sessionId + " is a parent of multi-package session and " 5086 + "requestUserPreapproval on the parent session isn't supported."); 5087 } 5088 5089 synchronized (mLock) { 5090 assertPreparedAndNotSealedLocked("request of session " + sessionId); 5091 mPreapprovalDetails = details; 5092 setPreapprovalRemoteStatusReceiver(statusReceiver); 5093 } 5094 } 5095 5096 private void dispatchPreapprovalRequest() { 5097 synchronized (mLock) { 5098 assertPreparedAndNotPreapprovalRequestedLocked("dispatchPreapprovalRequest"); 5099 } 5100 5101 // Mark this session are pre-approval requested, and ready to progress to the next phase. 5102 markAsPreapprovalRequested(); 5103 5104 mHandler.obtainMessage(MSG_PRE_APPROVAL_REQUEST).sendToTarget(); 5105 } 5106 5107 /** 5108 * Marks this session as pre-approval requested, and prevents further related modification. 5109 */ 5110 private void markAsPreapprovalRequested() { 5111 mPreapprovalRequested.set(true); 5112 } 5113 5114 @Override 5115 public boolean isApplicationEnabledSettingPersistent() { 5116 return params.applicationEnabledSettingPersistent; 5117 } 5118 5119 @Override 5120 public boolean isRequestUpdateOwnership() { 5121 return (params.installFlags & PackageManager.INSTALL_REQUEST_UPDATE_OWNERSHIP) != 0; 5122 } 5123 5124 @Override 5125 public void setPreVerifiedDomains(@NonNull DomainSet preVerifiedDomains) { 5126 // First check permissions 5127 final boolean exemptFromPermissionChecks = 5128 (mInstallerUid == Process.ROOT_UID) || (mInstallerUid == Process.SHELL_UID); 5129 if (!exemptFromPermissionChecks) { 5130 final Computer snapshot = mPm.snapshotComputer(); 5131 if (PackageManager.PERMISSION_GRANTED != snapshot.checkUidPermission( 5132 Manifest.permission.ACCESS_INSTANT_APPS, mInstallerUid)) { 5133 throw new SecurityException("You need android.permission.ACCESS_INSTANT_APPS " 5134 + "permission to set pre-verified domains."); 5135 } 5136 ComponentName instantAppInstallerComponent = snapshot.getInstantAppInstallerComponent(); 5137 if (instantAppInstallerComponent == null) { 5138 // Shouldn't happen 5139 throw new IllegalStateException("Instant app installer is not available. " 5140 + "Only the instant app installer can call this API."); 5141 } 5142 if (!instantAppInstallerComponent.getPackageName().equals(getInstallerPackageName())) { 5143 throw new SecurityException("Only the instant app installer can call this API."); 5144 } 5145 } 5146 // Then check size limits 5147 final long preVerifiedDomainsCountLimit = getPreVerifiedDomainsCountLimit(); 5148 if (preVerifiedDomains.getDomains().size() > preVerifiedDomainsCountLimit) { 5149 throw new IllegalArgumentException( 5150 "The number of pre-verified domains have exceeded the maximum of " 5151 + preVerifiedDomainsCountLimit); 5152 } 5153 final long preVerifiedDomainLengthLimit = getPreVerifiedDomainLengthLimit(); 5154 for (String domain : preVerifiedDomains.getDomains()) { 5155 if (domain.length() > preVerifiedDomainLengthLimit) { 5156 throw new IllegalArgumentException( 5157 "Pre-verified domain: [" + domain + " ] exceeds maximum length allowed: " 5158 + preVerifiedDomainLengthLimit); 5159 } 5160 } 5161 // Okay to proceed 5162 synchronized (mLock) { 5163 assertCallerIsOwnerOrRoot(); 5164 assertPreparedAndNotSealedLocked("setPreVerifiedDomains"); 5165 mPreVerifiedDomains = preVerifiedDomains; 5166 } 5167 } 5168 5169 private static long getPreVerifiedDomainsCountLimit() { 5170 final long token = Binder.clearCallingIdentity(); 5171 try { 5172 return DeviceConfig.getLong(NAMESPACE_PACKAGE_MANAGER_SERVICE, 5173 PROPERTY_PRE_VERIFIED_DOMAINS_COUNT_LIMIT, 5174 DEFAULT_PRE_VERIFIED_DOMAINS_COUNT_LIMIT); 5175 } finally { 5176 Binder.restoreCallingIdentity(token); 5177 } 5178 } 5179 5180 private static long getPreVerifiedDomainLengthLimit() { 5181 final long token = Binder.clearCallingIdentity(); 5182 try { 5183 return DeviceConfig.getLong(NAMESPACE_PACKAGE_MANAGER_SERVICE, 5184 PROPERTY_PRE_VERIFIED_DOMAIN_LENGTH_LIMIT, 5185 DEFAULT_PRE_VERIFIED_DOMAIN_LENGTH_LIMIT); 5186 } finally { 5187 Binder.restoreCallingIdentity(token); 5188 } 5189 } 5190 5191 @Override 5192 @Nullable 5193 public DomainSet getPreVerifiedDomains() { 5194 assertCallerIsOwnerOrRoot(); 5195 synchronized (mLock) { 5196 assertPreparedAndNotCommittedOrDestroyedLocked("getPreVerifiedDomains"); 5197 return mPreVerifiedDomains; 5198 } 5199 } 5200 5201 5202 void setSessionReady() { 5203 synchronized (mLock) { 5204 // Do not allow destroyed/failed session to change state 5205 if (mDestroyed || mSessionFailed) return; 5206 mSessionReady = true; 5207 mSessionApplied = false; 5208 mSessionFailed = false; 5209 mSessionErrorCode = PackageManager.INSTALL_UNKNOWN; 5210 mSessionErrorMessage = ""; 5211 } 5212 mCallback.onSessionChanged(this); 5213 } 5214 5215 void setSessionFailed(int errorCode, String errorMessage) { 5216 synchronized (mLock) { 5217 // Do not allow destroyed/failed session to change state 5218 if (mDestroyed || mSessionFailed) return; 5219 mSessionReady = false; 5220 mSessionApplied = false; 5221 mSessionFailed = true; 5222 mSessionErrorCode = errorCode; 5223 mSessionErrorMessage = errorMessage; 5224 Slog.d(TAG, "Marking session " + sessionId + " as failed: " + errorMessage); 5225 } 5226 destroy("Session marked as failed: " + errorMessage); 5227 mCallback.onSessionChanged(this); 5228 } 5229 5230 private void setSessionApplied() { 5231 synchronized (mLock) { 5232 // Do not allow destroyed/failed session to change state 5233 if (mDestroyed || mSessionFailed) return; 5234 mSessionReady = false; 5235 mSessionApplied = true; 5236 mSessionFailed = false; 5237 mSessionErrorCode = INSTALL_SUCCEEDED; 5238 mSessionErrorMessage = ""; 5239 Slog.d(TAG, "Marking session " + sessionId + " as applied"); 5240 } 5241 destroy(null); 5242 mCallback.onSessionChanged(this); 5243 } 5244 5245 /** {@hide} */ 5246 boolean isSessionReady() { 5247 synchronized (mLock) { 5248 return mSessionReady; 5249 } 5250 } 5251 5252 /** {@hide} */ 5253 boolean isSessionApplied() { 5254 synchronized (mLock) { 5255 return mSessionApplied; 5256 } 5257 } 5258 5259 /** {@hide} */ 5260 boolean isSessionFailed() { 5261 synchronized (mLock) { 5262 return mSessionFailed; 5263 } 5264 } 5265 5266 /** {@hide} */ 5267 int getSessionErrorCode() { 5268 synchronized (mLock) { 5269 return mSessionErrorCode; 5270 } 5271 } 5272 5273 /** {@hide} */ 5274 String getSessionErrorMessage() { 5275 synchronized (mLock) { 5276 return mSessionErrorMessage; 5277 } 5278 } 5279 5280 void registerUnarchivalListener(IntentSender intentSender) { 5281 synchronized (mLock) { 5282 this.mUnarchivalListeners.add(intentSender); 5283 } 5284 } 5285 5286 Set<IntentSender> getUnarchivalListeners() { 5287 synchronized (mLock) { 5288 return new ArraySet<>(mUnarchivalListeners); 5289 } 5290 } 5291 5292 void reportUnarchivalStatus(@UnarchivalStatus int status, int unarchiveId, 5293 long requiredStorageBytes, PendingIntent userActionIntent) { 5294 if (getUnarchivalStatus() != UNARCHIVAL_STATUS_UNSET) { 5295 throw new IllegalStateException( 5296 TextUtils.formatSimple( 5297 "Unarchival status for ID %s has already been set or a session has " 5298 + "been created for it already by the caller.", 5299 unarchiveId)); 5300 } 5301 mUnarchivalStatus = status; 5302 5303 // Execute expensive calls outside the sync block. 5304 mPm.mHandler.post( 5305 () -> mPm.mInstallerService.mPackageArchiver.notifyUnarchivalListener(status, 5306 getInstallerPackageName(), params.appPackageName, requiredStorageBytes, 5307 userActionIntent, getUnarchivalListeners(), userId)); 5308 if (status != UNARCHIVAL_OK) { 5309 Binder.withCleanCallingIdentity(this::abandon); 5310 } 5311 } 5312 5313 @UnarchivalStatus 5314 int getUnarchivalStatus() { 5315 return this.mUnarchivalStatus; 5316 } 5317 5318 /** 5319 * Free up storage used by this session and its children. 5320 * Must not be called on a child session. 5321 */ 5322 private void destroy(String reason) { 5323 // TODO(b/173194203): destroy() is called indirectly by 5324 // PackageInstallerService#restoreAndApplyStagedSessionIfNeeded on an orphan child session. 5325 // Enable this assertion when we figure out a better way to clean up orphan sessions. 5326 // assertNotChild("destroy"); 5327 5328 // TODO(b/173194203): destroyInternal() should be used by destroy() only. 5329 // For the sake of consistency, a session should be destroyed as a whole. The caller 5330 // should always call destroy() for cleanup without knowing it has child sessions or not. 5331 destroyInternal(reason); 5332 for (PackageInstallerSession child : getChildSessions()) { 5333 child.destroyInternal(reason); 5334 } 5335 } 5336 5337 /** 5338 * Free up storage used by this session. 5339 */ 5340 private void destroyInternal(String reason) { 5341 if (reason != null) { 5342 Slog.i(TAG, 5343 "Session [" + this.sessionId + "] was destroyed because of [" + reason + "]"); 5344 } 5345 final IncrementalFileStorages incrementalFileStorages; 5346 synchronized (mLock) { 5347 mSealed = true; 5348 if (!params.isStaged) { 5349 mDestroyed = true; 5350 } 5351 // Force shut down all bridges 5352 for (RevocableFileDescriptor fd : mFds) { 5353 fd.revoke(); 5354 } 5355 for (FileBridge bridge : mBridges) { 5356 bridge.forceClose(); 5357 } 5358 incrementalFileStorages = mIncrementalFileStorages; 5359 mIncrementalFileStorages = null; 5360 } 5361 try { 5362 if (incrementalFileStorages != null) { 5363 incrementalFileStorages.cleanUpAndMarkComplete(); 5364 } 5365 if (stageDir != null) { 5366 final String tempPackageName = stageDir.getName(); 5367 mInstaller.rmPackageDir(tempPackageName, stageDir.getAbsolutePath()); 5368 } 5369 } catch (InstallerException ignored) { 5370 } 5371 } 5372 5373 void dump(IndentingPrintWriter pw) { 5374 synchronized (mLock) { 5375 dumpLocked(pw); 5376 } 5377 } 5378 5379 @GuardedBy("mLock") 5380 private void dumpLocked(IndentingPrintWriter pw) { 5381 pw.println("Session " + sessionId + ":"); 5382 pw.increaseIndent(); 5383 5384 pw.printPair("userId", userId); 5385 pw.printPair("mOriginalInstallerUid", mOriginalInstallerUid); 5386 pw.printPair("mOriginalInstallerPackageName", mOriginalInstallerPackageName); 5387 pw.printPair("installerPackageName", mInstallSource.mInstallerPackageName); 5388 pw.printPair("installInitiatingPackageName", mInstallSource.mInitiatingPackageName); 5389 pw.printPair("installOriginatingPackageName", mInstallSource.mOriginatingPackageName); 5390 pw.printPair("mInstallerUid", mInstallerUid); 5391 pw.printPair("createdMillis", createdMillis); 5392 pw.printPair("updatedMillis", updatedMillis); 5393 pw.printPair("committedMillis", committedMillis); 5394 pw.printPair("stageDir", stageDir); 5395 pw.printPair("stageCid", stageCid); 5396 pw.println(); 5397 5398 params.dump(pw); 5399 5400 final float clientProgress; 5401 final float progress; 5402 synchronized (mProgressLock) { 5403 clientProgress = mClientProgress; 5404 progress = mProgress; 5405 } 5406 pw.printPair("mClientProgress", clientProgress); 5407 pw.printPair("mProgress", progress); 5408 pw.printPair("mCommitted", mCommitted); 5409 pw.printPair("mPreapprovalRequested", mPreapprovalRequested); 5410 pw.printPair("mSealed", mSealed); 5411 pw.printPair("mPermissionsManuallyAccepted", mPermissionsManuallyAccepted); 5412 pw.printPair("mStageDirInUse", mStageDirInUse); 5413 pw.printPair("mDestroyed", mDestroyed); 5414 pw.printPair("mFds", mFds.size()); 5415 pw.printPair("mBridges", mBridges.size()); 5416 pw.printPair("mFinalStatus", mFinalStatus); 5417 pw.printPair("mFinalMessage", mFinalMessage); 5418 pw.printPair("params.isMultiPackage", params.isMultiPackage); 5419 pw.printPair("params.isStaged", params.isStaged); 5420 pw.printPair("mParentSessionId", mParentSessionId); 5421 pw.printPair("mChildSessionIds", getChildSessionIdsLocked()); 5422 pw.printPair("mSessionApplied", mSessionApplied); 5423 pw.printPair("mSessionFailed", mSessionFailed); 5424 pw.printPair("mSessionReady", mSessionReady); 5425 pw.printPair("mSessionErrorCode", mSessionErrorCode); 5426 pw.printPair("mSessionErrorMessage", mSessionErrorMessage); 5427 pw.printPair("mPreapprovalDetails", mPreapprovalDetails); 5428 if (mPreVerifiedDomains != null) { 5429 pw.printPair("mPreVerifiedDomains", mPreVerifiedDomains); 5430 } 5431 pw.println(); 5432 5433 pw.decreaseIndent(); 5434 } 5435 5436 /** 5437 * This method doesn't change internal states and is safe to call outside the lock. 5438 */ 5439 private static void sendOnUserActionRequired(Context context, IntentSender target, 5440 int sessionId, Intent intent) { 5441 final Intent fillIn = new Intent(); 5442 fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId); 5443 fillIn.putExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_PENDING_USER_ACTION); 5444 fillIn.putExtra(PackageInstaller.EXTRA_PRE_APPROVAL, 5445 PackageInstaller.ACTION_CONFIRM_PRE_APPROVAL.equals(intent.getAction())); 5446 fillIn.putExtra(Intent.EXTRA_INTENT, intent); 5447 try { 5448 final BroadcastOptions options = BroadcastOptions.makeBasic(); 5449 options.setPendingIntentBackgroundActivityLaunchAllowed(false); 5450 target.sendIntent(context, 0, fillIn, null /* onFinished */, 5451 null /* handler */, null /* requiredPermission */, options.toBundle()); 5452 } catch (IntentSender.SendIntentException ignored) { 5453 } 5454 } 5455 5456 /** 5457 * This method doesn't change internal states and is safe to call outside the lock. 5458 */ 5459 private static void sendOnPackageInstalled(Context context, IntentSender target, int sessionId, 5460 boolean showNotification, int userId, String basePackageName, int returnCode, 5461 boolean isPreapproval, String msg, Bundle extras) { 5462 if (INSTALL_SUCCEEDED == returnCode && showNotification) { 5463 boolean update = (extras != null) && extras.getBoolean(Intent.EXTRA_REPLACING); 5464 Notification notification = PackageInstallerService.buildSuccessNotification(context, 5465 getDeviceOwnerInstalledPackageMsg(context, update), 5466 basePackageName, 5467 userId); 5468 if (notification != null) { 5469 NotificationManager notificationManager = (NotificationManager) 5470 context.getSystemService(Context.NOTIFICATION_SERVICE); 5471 notificationManager.notify(basePackageName, 5472 SystemMessageProto.SystemMessage.NOTE_PACKAGE_STATE, 5473 notification); 5474 } 5475 } 5476 final Intent fillIn = new Intent(); 5477 fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, basePackageName); 5478 fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId); 5479 fillIn.putExtra(PackageInstaller.EXTRA_STATUS, 5480 PackageManager.installStatusToPublicStatus(returnCode)); 5481 fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, 5482 PackageManager.installStatusToString(returnCode, msg)); 5483 fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode); 5484 fillIn.putExtra(PackageInstaller.EXTRA_PRE_APPROVAL, isPreapproval); 5485 if (extras != null) { 5486 final String existing = extras.getString( 5487 PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE); 5488 if (!TextUtils.isEmpty(existing)) { 5489 fillIn.putExtra(PackageInstaller.EXTRA_OTHER_PACKAGE_NAME, existing); 5490 } 5491 ArrayList<String> warnings = extras.getStringArrayList(PackageInstaller.EXTRA_WARNINGS); 5492 if (!ArrayUtils.isEmpty(warnings)) { 5493 fillIn.putStringArrayListExtra(PackageInstaller.EXTRA_WARNINGS, warnings); 5494 } 5495 } 5496 try { 5497 final BroadcastOptions options = BroadcastOptions.makeBasic(); 5498 options.setPendingIntentBackgroundActivityLaunchAllowed(false); 5499 target.sendIntent(context, 0, fillIn, null /* onFinished */, 5500 null /* handler */, null /* requiredPermission */, options.toBundle()); 5501 } catch (IntentSender.SendIntentException ignored) { 5502 } 5503 } 5504 5505 private static String getDeviceOwnerInstalledPackageMsg(Context context, boolean update) { 5506 DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class); 5507 return update 5508 ? dpm.getResources().getString(PACKAGE_UPDATED_BY_DO, 5509 () -> context.getString(R.string.package_updated_device_owner)) 5510 : dpm.getResources().getString(PACKAGE_INSTALLED_BY_DO, 5511 () -> context.getString(R.string.package_installed_device_owner)); 5512 } 5513 5514 /** 5515 * This method doesn't change internal states and is safe to call outside the lock. 5516 */ 5517 private static void sendPendingStreaming(Context context, IntentSender target, int sessionId, 5518 @Nullable String cause) { 5519 if (target == null) { 5520 Slog.e(TAG, "Missing receiver for pending streaming status."); 5521 return; 5522 } 5523 5524 final Intent intent = new Intent(); 5525 intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId); 5526 intent.putExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_PENDING_STREAMING); 5527 if (!TextUtils.isEmpty(cause)) { 5528 intent.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, 5529 "Staging Image Not Ready [" + cause + "]"); 5530 } else { 5531 intent.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, "Staging Image Not Ready"); 5532 } 5533 try { 5534 final BroadcastOptions options = BroadcastOptions.makeBasic(); 5535 options.setPendingIntentBackgroundActivityLaunchAllowed(false); 5536 target.sendIntent(context, 0, intent, null /* onFinished */, 5537 null /* handler */, null /* requiredPermission */, options.toBundle()); 5538 } catch (IntentSender.SendIntentException ignored) { 5539 } 5540 } 5541 5542 private static void writePermissionsLocked(@NonNull TypedXmlSerializer out, 5543 @NonNull SessionParams params) throws IOException { 5544 var permissionStates = params.getPermissionStates(); 5545 for (int index = 0; index < permissionStates.size(); index++) { 5546 var permissionName = permissionStates.keyAt(index); 5547 var state = permissionStates.valueAt(index); 5548 String tag = state == SessionParams.PERMISSION_STATE_GRANTED ? TAG_GRANT_PERMISSION 5549 : TAG_DENY_PERMISSION; 5550 out.startTag(null, tag); 5551 writeStringAttribute(out, ATTR_NAME, permissionName); 5552 out.endTag(null, tag); 5553 } 5554 } 5555 5556 private static void writeWhitelistedRestrictedPermissionsLocked(@NonNull TypedXmlSerializer out, 5557 @Nullable List<String> whitelistedRestrictedPermissions) throws IOException { 5558 if (whitelistedRestrictedPermissions != null) { 5559 final int permissionCount = whitelistedRestrictedPermissions.size(); 5560 for (int i = 0; i < permissionCount; i++) { 5561 out.startTag(null, TAG_WHITELISTED_RESTRICTED_PERMISSION); 5562 writeStringAttribute(out, ATTR_NAME, whitelistedRestrictedPermissions.get(i)); 5563 out.endTag(null, TAG_WHITELISTED_RESTRICTED_PERMISSION); 5564 } 5565 } 5566 } 5567 5568 private static void writeAutoRevokePermissionsMode(@NonNull TypedXmlSerializer out, int mode) 5569 throws IOException { 5570 out.startTag(null, TAG_AUTO_REVOKE_PERMISSIONS_MODE); 5571 out.attributeInt(null, ATTR_MODE, mode); 5572 out.endTag(null, TAG_AUTO_REVOKE_PERMISSIONS_MODE); 5573 } 5574 5575 5576 private static File buildAppIconFile(int sessionId, @NonNull File sessionsDir) { 5577 return new File(sessionsDir, "app_icon." + sessionId + ".png"); 5578 } 5579 5580 /** 5581 * Write this session to a {@link TypedXmlSerializer}. 5582 * 5583 * @param out Where to write the session to 5584 * @param sessionsDir The directory containing the sessions 5585 */ 5586 void write(@NonNull TypedXmlSerializer out, @NonNull File sessionsDir) throws IOException { 5587 synchronized (mLock) { 5588 if (mDestroyed && !params.isStaged) { 5589 return; 5590 } 5591 5592 out.startTag(null, TAG_SESSION); 5593 5594 out.attributeInt(null, ATTR_SESSION_ID, sessionId); 5595 out.attributeInt(null, ATTR_USER_ID, userId); 5596 writeStringAttribute(out, ATTR_INSTALLER_PACKAGE_NAME, 5597 mInstallSource.mInstallerPackageName); 5598 out.attributeInt(null, ATTR_INSTALLER_PACKAGE_UID, mInstallSource.mInstallerPackageUid); 5599 writeStringAttribute(out, ATTR_UPDATE_OWNER_PACKAGE_NAME, 5600 mInstallSource.mUpdateOwnerPackageName); 5601 writeStringAttribute(out, ATTR_INSTALLER_ATTRIBUTION_TAG, 5602 mInstallSource.mInstallerAttributionTag); 5603 out.attributeInt(null, ATTR_INSTALLER_UID, mInstallerUid); 5604 writeStringAttribute(out, ATTR_INITIATING_PACKAGE_NAME, 5605 mInstallSource.mInitiatingPackageName); 5606 writeStringAttribute(out, ATTR_ORIGINATING_PACKAGE_NAME, 5607 mInstallSource.mOriginatingPackageName); 5608 out.attributeLong(null, ATTR_CREATED_MILLIS, createdMillis); 5609 out.attributeLong(null, ATTR_UPDATED_MILLIS, updatedMillis); 5610 out.attributeLong(null, ATTR_COMMITTED_MILLIS, committedMillis); 5611 if (stageDir != null) { 5612 writeStringAttribute(out, ATTR_SESSION_STAGE_DIR, 5613 stageDir.getAbsolutePath()); 5614 } 5615 if (stageCid != null) { 5616 writeStringAttribute(out, ATTR_SESSION_STAGE_CID, stageCid); 5617 } 5618 writeBooleanAttribute(out, ATTR_PREPARED, mPrepared); 5619 writeBooleanAttribute(out, ATTR_COMMITTED, isCommitted()); 5620 writeBooleanAttribute(out, ATTR_DESTROYED, mDestroyed); 5621 writeBooleanAttribute(out, ATTR_SEALED, mSealed); 5622 5623 writeBooleanAttribute(out, ATTR_MULTI_PACKAGE, params.isMultiPackage); 5624 writeBooleanAttribute(out, ATTR_STAGED_SESSION, params.isStaged); 5625 writeBooleanAttribute(out, ATTR_IS_READY, mSessionReady); 5626 writeBooleanAttribute(out, ATTR_IS_FAILED, mSessionFailed); 5627 writeBooleanAttribute(out, ATTR_IS_APPLIED, mSessionApplied); 5628 out.attributeInt(null, ATTR_PACKAGE_SOURCE, params.packageSource); 5629 out.attributeInt(null, ATTR_SESSION_ERROR_CODE, mSessionErrorCode); 5630 writeStringAttribute(out, ATTR_SESSION_ERROR_MESSAGE, mSessionErrorMessage); 5631 // TODO(patb,109941548): avoid writing to xml and instead infer / validate this after 5632 // we've read all sessions. 5633 out.attributeInt(null, ATTR_PARENT_SESSION_ID, mParentSessionId); 5634 out.attributeInt(null, ATTR_MODE, params.mode); 5635 out.attributeInt(null, ATTR_INSTALL_FLAGS, params.installFlags); 5636 out.attributeInt(null, ATTR_INSTALL_LOCATION, params.installLocation); 5637 out.attributeLong(null, ATTR_SIZE_BYTES, params.sizeBytes); 5638 writeStringAttribute(out, ATTR_APP_PACKAGE_NAME, params.appPackageName); 5639 writeStringAttribute(out, ATTR_APP_LABEL, params.appLabel); 5640 writeUriAttribute(out, ATTR_ORIGINATING_URI, params.originatingUri); 5641 out.attributeInt(null, ATTR_ORIGINATING_UID, params.originatingUid); 5642 writeUriAttribute(out, ATTR_REFERRER_URI, params.referrerUri); 5643 writeStringAttribute(out, ATTR_ABI_OVERRIDE, params.abiOverride); 5644 writeStringAttribute(out, ATTR_VOLUME_UUID, params.volumeUuid); 5645 out.attributeInt(null, ATTR_INSTALL_REASON, params.installReason); 5646 writeBooleanAttribute(out, ATTR_APPLICATION_ENABLED_SETTING_PERSISTENT, 5647 params.applicationEnabledSettingPersistent); 5648 5649 final boolean isDataLoader = params.dataLoaderParams != null; 5650 writeBooleanAttribute(out, ATTR_IS_DATALOADER, isDataLoader); 5651 if (isDataLoader) { 5652 out.attributeInt(null, ATTR_DATALOADER_TYPE, params.dataLoaderParams.getType()); 5653 writeStringAttribute(out, ATTR_DATALOADER_PACKAGE_NAME, 5654 params.dataLoaderParams.getComponentName().getPackageName()); 5655 writeStringAttribute(out, ATTR_DATALOADER_CLASS_NAME, 5656 params.dataLoaderParams.getComponentName().getClassName()); 5657 writeStringAttribute(out, ATTR_DATALOADER_ARGUMENTS, 5658 params.dataLoaderParams.getArguments()); 5659 } 5660 5661 writePermissionsLocked(out, params); 5662 writeWhitelistedRestrictedPermissionsLocked(out, 5663 params.whitelistedRestrictedPermissions); 5664 writeAutoRevokePermissionsMode(out, params.autoRevokePermissionsMode); 5665 5666 // Persist app icon if changed since last written 5667 File appIconFile = buildAppIconFile(sessionId, sessionsDir); 5668 if (params.appIcon == null && appIconFile.exists()) { 5669 appIconFile.delete(); 5670 } else if (params.appIcon != null 5671 && appIconFile.lastModified() != params.appIconLastModified) { 5672 if (LOGD) Slog.w(TAG, "Writing changed icon " + appIconFile); 5673 FileOutputStream os = null; 5674 try { 5675 os = new FileOutputStream(appIconFile); 5676 params.appIcon.compress(Bitmap.CompressFormat.PNG, 90, os); 5677 } catch (IOException e) { 5678 Slog.w(TAG, "Failed to write icon " + appIconFile + ": " + e.getMessage()); 5679 } finally { 5680 IoUtils.closeQuietly(os); 5681 } 5682 5683 params.appIconLastModified = appIconFile.lastModified(); 5684 } 5685 final int[] childSessionIds = getChildSessionIdsLocked(); 5686 for (int childSessionId : childSessionIds) { 5687 out.startTag(null, TAG_CHILD_SESSION); 5688 out.attributeInt(null, ATTR_SESSION_ID, childSessionId); 5689 out.endTag(null, TAG_CHILD_SESSION); 5690 } 5691 5692 final InstallationFile[] files = getInstallationFilesLocked(); 5693 for (InstallationFile file : files) { 5694 out.startTag(null, TAG_SESSION_FILE); 5695 out.attributeInt(null, ATTR_LOCATION, file.getLocation()); 5696 writeStringAttribute(out, ATTR_NAME, file.getName()); 5697 out.attributeLong(null, ATTR_LENGTH_BYTES, file.getLengthBytes()); 5698 writeByteArrayAttribute(out, ATTR_METADATA, file.getMetadata()); 5699 writeByteArrayAttribute(out, ATTR_SIGNATURE, file.getSignature()); 5700 out.endTag(null, TAG_SESSION_FILE); 5701 } 5702 5703 for (int i = 0, isize = mChecksums.size(); i < isize; ++i) { 5704 final String fileName = mChecksums.keyAt(i); 5705 final PerFileChecksum perFileChecksum = mChecksums.valueAt(i); 5706 final Checksum[] checksums = perFileChecksum.getChecksums(); 5707 for (Checksum checksum : checksums) { 5708 out.startTag(null, TAG_SESSION_CHECKSUM); 5709 writeStringAttribute(out, ATTR_NAME, fileName); 5710 out.attributeInt(null, ATTR_CHECKSUM_KIND, checksum.getType()); 5711 writeByteArrayAttribute(out, ATTR_CHECKSUM_VALUE, checksum.getValue()); 5712 out.endTag(null, TAG_SESSION_CHECKSUM); 5713 } 5714 } 5715 for (int i = 0, isize = mChecksums.size(); i < isize; ++i) { 5716 final String fileName = mChecksums.keyAt(i); 5717 final PerFileChecksum perFileChecksum = mChecksums.valueAt(i); 5718 final byte[] signature = perFileChecksum.getSignature(); 5719 if (signature == null || signature.length == 0) { 5720 continue; 5721 } 5722 out.startTag(null, TAG_SESSION_CHECKSUM_SIGNATURE); 5723 writeStringAttribute(out, ATTR_NAME, fileName); 5724 writeByteArrayAttribute(out, ATTR_SIGNATURE, signature); 5725 out.endTag(null, TAG_SESSION_CHECKSUM_SIGNATURE); 5726 } 5727 if (mPreVerifiedDomains != null) { 5728 for (String domain : mPreVerifiedDomains.getDomains()) { 5729 out.startTag(null, TAG_PRE_VERIFIED_DOMAINS); 5730 writeStringAttribute(out, ATTR_DOMAIN, domain); 5731 out.endTag(null, TAG_PRE_VERIFIED_DOMAINS); 5732 } 5733 } 5734 } 5735 5736 out.endTag(null, TAG_SESSION); 5737 } 5738 5739 // Validity check to be performed when the session is restored from an external file. Only one 5740 // of the session states should be true, or none of them. 5741 private static boolean isStagedSessionStateValid(boolean isReady, boolean isApplied, 5742 boolean isFailed) { 5743 return (!isReady && !isApplied && !isFailed) 5744 || (isReady && !isApplied && !isFailed) 5745 || (!isReady && isApplied && !isFailed) 5746 || (!isReady && !isApplied && isFailed); 5747 } 5748 5749 /** 5750 * Read new session from a {@link TypedXmlPullParser xml description} and create it. 5751 * 5752 * @param in The source of the description 5753 * @param callback Callback the session uses to notify about changes of it's state 5754 * @param context Context to be used by the session 5755 * @param pm PackageManager to use by the session 5756 * @param installerThread Thread to be used for callbacks of this session 5757 * @param sessionsDir The directory the sessions are stored in 5758 * 5759 * @param sessionProvider to get the other PackageInstallerSession instance by sessionId. 5760 * @return The newly created session 5761 */ 5762 public static PackageInstallerSession readFromXml(@NonNull TypedXmlPullParser in, 5763 @NonNull PackageInstallerService.InternalCallback callback, @NonNull Context context, 5764 @NonNull PackageManagerService pm, Looper installerThread, 5765 @NonNull StagingManager stagingManager, @NonNull File sessionsDir, 5766 @NonNull PackageSessionProvider sessionProvider, 5767 @NonNull SilentUpdatePolicy silentUpdatePolicy) 5768 throws IOException, XmlPullParserException { 5769 final int sessionId = in.getAttributeInt(null, ATTR_SESSION_ID); 5770 final int userId = in.getAttributeInt(null, ATTR_USER_ID); 5771 final String installerPackageName = readStringAttribute(in, ATTR_INSTALLER_PACKAGE_NAME); 5772 final int installPackageUid = in.getAttributeInt(null, ATTR_INSTALLER_PACKAGE_UID, 5773 INVALID_UID); 5774 final String updateOwnerPackageName = readStringAttribute(in, 5775 ATTR_UPDATE_OWNER_PACKAGE_NAME); 5776 final String installerAttributionTag = readStringAttribute(in, 5777 ATTR_INSTALLER_ATTRIBUTION_TAG); 5778 final int installerUid = in.getAttributeInt(null, ATTR_INSTALLER_UID, pm.snapshotComputer() 5779 .getPackageUid(installerPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, 5780 userId)); 5781 final String installInitiatingPackageName = 5782 readStringAttribute(in, ATTR_INITIATING_PACKAGE_NAME); 5783 final String installOriginatingPackageName = 5784 readStringAttribute(in, ATTR_ORIGINATING_PACKAGE_NAME); 5785 final long createdMillis = in.getAttributeLong(null, ATTR_CREATED_MILLIS); 5786 long updatedMillis = in.getAttributeLong(null, ATTR_UPDATED_MILLIS); 5787 final long committedMillis = in.getAttributeLong(null, ATTR_COMMITTED_MILLIS, 0L); 5788 final String stageDirRaw = readStringAttribute(in, ATTR_SESSION_STAGE_DIR); 5789 final File stageDir = (stageDirRaw != null) ? new File(stageDirRaw) : null; 5790 final String stageCid = readStringAttribute(in, ATTR_SESSION_STAGE_CID); 5791 final boolean prepared = in.getAttributeBoolean(null, ATTR_PREPARED, true); 5792 final boolean committed = in.getAttributeBoolean(null, ATTR_COMMITTED, false); 5793 final boolean destroyed = in.getAttributeBoolean(null, ATTR_DESTROYED, false); 5794 final boolean sealed = in.getAttributeBoolean(null, ATTR_SEALED, false); 5795 final int parentSessionId = in.getAttributeInt(null, ATTR_PARENT_SESSION_ID, 5796 SessionInfo.INVALID_ID); 5797 5798 final SessionParams params = new SessionParams( 5799 SessionParams.MODE_INVALID); 5800 params.isMultiPackage = in.getAttributeBoolean(null, ATTR_MULTI_PACKAGE, false); 5801 params.isStaged = in.getAttributeBoolean(null, ATTR_STAGED_SESSION, false); 5802 params.mode = in.getAttributeInt(null, ATTR_MODE); 5803 params.installFlags = in.getAttributeInt(null, ATTR_INSTALL_FLAGS); 5804 params.installLocation = in.getAttributeInt(null, ATTR_INSTALL_LOCATION); 5805 params.sizeBytes = in.getAttributeLong(null, ATTR_SIZE_BYTES); 5806 params.appPackageName = readStringAttribute(in, ATTR_APP_PACKAGE_NAME); 5807 params.appIcon = readBitmapAttribute(in, ATTR_APP_ICON); 5808 params.appLabel = readStringAttribute(in, ATTR_APP_LABEL); 5809 params.originatingUri = readUriAttribute(in, ATTR_ORIGINATING_URI); 5810 params.originatingUid = 5811 in.getAttributeInt(null, ATTR_ORIGINATING_UID, SessionParams.UID_UNKNOWN); 5812 params.referrerUri = readUriAttribute(in, ATTR_REFERRER_URI); 5813 params.abiOverride = readStringAttribute(in, ATTR_ABI_OVERRIDE); 5814 params.volumeUuid = readStringAttribute(in, ATTR_VOLUME_UUID); 5815 params.installReason = in.getAttributeInt(null, ATTR_INSTALL_REASON); 5816 params.packageSource = in.getAttributeInt(null, ATTR_PACKAGE_SOURCE); 5817 params.applicationEnabledSettingPersistent = in.getAttributeBoolean(null, 5818 ATTR_APPLICATION_ENABLED_SETTING_PERSISTENT, false); 5819 5820 if (in.getAttributeBoolean(null, ATTR_IS_DATALOADER, false)) { 5821 params.dataLoaderParams = new DataLoaderParams( 5822 in.getAttributeInt(null, ATTR_DATALOADER_TYPE), 5823 new ComponentName( 5824 readStringAttribute(in, ATTR_DATALOADER_PACKAGE_NAME), 5825 readStringAttribute(in, ATTR_DATALOADER_CLASS_NAME)), 5826 readStringAttribute(in, ATTR_DATALOADER_ARGUMENTS)); 5827 } 5828 5829 final File appIconFile = buildAppIconFile(sessionId, sessionsDir); 5830 if (appIconFile.exists()) { 5831 params.appIcon = BitmapFactory.decodeFile(appIconFile.getAbsolutePath()); 5832 params.appIconLastModified = appIconFile.lastModified(); 5833 } 5834 final boolean isReady = in.getAttributeBoolean(null, ATTR_IS_READY, false); 5835 final boolean isFailed = in.getAttributeBoolean(null, ATTR_IS_FAILED, false); 5836 final boolean isApplied = in.getAttributeBoolean(null, ATTR_IS_APPLIED, false); 5837 final int sessionErrorCode = in.getAttributeInt(null, ATTR_SESSION_ERROR_CODE, 5838 PackageManager.INSTALL_UNKNOWN); 5839 final String sessionErrorMessage = readStringAttribute(in, ATTR_SESSION_ERROR_MESSAGE); 5840 5841 if (!isStagedSessionStateValid(isReady, isApplied, isFailed)) { 5842 throw new IllegalArgumentException("Can't restore staged session with invalid state."); 5843 } 5844 5845 // Parse sub tags of this session, typically used for repeated values / arrays. 5846 // Sub tags can come in any order, therefore we need to keep track of what we find while 5847 // parsing and only set the right values at the end. 5848 5849 // Store the current depth. We should stop parsing when we reach an end tag at the same 5850 // depth. 5851 List<String> legacyGrantedRuntimePermissions = new ArrayList<>(); 5852 ArraySet<String> grantPermissions = new ArraySet<>(); 5853 ArraySet<String> denyPermissions = new ArraySet<>(); 5854 List<String> whitelistedRestrictedPermissions = new ArrayList<>(); 5855 int autoRevokePermissionsMode = MODE_DEFAULT; 5856 IntArray childSessionIds = new IntArray(); 5857 List<InstallationFile> files = new ArrayList<>(); 5858 ArrayMap<String, List<Checksum>> checksums = new ArrayMap<>(); 5859 ArrayMap<String, byte[]> signatures = new ArrayMap<>(); 5860 ArraySet<String> preVerifiedDomainSet = new ArraySet<>(); 5861 int outerDepth = in.getDepth(); 5862 int type; 5863 while ((type = in.next()) != XmlPullParser.END_DOCUMENT 5864 && (type != XmlPullParser.END_TAG || in.getDepth() > outerDepth)) { 5865 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 5866 continue; 5867 } 5868 switch (in.getName()) { 5869 case TAG_GRANTED_RUNTIME_PERMISSION: 5870 legacyGrantedRuntimePermissions.add(readStringAttribute(in, ATTR_NAME)); 5871 break; 5872 case TAG_GRANT_PERMISSION: 5873 grantPermissions.add(readStringAttribute(in, ATTR_NAME)); 5874 break; 5875 case TAG_DENY_PERMISSION: 5876 denyPermissions.add(readStringAttribute(in, ATTR_NAME)); 5877 break; 5878 case TAG_WHITELISTED_RESTRICTED_PERMISSION: 5879 whitelistedRestrictedPermissions.add(readStringAttribute(in, ATTR_NAME)); 5880 break; 5881 case TAG_AUTO_REVOKE_PERMISSIONS_MODE: 5882 autoRevokePermissionsMode = in.getAttributeInt(null, ATTR_MODE); 5883 break; 5884 case TAG_CHILD_SESSION: 5885 childSessionIds.add(in.getAttributeInt(null, ATTR_SESSION_ID, 5886 SessionInfo.INVALID_ID)); 5887 break; 5888 case TAG_SESSION_FILE: 5889 files.add(new InstallationFile( 5890 in.getAttributeInt(null, ATTR_LOCATION, 0), 5891 readStringAttribute(in, ATTR_NAME), 5892 in.getAttributeLong(null, ATTR_LENGTH_BYTES, -1), 5893 readByteArrayAttribute(in, ATTR_METADATA), 5894 readByteArrayAttribute(in, ATTR_SIGNATURE))); 5895 break; 5896 case TAG_SESSION_CHECKSUM: 5897 final String fileName = readStringAttribute(in, ATTR_NAME); 5898 final Checksum checksum = new Checksum( 5899 in.getAttributeInt(null, ATTR_CHECKSUM_KIND, 0), 5900 readByteArrayAttribute(in, ATTR_CHECKSUM_VALUE)); 5901 5902 List<Checksum> fileChecksums = checksums.get(fileName); 5903 if (fileChecksums == null) { 5904 fileChecksums = new ArrayList<>(); 5905 checksums.put(fileName, fileChecksums); 5906 } 5907 fileChecksums.add(checksum); 5908 break; 5909 case TAG_SESSION_CHECKSUM_SIGNATURE: 5910 final String fileName1 = readStringAttribute(in, ATTR_NAME); 5911 final byte[] signature = readByteArrayAttribute(in, ATTR_SIGNATURE); 5912 signatures.put(fileName1, signature); 5913 break; 5914 case TAG_PRE_VERIFIED_DOMAINS: 5915 preVerifiedDomainSet.add(readStringAttribute(in, ATTR_DOMAIN)); 5916 break; 5917 } 5918 } 5919 5920 if (legacyGrantedRuntimePermissions.size() > 0) { 5921 params.setPermissionStates(legacyGrantedRuntimePermissions, Collections.emptyList()); 5922 } else { 5923 params.setPermissionStates(grantPermissions, denyPermissions); 5924 } 5925 5926 if (whitelistedRestrictedPermissions.size() > 0) { 5927 params.whitelistedRestrictedPermissions = whitelistedRestrictedPermissions; 5928 } 5929 5930 params.autoRevokePermissionsMode = autoRevokePermissionsMode; 5931 5932 int[] childSessionIdsArray; 5933 if (childSessionIds.size() > 0) { 5934 childSessionIdsArray = new int[childSessionIds.size()]; 5935 for (int i = 0, size = childSessionIds.size(); i < size; ++i) { 5936 childSessionIdsArray[i] = childSessionIds.get(i); 5937 } 5938 } else { 5939 childSessionIdsArray = EMPTY_CHILD_SESSION_ARRAY; 5940 } 5941 5942 InstallationFile[] fileArray = null; 5943 if (!files.isEmpty()) { 5944 fileArray = files.toArray(EMPTY_INSTALLATION_FILE_ARRAY); 5945 } 5946 5947 ArrayMap<String, PerFileChecksum> checksumsMap = null; 5948 if (!checksums.isEmpty()) { 5949 checksumsMap = new ArrayMap<>(checksums.size()); 5950 for (int i = 0, isize = checksums.size(); i < isize; ++i) { 5951 final String fileName = checksums.keyAt(i); 5952 final List<Checksum> perFileChecksum = checksums.valueAt(i); 5953 final byte[] perFileSignature = signatures.get(fileName); 5954 checksumsMap.put(fileName, new PerFileChecksum( 5955 perFileChecksum.toArray(new Checksum[perFileChecksum.size()]), 5956 perFileSignature)); 5957 } 5958 } 5959 5960 DomainSet preVerifiedDomains = 5961 preVerifiedDomainSet.isEmpty() ? null : new DomainSet(preVerifiedDomainSet); 5962 5963 InstallSource installSource = InstallSource.create(installInitiatingPackageName, 5964 installOriginatingPackageName, installerPackageName, installPackageUid, 5965 updateOwnerPackageName, installerAttributionTag, params.packageSource); 5966 return new PackageInstallerSession(callback, context, pm, sessionProvider, 5967 silentUpdatePolicy, installerThread, stagingManager, sessionId, userId, 5968 installerUid, installSource, params, createdMillis, committedMillis, stageDir, 5969 stageCid, fileArray, checksumsMap, prepared, committed, destroyed, sealed, 5970 childSessionIdsArray, parentSessionId, isReady, isFailed, isApplied, 5971 sessionErrorCode, sessionErrorMessage, preVerifiedDomains); 5972 } 5973 } 5974