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