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