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