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