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 org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
20 import static org.xmlpull.v1.XmlPullParser.START_TAG;
21 
22 import android.Manifest;
23 import android.annotation.NonNull;
24 import android.annotation.Nullable;
25 import android.app.ActivityManager;
26 import android.app.AppGlobals;
27 import android.app.AppOpsManager;
28 import android.app.Notification;
29 import android.app.NotificationManager;
30 import android.app.PackageDeleteObserver;
31 import android.app.admin.DevicePolicyEventLogger;
32 import android.app.admin.DevicePolicyManagerInternal;
33 import android.content.Context;
34 import android.content.Intent;
35 import android.content.IntentSender;
36 import android.content.IntentSender.SendIntentException;
37 import android.content.pm.ApplicationInfo;
38 import android.content.pm.IPackageInstaller;
39 import android.content.pm.IPackageInstallerCallback;
40 import android.content.pm.IPackageInstallerSession;
41 import android.content.pm.PackageInfo;
42 import android.content.pm.PackageInstaller;
43 import android.content.pm.PackageInstaller.SessionInfo;
44 import android.content.pm.PackageInstaller.SessionParams;
45 import android.content.pm.PackageItemInfo;
46 import android.content.pm.PackageManager;
47 import android.content.pm.ParceledListSlice;
48 import android.content.pm.VersionedPackage;
49 import android.graphics.Bitmap;
50 import android.net.Uri;
51 import android.os.Binder;
52 import android.os.Build;
53 import android.os.Environment;
54 import android.os.Handler;
55 import android.os.HandlerThread;
56 import android.os.Looper;
57 import android.os.Message;
58 import android.os.Process;
59 import android.os.RemoteCallbackList;
60 import android.os.RemoteException;
61 import android.os.SELinux;
62 import android.os.UserManager;
63 import android.os.storage.StorageManager;
64 import android.stats.devicepolicy.DevicePolicyEnums;
65 import android.system.ErrnoException;
66 import android.system.Os;
67 import android.text.TextUtils;
68 import android.text.format.DateUtils;
69 import android.util.ArraySet;
70 import android.util.AtomicFile;
71 import android.util.ExceptionUtils;
72 import android.util.Slog;
73 import android.util.SparseArray;
74 import android.util.SparseBooleanArray;
75 import android.util.SparseIntArray;
76 import android.util.TypedXmlPullParser;
77 import android.util.TypedXmlSerializer;
78 import android.util.Xml;
79 
80 import com.android.internal.R;
81 import com.android.internal.annotations.GuardedBy;
82 import com.android.internal.content.PackageHelper;
83 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
84 import com.android.internal.notification.SystemNotificationChannels;
85 import com.android.internal.util.ImageUtils;
86 import com.android.internal.util.IndentingPrintWriter;
87 import com.android.server.IoThread;
88 import com.android.server.LocalServices;
89 import com.android.server.SystemConfig;
90 import com.android.server.SystemService;
91 import com.android.server.SystemServiceManager;
92 import com.android.server.pm.parsing.PackageParser2;
93 import com.android.server.pm.utils.RequestThrottle;
94 
95 import libcore.io.IoUtils;
96 
97 import org.xmlpull.v1.XmlPullParserException;
98 
99 import java.io.CharArrayWriter;
100 import java.io.File;
101 import java.io.FileInputStream;
102 import java.io.FileNotFoundException;
103 import java.io.FileOutputStream;
104 import java.io.FilenameFilter;
105 import java.io.IOException;
106 import java.security.SecureRandom;
107 import java.util.ArrayList;
108 import java.util.Collections;
109 import java.util.List;
110 import java.util.Objects;
111 import java.util.Random;
112 import java.util.function.IntPredicate;
113 import java.util.function.Supplier;
114 
115 /** The service responsible for installing packages. */
116 public class PackageInstallerService extends IPackageInstaller.Stub implements
117         PackageSessionProvider {
118     private static final String TAG = "PackageInstaller";
119     private static final boolean LOGD = false;
120 
121     // TODO: remove outstanding sessions when installer package goes away
122     // TODO: notify listeners in other users when package has been installed there
123     // TODO: purge expired sessions periodically in addition to at reboot
124 
125     /** XML constants used in {@link #mSessionsFile} */
126     private static final String TAG_SESSIONS = "sessions";
127 
128     /** Automatically destroy sessions older than this */
129     private static final long MAX_AGE_MILLIS = 3 * DateUtils.DAY_IN_MILLIS;
130     /** Automatically destroy staged sessions that have not changed state in this time */
131     private static final long MAX_TIME_SINCE_UPDATE_MILLIS = 7 * DateUtils.DAY_IN_MILLIS;
132     /** Upper bound on number of active sessions for a UID that has INSTALL_PACKAGES */
133     private static final long MAX_ACTIVE_SESSIONS_WITH_PERMISSION = 1024;
134     /** Upper bound on number of active sessions for a UID without INSTALL_PACKAGES */
135     private static final long MAX_ACTIVE_SESSIONS_NO_PERMISSION = 50;
136     /** Upper bound on number of historical sessions for a UID */
137     private static final long MAX_HISTORICAL_SESSIONS = 1048576;
138     /** Destroy sessions older than this on storage free request */
139     private static final long MAX_SESSION_AGE_ON_LOW_STORAGE_MILLIS = 8 * DateUtils.HOUR_IN_MILLIS;
140 
141     /**
142      * Allow verification-skipping if it's a development app installed through ADB with
143      * disable verification flag specified.
144      */
145     private static final int ADB_DEV_MODE = PackageManager.INSTALL_FROM_ADB
146             | PackageManager.INSTALL_ALLOW_TEST;
147 
148     private final Context mContext;
149     private final PackageManagerService mPm;
150     private final ApexManager mApexManager;
151     private final StagingManager mStagingManager;
152 
153     private AppOpsManager mAppOps;
154 
155     private final HandlerThread mInstallThread;
156     private final Handler mInstallHandler;
157 
158     private final Callbacks mCallbacks;
159 
160     private volatile boolean mOkToSendBroadcasts = false;
161     private volatile boolean mBypassNextStagedInstallerCheck = false;
162     private volatile boolean mBypassNextAllowedApexUpdateCheck = false;
163 
164     /**
165      * File storing persisted {@link #mSessions} metadata.
166      */
167     private final AtomicFile mSessionsFile;
168 
169     /**
170      * Directory storing persisted {@link #mSessions} metadata which is too
171      * heavy to store directly in {@link #mSessionsFile}.
172      */
173     private final File mSessionsDir;
174 
175     private final InternalCallback mInternalCallback = new InternalCallback();
176 
177     /**
178      * Used for generating session IDs. Since this is created at boot time,
179      * normal random might be predictable.
180      */
181     private final Random mRandom = new SecureRandom();
182 
183     /** All sessions allocated */
184     @GuardedBy("mSessions")
185     private final SparseBooleanArray mAllocatedSessions = new SparseBooleanArray();
186 
187     @GuardedBy("mSessions")
188     private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>();
189 
190     /** Historical sessions kept around for debugging purposes */
191     @GuardedBy("mSessions")
192     private final List<String> mHistoricalSessions = new ArrayList<>();
193 
194     @GuardedBy("mSessions")
195     private final SparseIntArray mHistoricalSessionsByInstaller = new SparseIntArray();
196 
197     /** Sessions allocated to legacy users */
198     @GuardedBy("mSessions")
199     private final SparseBooleanArray mLegacySessions = new SparseBooleanArray();
200 
201     /** Policy for allowing a silent update. */
202     private final SilentUpdatePolicy mSilentUpdatePolicy = new SilentUpdatePolicy();
203 
204     private static final FilenameFilter sStageFilter = new FilenameFilter() {
205         @Override
206         public boolean accept(File dir, String name) {
207             return isStageName(name);
208         }
209     };
210 
211     private static final class Lifecycle extends SystemService {
212         private final PackageInstallerService mPackageInstallerService;
213 
Lifecycle(Context context, PackageInstallerService service)214         Lifecycle(Context context, PackageInstallerService service) {
215             super(context);
216             mPackageInstallerService = service;
217         }
218 
219         @Override
onStart()220         public void onStart() {
221             // no-op
222         }
223 
224         @Override
onBootPhase(int phase)225         public void onBootPhase(int phase) {
226             if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
227                 mPackageInstallerService.onBroadcastReady();
228             }
229         }
230     }
231 
232     @NonNull
233     private final RequestThrottle mSettingsWriteRequest = new RequestThrottle(IoThread.getHandler(),
234             () -> {
235                 synchronized (mSessions) {
236                     return writeSessionsLocked();
237                 }
238             });
239 
PackageInstallerService(Context context, PackageManagerService pm, Supplier<PackageParser2> apexParserSupplier)240     public PackageInstallerService(Context context, PackageManagerService pm,
241             Supplier<PackageParser2> apexParserSupplier) {
242         mContext = context;
243         mPm = pm;
244 
245         mInstallThread = new HandlerThread(TAG);
246         mInstallThread.start();
247 
248         mInstallHandler = new Handler(mInstallThread.getLooper());
249 
250         mCallbacks = new Callbacks(mInstallThread.getLooper());
251 
252         mSessionsFile = new AtomicFile(
253                 new File(Environment.getDataSystemDirectory(), "install_sessions.xml"),
254                 "package-session");
255         mSessionsDir = new File(Environment.getDataSystemDirectory(), "install_sessions");
256         mSessionsDir.mkdirs();
257 
258         mApexManager = ApexManager.getInstance();
259         mStagingManager = new StagingManager(context, apexParserSupplier);
260 
261         LocalServices.getService(SystemServiceManager.class).startService(
262                 new Lifecycle(context, this));
263     }
264 
okToSendBroadcasts()265     boolean okToSendBroadcasts()  {
266         return mOkToSendBroadcasts;
267     }
268 
systemReady()269     public void systemReady() {
270         mAppOps = mContext.getSystemService(AppOpsManager.class);
271         mStagingManager.systemReady();
272 
273         synchronized (mSessions) {
274             readSessionsLocked();
275 
276             reconcileStagesLocked(StorageManager.UUID_PRIVATE_INTERNAL);
277 
278             final ArraySet<File> unclaimedIcons = newArraySet(
279                     mSessionsDir.listFiles());
280 
281             // Ignore stages and icons claimed by active sessions
282             for (int i = 0; i < mSessions.size(); i++) {
283                 final PackageInstallerSession session = mSessions.valueAt(i);
284                 unclaimedIcons.remove(buildAppIconFile(session.sessionId));
285             }
286 
287             // Clean up orphaned icons
288             for (File icon : unclaimedIcons) {
289                 Slog.w(TAG, "Deleting orphan icon " + icon);
290                 icon.delete();
291             }
292 
293             // Invalid sessions might have been marked while parsing. Re-write the database with
294             // the updated information.
295             mSettingsWriteRequest.runNow();
296 
297         }
298     }
299 
onBroadcastReady()300     private void onBroadcastReady() {
301         // Broadcasts are not sent while we restore sessions on boot, since no processes would be
302         // ready to listen to them. From now on, it is safe to send broadcasts which otherwise will
303         // be rejected by ActivityManagerService if its systemReady() is not completed.
304         mOkToSendBroadcasts = true;
305     }
306 
restoreAndApplyStagedSessionIfNeeded()307     void restoreAndApplyStagedSessionIfNeeded() {
308         List<StagingManager.StagedSession> stagedSessionsToRestore = new ArrayList<>();
309         synchronized (mSessions) {
310             for (int i = 0; i < mSessions.size(); i++) {
311                 final PackageInstallerSession session = mSessions.valueAt(i);
312                 if (!session.isStaged()) {
313                     continue;
314                 }
315                 StagingManager.StagedSession stagedSession = session.mStagedSession;
316                 if (!stagedSession.isInTerminalState() && stagedSession.hasParentSessionId()
317                         && getSession(stagedSession.getParentSessionId()) == null) {
318                     stagedSession.setSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
319                             "An orphan staged session " + stagedSession.sessionId() + " is found, "
320                                 + "parent " + stagedSession.getParentSessionId() + " is missing");
321                     continue;
322                 }
323                 if (!stagedSession.hasParentSessionId() && stagedSession.isCommitted()
324                         && !stagedSession.isInTerminalState()) {
325                     // StagingManager.restoreSessions expects a list of committed, non-finalized
326                     // parent staged sessions.
327                     stagedSessionsToRestore.add(stagedSession);
328                 }
329             }
330         }
331         // Don't hold mSessions lock when calling restoreSessions, since it might trigger an APK
332         // atomic install which needs to query sessions, which requires lock on mSessions.
333         // Note: restoreSessions mutates content of stagedSessionsToRestore.
334         mStagingManager.restoreSessions(stagedSessionsToRestore, mPm.isDeviceUpgrading());
335     }
336 
337     @GuardedBy("mSessions")
reconcileStagesLocked(String volumeUuid)338     private void reconcileStagesLocked(String volumeUuid) {
339         final ArraySet<File> unclaimedStages = getStagingDirsOnVolume(volumeUuid);
340         // Ignore stages claimed by active sessions
341         for (int i = 0; i < mSessions.size(); i++) {
342             final PackageInstallerSession session = mSessions.valueAt(i);
343             unclaimedStages.remove(session.stageDir);
344         }
345         removeStagingDirs(unclaimedStages);
346     }
347 
getStagingDirsOnVolume(String volumeUuid)348     private ArraySet<File> getStagingDirsOnVolume(String volumeUuid) {
349         final File stagingDir = getTmpSessionDir(volumeUuid);
350         final ArraySet<File> stagingDirs = newArraySet(stagingDir.listFiles(sStageFilter));
351 
352         // We also need to clean up orphaned staging directory for staged sessions
353         final File stagedSessionStagingDir = Environment.getDataStagingDirectory(volumeUuid);
354         stagingDirs.addAll(newArraySet(stagedSessionStagingDir.listFiles()));
355         return stagingDirs;
356     }
357 
removeStagingDirs(ArraySet<File> stagingDirsToRemove)358     private void removeStagingDirs(ArraySet<File> stagingDirsToRemove) {
359         // Clean up orphaned staging directories
360         for (File stage : stagingDirsToRemove) {
361             Slog.w(TAG, "Deleting orphan stage " + stage);
362             synchronized (mPm.mInstallLock) {
363                 mPm.removeCodePathLI(stage);
364             }
365         }
366     }
367 
onPrivateVolumeMounted(String volumeUuid)368     public void onPrivateVolumeMounted(String volumeUuid) {
369         synchronized (mSessions) {
370             reconcileStagesLocked(volumeUuid);
371         }
372     }
373 
374     /**
375      * Called to free up some storage space from obsolete installation files
376      */
freeStageDirs(String volumeUuid)377     public void freeStageDirs(String volumeUuid) {
378         final ArraySet<File> unclaimedStagingDirsOnVolume = getStagingDirsOnVolume(volumeUuid);
379         final long currentTimeMillis = System.currentTimeMillis();
380         synchronized (mSessions) {
381             for (int i = 0; i < mSessions.size(); i++) {
382                 final PackageInstallerSession session = mSessions.valueAt(i);
383                 if (!unclaimedStagingDirsOnVolume.contains(session.stageDir)) {
384                     // Only handles sessions stored on the target volume
385                     continue;
386                 }
387                 final long age = currentTimeMillis - session.createdMillis;
388                 if (age >= MAX_SESSION_AGE_ON_LOW_STORAGE_MILLIS) {
389                     // Aggressively close old sessions because we are running low on storage
390                     // Their staging dirs will be removed too
391                     PackageInstallerSession root = !session.hasParentSessionId()
392                             ? session : mSessions.get(session.getParentSessionId());
393                     if (root == null) {
394                         Slog.e(TAG, "freeStageDirs: found an orphaned session: "
395                                 + session.sessionId + " parent=" + session.getParentSessionId());
396                     } else if (!root.isDestroyed()) {
397                         root.abandon();
398                     }
399                 } else {
400                     // Session is new enough, so it deserves to be kept even on low storage
401                     unclaimedStagingDirsOnVolume.remove(session.stageDir);
402                 }
403             }
404         }
405         removeStagingDirs(unclaimedStagingDirsOnVolume);
406     }
407 
isStageName(String name)408     public static boolean isStageName(String name) {
409         final boolean isFile = name.startsWith("vmdl") && name.endsWith(".tmp");
410         final boolean isContainer = name.startsWith("smdl") && name.endsWith(".tmp");
411         final boolean isLegacyContainer = name.startsWith("smdl2tmp");
412         return isFile || isContainer || isLegacyContainer;
413     }
414 
415     @Deprecated
allocateStageDirLegacy(String volumeUuid, boolean isEphemeral)416     public File allocateStageDirLegacy(String volumeUuid, boolean isEphemeral) throws IOException {
417         synchronized (mSessions) {
418             try {
419                 final int sessionId = allocateSessionIdLocked();
420                 mLegacySessions.put(sessionId, true);
421                 final File sessionStageDir = buildTmpSessionDir(sessionId, volumeUuid);
422                 prepareStageDir(sessionStageDir);
423                 return sessionStageDir;
424             } catch (IllegalStateException e) {
425                 throw new IOException(e);
426             }
427         }
428     }
429 
430     @Deprecated
allocateExternalStageCidLegacy()431     public String allocateExternalStageCidLegacy() {
432         synchronized (mSessions) {
433             final int sessionId = allocateSessionIdLocked();
434             mLegacySessions.put(sessionId, true);
435             return "smdl" + sessionId + ".tmp";
436         }
437     }
438 
439     @GuardedBy("mSessions")
readSessionsLocked()440     private void readSessionsLocked() {
441         if (LOGD) Slog.v(TAG, "readSessionsLocked()");
442 
443         mSessions.clear();
444 
445         FileInputStream fis = null;
446         try {
447             fis = mSessionsFile.openRead();
448             final TypedXmlPullParser in = Xml.resolvePullParser(fis);
449 
450             int type;
451             while ((type = in.next()) != END_DOCUMENT) {
452                 if (type == START_TAG) {
453                     final String tag = in.getName();
454                     if (PackageInstallerSession.TAG_SESSION.equals(tag)) {
455                         final PackageInstallerSession session;
456                         try {
457                             session = PackageInstallerSession.readFromXml(in, mInternalCallback,
458                                     mContext, mPm, mInstallThread.getLooper(), mStagingManager,
459                                     mSessionsDir, this, mSilentUpdatePolicy);
460                         } catch (Exception e) {
461                             Slog.e(TAG, "Could not read session", e);
462                             continue;
463                         }
464 
465                         final long age = System.currentTimeMillis() - session.createdMillis;
466                         final long timeSinceUpdate =
467                                 System.currentTimeMillis() - session.getUpdatedMillis();
468                         final boolean valid;
469                         if (session.isStaged()) {
470                             if (timeSinceUpdate >= MAX_TIME_SINCE_UPDATE_MILLIS
471                                     && session.isStagedAndInTerminalState()) {
472                                 valid = false;
473                             } else {
474                                 valid = true;
475                             }
476                         } else if (age >= MAX_AGE_MILLIS) {
477                             Slog.w(TAG, "Abandoning old session created at "
478                                         + session.createdMillis);
479                             valid = false;
480                         } else {
481                             valid = true;
482                         }
483 
484                         if (valid) {
485                             mSessions.put(session.sessionId, session);
486                         } else {
487                             // Since this is early during boot we don't send
488                             // any observer events about the session, but we
489                             // keep details around for dumpsys.
490                             addHistoricalSessionLocked(session);
491                         }
492                         mAllocatedSessions.put(session.sessionId, true);
493                     }
494                 }
495             }
496         } catch (FileNotFoundException e) {
497             // Missing sessions are okay, probably first boot
498         } catch (IOException | XmlPullParserException e) {
499             Slog.wtf(TAG, "Failed reading install sessions", e);
500         } finally {
501             IoUtils.closeQuietly(fis);
502         }
503         // After reboot housekeeping.
504         for (int i = 0; i < mSessions.size(); ++i) {
505             PackageInstallerSession session = mSessions.valueAt(i);
506             session.onAfterSessionRead(mSessions);
507         }
508     }
509 
510     @GuardedBy("mSessions")
addHistoricalSessionLocked(PackageInstallerSession session)511     private void addHistoricalSessionLocked(PackageInstallerSession session) {
512         CharArrayWriter writer = new CharArrayWriter();
513         IndentingPrintWriter pw = new IndentingPrintWriter(writer, "    ");
514         session.dump(pw);
515         mHistoricalSessions.add(writer.toString());
516 
517         int installerUid = session.getInstallerUid();
518         // Increment the number of sessions by this installerUid.
519         mHistoricalSessionsByInstaller.put(installerUid,
520                 mHistoricalSessionsByInstaller.get(installerUid) + 1);
521     }
522 
523     @GuardedBy("mSessions")
writeSessionsLocked()524     private boolean writeSessionsLocked() {
525         if (LOGD) Slog.v(TAG, "writeSessionsLocked()");
526 
527         FileOutputStream fos = null;
528         try {
529             fos = mSessionsFile.startWrite();
530 
531             final TypedXmlSerializer out = Xml.resolveSerializer(fos);
532             out.startDocument(null, true);
533             out.startTag(null, TAG_SESSIONS);
534             final int size = mSessions.size();
535             for (int i = 0; i < size; i++) {
536                 final PackageInstallerSession session = mSessions.valueAt(i);
537                 session.write(out, mSessionsDir);
538             }
539             out.endTag(null, TAG_SESSIONS);
540             out.endDocument();
541 
542             mSessionsFile.finishWrite(fos);
543             return true;
544         } catch (IOException e) {
545             if (fos != null) {
546                 mSessionsFile.failWrite(fos);
547             }
548         }
549 
550         return false;
551     }
552 
buildAppIconFile(int sessionId)553     private File buildAppIconFile(int sessionId) {
554         return new File(mSessionsDir, "app_icon." + sessionId + ".png");
555     }
556 
557     @Override
createSession(SessionParams params, String installerPackageName, String callingAttributionTag, int userId)558     public int createSession(SessionParams params, String installerPackageName,
559             String callingAttributionTag, int userId) {
560         try {
561             return createSessionInternal(params, installerPackageName, callingAttributionTag,
562                     userId);
563         } catch (IOException e) {
564             throw ExceptionUtils.wrap(e);
565         }
566     }
567 
createSessionInternal(SessionParams params, String installerPackageName, String installerAttributionTag, int userId)568     private int createSessionInternal(SessionParams params, String installerPackageName,
569             String installerAttributionTag, int userId)
570             throws IOException {
571         final int callingUid = Binder.getCallingUid();
572         mPm.enforceCrossUserPermission(
573                 callingUid, userId, true, true, "createSession");
574 
575         if (mPm.isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
576             throw new SecurityException("User restriction prevents installing");
577         }
578 
579         if (params.dataLoaderParams != null
580                 && mContext.checkCallingOrSelfPermission(Manifest.permission.USE_INSTALLER_V2)
581                         != PackageManager.PERMISSION_GRANTED) {
582             throw new SecurityException("You need the "
583                     + "com.android.permission.USE_INSTALLER_V2 permission "
584                     + "to use a data loader");
585         }
586 
587         // INSTALL_REASON_ROLLBACK allows an app to be rolled back without requiring the ROLLBACK
588         // capability; ensure if this is set as the install reason the app has one of the necessary
589         // signature permissions to perform the rollback.
590         if (params.installReason == PackageManager.INSTALL_REASON_ROLLBACK) {
591             if (mContext.checkCallingOrSelfPermission(Manifest.permission.MANAGE_ROLLBACKS)
592                     != PackageManager.PERMISSION_GRANTED &&
593                     mContext.checkCallingOrSelfPermission(Manifest.permission.TEST_MANAGE_ROLLBACKS)
594                     != PackageManager.PERMISSION_GRANTED) {
595                 throw new SecurityException(
596                         "INSTALL_REASON_ROLLBACK requires the MANAGE_ROLLBACKS permission or the "
597                                 + "TEST_MANAGE_ROLLBACKS permission");
598             }
599         }
600 
601         // App package name and label length is restricted so that really long strings aren't
602         // written to disk.
603         if (params.appPackageName != null
604                 && params.appPackageName.length() > SessionParams.MAX_PACKAGE_NAME_LENGTH) {
605             params.appPackageName = null;
606         }
607 
608         params.appLabel = TextUtils.trimToSize(params.appLabel,
609                 PackageItemInfo.MAX_SAFE_LABEL_LENGTH);
610 
611         String requestedInstallerPackageName = (params.installerPackageName != null
612                 && params.installerPackageName.length() < SessionParams.MAX_PACKAGE_NAME_LENGTH)
613                 ? params.installerPackageName : installerPackageName;
614 
615         if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {
616             params.installFlags |= PackageManager.INSTALL_FROM_ADB;
617             // adb installs can override the installingPackageName, but not the
618             // initiatingPackageName
619             installerPackageName = null;
620         } else {
621             if (callingUid != Process.SYSTEM_UID) {
622                 // The supplied installerPackageName must always belong to the calling app.
623                 mAppOps.checkPackage(callingUid, installerPackageName);
624             }
625             // Only apps with INSTALL_PACKAGES are allowed to set an installer that is not the
626             // caller.
627             if (!TextUtils.equals(requestedInstallerPackageName, installerPackageName)) {
628                 if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES)
629                         != PackageManager.PERMISSION_GRANTED) {
630                     mAppOps.checkPackage(callingUid, requestedInstallerPackageName);
631                 }
632             }
633 
634             params.installFlags &= ~PackageManager.INSTALL_FROM_ADB;
635             params.installFlags &= ~PackageManager.INSTALL_ALL_USERS;
636             params.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
637             if ((params.installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0
638                     && !mPm.isCallerVerifier(callingUid)) {
639                 params.installFlags &= ~PackageManager.INSTALL_VIRTUAL_PRELOAD;
640             }
641             if (mContext.checkCallingOrSelfPermission(
642                     Manifest.permission.INSTALL_TEST_ONLY_PACKAGE)
643                     != PackageManager.PERMISSION_GRANTED) {
644                 params.installFlags &= ~PackageManager.INSTALL_ALLOW_TEST;
645             }
646         }
647 
648         String originatingPackageName = null;
649         if (params.originatingUid != SessionParams.UID_UNKNOWN
650                 && params.originatingUid != callingUid) {
651             String[] packages = mPm.getPackagesForUid(params.originatingUid);
652             if (packages != null && packages.length > 0) {
653                 // Choose an arbitrary representative package in the case of a shared UID.
654                 originatingPackageName = packages[0];
655             }
656         }
657 
658         if (Build.IS_DEBUGGABLE || isCalledBySystemOrShell(callingUid)) {
659             params.installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE;
660         } else {
661             params.installFlags &= ~PackageManager.INSTALL_ALLOW_DOWNGRADE;
662             params.installFlags &= ~PackageManager.INSTALL_REQUEST_DOWNGRADE;
663         }
664 
665         if ((params.installFlags & ADB_DEV_MODE) != ADB_DEV_MODE) {
666             // Only tools under specific conditions (test app installed through ADB, and
667             // verification disabled flag specified) can disable verification.
668             params.installFlags &= ~PackageManager.INSTALL_DISABLE_VERIFICATION;
669         }
670 
671         boolean isApex = (params.installFlags & PackageManager.INSTALL_APEX) != 0;
672         if (isApex) {
673             if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGE_UPDATES)
674                     == PackageManager.PERMISSION_DENIED
675                     && mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES)
676                     == PackageManager.PERMISSION_DENIED) {
677                 throw new SecurityException("Not allowed to perform APEX updates");
678             }
679         } else if (params.isStaged) {
680             mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, TAG);
681         }
682 
683         if (isApex) {
684             if (!mApexManager.isApexSupported()) {
685                 throw new IllegalArgumentException(
686                     "This device doesn't support the installation of APEX files");
687             }
688             if (params.isMultiPackage) {
689                 throw new IllegalArgumentException("A multi-session can't be set as APEX.");
690             }
691             if (!params.isStaged
692                     && (params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
693                 throw new IllegalArgumentException(
694                     "Non-staged APEX session doesn't support INSTALL_ENABLE_ROLLBACK");
695             }
696             if (isCalledBySystemOrShell(callingUid) || mBypassNextAllowedApexUpdateCheck) {
697                 params.installFlags |= PackageManager.INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK;
698             } else {
699                 // Only specific APEX updates (installed through ADB, or for CTS tests) can disable
700                 // allowed APEX update check.
701                 params.installFlags &= ~PackageManager.INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK;
702             }
703         }
704 
705         if ((params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0
706                 && !isCalledBySystemOrShell(callingUid)
707                 && (mPm.getFlagsForUid(callingUid) & ApplicationInfo.FLAG_SYSTEM) == 0) {
708             throw new SecurityException(
709                     "Only system apps could use the PackageManager.INSTALL_INSTANT_APP flag.");
710         }
711 
712         if (params.isStaged && !isCalledBySystemOrShell(callingUid)) {
713             if (!mBypassNextStagedInstallerCheck
714                     && !isStagedInstallerAllowed(requestedInstallerPackageName)) {
715                 throw new SecurityException("Installer not allowed to commit staged install");
716             }
717         }
718         if (isApex && !isCalledBySystemOrShell(callingUid)) {
719             if (!mBypassNextStagedInstallerCheck
720                     && !isStagedInstallerAllowed(requestedInstallerPackageName)) {
721                 throw new SecurityException(
722                         "Installer not allowed to commit non-staged APEX install");
723             }
724         }
725 
726         mBypassNextStagedInstallerCheck = false;
727         mBypassNextAllowedApexUpdateCheck = false;
728 
729         if (!params.isMultiPackage) {
730             // Only system components can circumvent runtime permissions when installing.
731             if ((params.installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0
732                     && mContext.checkCallingOrSelfPermission(Manifest.permission
733                     .INSTALL_GRANT_RUNTIME_PERMISSIONS) == PackageManager.PERMISSION_DENIED) {
734                 throw new SecurityException("You need the "
735                         + "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS permission "
736                         + "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag");
737             }
738 
739             // Defensively resize giant app icons
740             if (params.appIcon != null) {
741                 final ActivityManager am = (ActivityManager) mContext.getSystemService(
742                         Context.ACTIVITY_SERVICE);
743                 final int iconSize = am.getLauncherLargeIconSize();
744                 if ((params.appIcon.getWidth() > iconSize * 2)
745                         || (params.appIcon.getHeight() > iconSize * 2)) {
746                     params.appIcon = Bitmap.createScaledBitmap(params.appIcon, iconSize, iconSize,
747                             true);
748                 }
749             }
750 
751             switch (params.mode) {
752                 case SessionParams.MODE_FULL_INSTALL:
753                 case SessionParams.MODE_INHERIT_EXISTING:
754                     break;
755                 default:
756                     throw new IllegalArgumentException("Invalid install mode: " + params.mode);
757             }
758 
759             // If caller requested explicit location, validity check it, otherwise
760             // resolve the best internal or adopted location.
761             if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
762                 if (!PackageHelper.fitsOnInternal(mContext, params)) {
763                     throw new IOException("No suitable internal storage available");
764                 }
765             } else if ((params.installFlags & PackageManager.INSTALL_FORCE_VOLUME_UUID) != 0) {
766                 // For now, installs to adopted media are treated as internal from
767                 // an install flag point-of-view.
768                 params.installFlags |= PackageManager.INSTALL_INTERNAL;
769             } else {
770                 params.installFlags |= PackageManager.INSTALL_INTERNAL;
771 
772                 // Resolve best location for install, based on combination of
773                 // requested install flags, delta size, and manifest settings.
774                 final long ident = Binder.clearCallingIdentity();
775                 try {
776                     params.volumeUuid = PackageHelper.resolveInstallVolume(mContext, params);
777                 } finally {
778                     Binder.restoreCallingIdentity(ident);
779                 }
780             }
781         }
782 
783         final int sessionId;
784         final PackageInstallerSession session;
785         synchronized (mSessions) {
786             // Check that the installer does not have too many active sessions.
787             final int activeCount = getSessionCount(mSessions, callingUid);
788             if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES)
789                     == PackageManager.PERMISSION_GRANTED) {
790                 if (activeCount >= MAX_ACTIVE_SESSIONS_WITH_PERMISSION) {
791                     throw new IllegalStateException(
792                             "Too many active sessions for UID " + callingUid);
793                 }
794             } else if (activeCount >= MAX_ACTIVE_SESSIONS_NO_PERMISSION) {
795                 throw new IllegalStateException(
796                         "Too many active sessions for UID " + callingUid);
797             }
798             final int historicalCount = mHistoricalSessionsByInstaller.get(callingUid);
799             if (historicalCount >= MAX_HISTORICAL_SESSIONS) {
800                 throw new IllegalStateException(
801                         "Too many historical sessions for UID " + callingUid);
802             }
803 
804             sessionId = allocateSessionIdLocked();
805         }
806 
807         final long createdMillis = System.currentTimeMillis();
808         // We're staging to exactly one location
809         File stageDir = null;
810         String stageCid = null;
811         if (!params.isMultiPackage) {
812             if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
813                 stageDir = buildSessionDir(sessionId, params);
814             } else {
815                 stageCid = buildExternalStageCid(sessionId);
816             }
817         }
818 
819         // reset the force queryable param if it's not called by an approved caller.
820         if (params.forceQueryableOverride) {
821             if (callingUid != Process.SHELL_UID && callingUid != Process.ROOT_UID) {
822                 params.forceQueryableOverride = false;
823             }
824         }
825         InstallSource installSource = InstallSource.create(installerPackageName,
826                 originatingPackageName, requestedInstallerPackageName,
827                 installerAttributionTag);
828         session = new PackageInstallerSession(mInternalCallback, mContext, mPm, this,
829                 mSilentUpdatePolicy, mInstallThread.getLooper(), mStagingManager, sessionId,
830                 userId, callingUid, installSource, params, createdMillis, 0L, stageDir, stageCid,
831                 null, null, false, false, false, false, null, SessionInfo.INVALID_ID,
832                 false, false, false, SessionInfo.STAGED_SESSION_NO_ERROR, "");
833 
834         synchronized (mSessions) {
835             mSessions.put(sessionId, session);
836         }
837 
838         mCallbacks.notifySessionCreated(session.sessionId, session.userId);
839 
840         mSettingsWriteRequest.schedule();
841         return sessionId;
842     }
843 
isCalledBySystemOrShell(int callingUid)844     private boolean isCalledBySystemOrShell(int callingUid) {
845         return callingUid == Process.SYSTEM_UID || callingUid == Process.ROOT_UID
846                 || callingUid == Process.SHELL_UID;
847     }
848 
isStagedInstallerAllowed(String installerName)849     private boolean isStagedInstallerAllowed(String installerName) {
850         return SystemConfig.getInstance().getWhitelistedStagedInstallers().contains(installerName);
851     }
852 
853     @Override
updateSessionAppIcon(int sessionId, Bitmap appIcon)854     public void updateSessionAppIcon(int sessionId, Bitmap appIcon) {
855         synchronized (mSessions) {
856             final PackageInstallerSession session = mSessions.get(sessionId);
857             if (session == null || !isCallingUidOwner(session)) {
858                 throw new SecurityException("Caller has no access to session " + sessionId);
859             }
860 
861             // Defensively resize giant app icons
862             if (appIcon != null) {
863                 final ActivityManager am = (ActivityManager) mContext.getSystemService(
864                         Context.ACTIVITY_SERVICE);
865                 final int iconSize = am.getLauncherLargeIconSize();
866                 if ((appIcon.getWidth() > iconSize * 2)
867                         || (appIcon.getHeight() > iconSize * 2)) {
868                     appIcon = Bitmap.createScaledBitmap(appIcon, iconSize, iconSize, true);
869                 }
870             }
871 
872             session.params.appIcon = appIcon;
873             session.params.appIconLastModified = -1;
874 
875             mInternalCallback.onSessionBadgingChanged(session);
876         }
877     }
878 
879     @Override
updateSessionAppLabel(int sessionId, String appLabel)880     public void updateSessionAppLabel(int sessionId, String appLabel) {
881         synchronized (mSessions) {
882             final PackageInstallerSession session = mSessions.get(sessionId);
883             if (session == null || !isCallingUidOwner(session)) {
884                 throw new SecurityException("Caller has no access to session " + sessionId);
885             }
886             session.params.appLabel = appLabel;
887             mInternalCallback.onSessionBadgingChanged(session);
888         }
889     }
890 
891     @Override
abandonSession(int sessionId)892     public void abandonSession(int sessionId) {
893         synchronized (mSessions) {
894             final PackageInstallerSession session = mSessions.get(sessionId);
895             if (session == null || !isCallingUidOwner(session)) {
896                 throw new SecurityException("Caller has no access to session " + sessionId);
897             }
898             session.abandon();
899         }
900     }
901 
902     @Override
openSession(int sessionId)903     public IPackageInstallerSession openSession(int sessionId) {
904         try {
905             return openSessionInternal(sessionId);
906         } catch (IOException e) {
907             throw ExceptionUtils.wrap(e);
908         }
909     }
910 
openSessionInternal(int sessionId)911     private IPackageInstallerSession openSessionInternal(int sessionId) throws IOException {
912         synchronized (mSessions) {
913             final PackageInstallerSession session = mSessions.get(sessionId);
914             if (session == null || !isCallingUidOwner(session)) {
915                 throw new SecurityException("Caller has no access to session " + sessionId);
916             }
917             session.open();
918             return session;
919         }
920     }
921 
922     @GuardedBy("mSessions")
allocateSessionIdLocked()923     private int allocateSessionIdLocked() {
924         int n = 0;
925         int sessionId;
926         do {
927             sessionId = mRandom.nextInt(Integer.MAX_VALUE - 1) + 1;
928             if (!mAllocatedSessions.get(sessionId, false)) {
929                 mAllocatedSessions.put(sessionId, true);
930                 return sessionId;
931             }
932         } while (n++ < 32);
933 
934         throw new IllegalStateException("Failed to allocate session ID");
935     }
936 
getTmpSessionDir(String volumeUuid)937     private File getTmpSessionDir(String volumeUuid) {
938         return Environment.getDataAppDirectory(volumeUuid);
939     }
940 
buildTmpSessionDir(int sessionId, String volumeUuid)941     private File buildTmpSessionDir(int sessionId, String volumeUuid) {
942         final File sessionStagingDir = getTmpSessionDir(volumeUuid);
943         return new File(sessionStagingDir, "vmdl" + sessionId + ".tmp");
944     }
945 
buildSessionDir(int sessionId, SessionParams params)946     private File buildSessionDir(int sessionId, SessionParams params) {
947         if (params.isStaged || (params.installFlags & PackageManager.INSTALL_APEX) != 0) {
948             final File sessionStagingDir = Environment.getDataStagingDirectory(params.volumeUuid);
949             return new File(sessionStagingDir, "session_" + sessionId);
950         }
951         return buildTmpSessionDir(sessionId, params.volumeUuid);
952     }
953 
prepareStageDir(File stageDir)954     static void prepareStageDir(File stageDir) throws IOException {
955         if (stageDir.exists()) {
956             throw new IOException("Session dir already exists: " + stageDir);
957         }
958 
959         try {
960             Os.mkdir(stageDir.getAbsolutePath(), 0775);
961             Os.chmod(stageDir.getAbsolutePath(), 0775);
962         } catch (ErrnoException e) {
963             // This purposefully throws if directory already exists
964             throw new IOException("Failed to prepare session dir: " + stageDir, e);
965         }
966 
967         if (!SELinux.restorecon(stageDir)) {
968             throw new IOException("Failed to restorecon session dir: " + stageDir);
969         }
970     }
971 
buildExternalStageCid(int sessionId)972     private String buildExternalStageCid(int sessionId) {
973         return "smdl" + sessionId + ".tmp";
974     }
975 
976     @Override
getSessionInfo(int sessionId)977     public SessionInfo getSessionInfo(int sessionId) {
978         synchronized (mSessions) {
979             final PackageInstallerSession session = mSessions.get(sessionId);
980 
981             return (session != null && !(session.isStaged() && session.isDestroyed()))
982                     ? session.generateInfoForCaller(true /*withIcon*/, Binder.getCallingUid())
983                     : null;
984         }
985     }
986 
987     @Override
getStagedSessions()988     public ParceledListSlice<SessionInfo> getStagedSessions() {
989         final List<SessionInfo> result = new ArrayList<>();
990         synchronized (mSessions) {
991             for (int i = 0; i < mSessions.size(); i++) {
992                 final PackageInstallerSession session = mSessions.valueAt(i);
993                 if (session.isStaged() && !session.isDestroyed()) {
994                     result.add(session.generateInfoForCaller(false, Binder.getCallingUid()));
995                 }
996             }
997         }
998         return new ParceledListSlice<>(result);
999     }
1000 
1001     @Override
getAllSessions(int userId)1002     public ParceledListSlice<SessionInfo> getAllSessions(int userId) {
1003         final int callingUid = Binder.getCallingUid();
1004         mPm.enforceCrossUserPermission(
1005                 callingUid, userId, true, false, "getAllSessions");
1006 
1007         final List<SessionInfo> result = new ArrayList<>();
1008         synchronized (mSessions) {
1009             for (int i = 0; i < mSessions.size(); i++) {
1010                 final PackageInstallerSession session = mSessions.valueAt(i);
1011                 if (session.userId == userId && !session.hasParentSessionId()
1012                         && !(session.isStaged() && session.isDestroyed())) {
1013                     result.add(session.generateInfoForCaller(false, callingUid));
1014                 }
1015             }
1016         }
1017         return new ParceledListSlice<>(result);
1018     }
1019 
1020     @Override
getMySessions(String installerPackageName, int userId)1021     public ParceledListSlice<SessionInfo> getMySessions(String installerPackageName, int userId) {
1022         mPm.enforceCrossUserPermission(
1023                 Binder.getCallingUid(), userId, true, false, "getMySessions");
1024         mAppOps.checkPackage(Binder.getCallingUid(), installerPackageName);
1025 
1026         final List<SessionInfo> result = new ArrayList<>();
1027         synchronized (mSessions) {
1028             for (int i = 0; i < mSessions.size(); i++) {
1029                 final PackageInstallerSession session = mSessions.valueAt(i);
1030 
1031                 SessionInfo info =
1032                         session.generateInfoForCaller(false /*withIcon*/, Process.SYSTEM_UID);
1033                 if (Objects.equals(info.getInstallerPackageName(), installerPackageName)
1034                         && session.userId == userId && !session.hasParentSessionId()
1035                         && isCallingUidOwner(session)) {
1036                     result.add(info);
1037                 }
1038             }
1039         }
1040         return new ParceledListSlice<>(result);
1041     }
1042 
1043     @Override
uninstall(VersionedPackage versionedPackage, String callerPackageName, int flags, IntentSender statusReceiver, int userId)1044     public void uninstall(VersionedPackage versionedPackage, String callerPackageName, int flags,
1045                 IntentSender statusReceiver, int userId) {
1046         final int callingUid = Binder.getCallingUid();
1047         mPm.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
1048         if ((callingUid != Process.SHELL_UID) && (callingUid != Process.ROOT_UID)) {
1049             mAppOps.checkPackage(callingUid, callerPackageName);
1050         }
1051 
1052         // Check whether the caller is device owner or affiliated profile owner, in which case we do
1053         // it silently.
1054         DevicePolicyManagerInternal dpmi =
1055                 LocalServices.getService(DevicePolicyManagerInternal.class);
1056         final boolean canSilentlyInstallPackage =
1057                 dpmi != null && dpmi.canSilentlyInstallPackage(callerPackageName, callingUid);
1058 
1059         final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext,
1060                 statusReceiver, versionedPackage.getPackageName(),
1061                 canSilentlyInstallPackage, userId);
1062         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES)
1063                     == PackageManager.PERMISSION_GRANTED) {
1064             // Sweet, call straight through!
1065             mPm.deletePackageVersioned(versionedPackage, adapter.getBinder(), userId, flags);
1066         } else if (canSilentlyInstallPackage) {
1067             // Allow the device owner and affiliated profile owner to silently delete packages
1068             // Need to clear the calling identity to get DELETE_PACKAGES permission
1069             final long ident = Binder.clearCallingIdentity();
1070             try {
1071                 mPm.deletePackageVersioned(versionedPackage, adapter.getBinder(), userId, flags);
1072             } finally {
1073                 Binder.restoreCallingIdentity(ident);
1074             }
1075             DevicePolicyEventLogger
1076                     .createEvent(DevicePolicyEnums.UNINSTALL_PACKAGE)
1077                     .setAdmin(callerPackageName)
1078                     .write();
1079         } else {
1080             ApplicationInfo appInfo = mPm.getApplicationInfo(callerPackageName, 0, userId);
1081             if (appInfo.targetSdkVersion >= Build.VERSION_CODES.P) {
1082                 mContext.enforceCallingOrSelfPermission(Manifest.permission.REQUEST_DELETE_PACKAGES,
1083                         null);
1084             }
1085 
1086             // Take a short detour to confirm with user
1087             final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
1088             intent.setData(Uri.fromParts("package", versionedPackage.getPackageName(), null));
1089             intent.putExtra(PackageInstaller.EXTRA_CALLBACK, adapter.getBinder().asBinder());
1090             adapter.onUserActionRequired(intent);
1091         }
1092     }
1093 
1094     @Override
uninstallExistingPackage(VersionedPackage versionedPackage, String callerPackageName, IntentSender statusReceiver, int userId)1095     public void uninstallExistingPackage(VersionedPackage versionedPackage,
1096             String callerPackageName, IntentSender statusReceiver, int userId) {
1097         final int callingUid = Binder.getCallingUid();
1098         mContext.enforceCallingOrSelfPermission(Manifest.permission.DELETE_PACKAGES, null);
1099         mPm.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
1100         if ((callingUid != Process.SHELL_UID) && (callingUid != Process.ROOT_UID)) {
1101             mAppOps.checkPackage(callingUid, callerPackageName);
1102         }
1103 
1104         final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext,
1105                 statusReceiver, versionedPackage.getPackageName(), false, userId);
1106         mPm.deleteExistingPackageAsUser(versionedPackage, adapter.getBinder(), userId);
1107     }
1108 
1109     @Override
installExistingPackage(String packageName, int installFlags, int installReason, IntentSender statusReceiver, int userId, List<String> whiteListedPermissions)1110     public void installExistingPackage(String packageName, int installFlags, int installReason,
1111             IntentSender statusReceiver, int userId, List<String> whiteListedPermissions) {
1112         mPm.installExistingPackageAsUser(packageName, userId, installFlags, installReason,
1113                 whiteListedPermissions, statusReceiver);
1114     }
1115 
1116     @Override
setPermissionsResult(int sessionId, boolean accepted)1117     public void setPermissionsResult(int sessionId, boolean accepted) {
1118         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, TAG);
1119 
1120         synchronized (mSessions) {
1121             PackageInstallerSession session = mSessions.get(sessionId);
1122             if (session != null) {
1123                 session.setPermissionsResult(accepted);
1124             }
1125         }
1126     }
1127 
1128     @Override
registerCallback(IPackageInstallerCallback callback, int userId)1129     public void registerCallback(IPackageInstallerCallback callback, int userId) {
1130         mPm.enforceCrossUserPermission(
1131                 Binder.getCallingUid(), userId, true, false, "registerCallback");
1132         registerCallback(callback, eventUserId -> userId == eventUserId);
1133     }
1134 
1135     /**
1136      * Assume permissions already checked and caller's identity cleared
1137      */
registerCallback(IPackageInstallerCallback callback, IntPredicate userCheck)1138     public void registerCallback(IPackageInstallerCallback callback, IntPredicate userCheck) {
1139         mCallbacks.register(callback, userCheck);
1140     }
1141 
1142     @Override
unregisterCallback(IPackageInstallerCallback callback)1143     public void unregisterCallback(IPackageInstallerCallback callback) {
1144         mCallbacks.unregister(callback);
1145     }
1146 
1147     @Override
getSession(int sessionId)1148     public PackageInstallerSession getSession(int sessionId) {
1149         synchronized (mSessions) {
1150             return mSessions.get(sessionId);
1151         }
1152     }
1153 
1154     @Override
bypassNextStagedInstallerCheck(boolean value)1155     public void bypassNextStagedInstallerCheck(boolean value) {
1156         if (!isCalledBySystemOrShell(Binder.getCallingUid())) {
1157             throw new SecurityException("Caller not allowed to bypass staged installer check");
1158         }
1159         mBypassNextStagedInstallerCheck = value;
1160     }
1161 
1162     @Override
bypassNextAllowedApexUpdateCheck(boolean value)1163     public void bypassNextAllowedApexUpdateCheck(boolean value) {
1164         if (!isCalledBySystemOrShell(Binder.getCallingUid())) {
1165             throw new SecurityException("Caller not allowed to bypass allowed apex update check");
1166         }
1167         mBypassNextAllowedApexUpdateCheck = value;
1168     }
1169 
1170     /**
1171      * Set an installer to allow for the unlimited silent updates.
1172      */
1173     @Override
setAllowUnlimitedSilentUpdates(@ullable String installerPackageName)1174     public void setAllowUnlimitedSilentUpdates(@Nullable String installerPackageName) {
1175         if (!isCalledBySystemOrShell(Binder.getCallingUid())) {
1176             throw new SecurityException("Caller not allowed to unlimite silent updates");
1177         }
1178         mSilentUpdatePolicy.setAllowUnlimitedSilentUpdates(installerPackageName);
1179     }
1180 
1181     /**
1182      * Set the silent updates throttle time in seconds.
1183      */
1184     @Override
setSilentUpdatesThrottleTime(long throttleTimeInSeconds)1185     public void setSilentUpdatesThrottleTime(long throttleTimeInSeconds) {
1186         if (!isCalledBySystemOrShell(Binder.getCallingUid())) {
1187             throw new SecurityException("Caller not allowed to set silent updates throttle time");
1188         }
1189         mSilentUpdatePolicy.setSilentUpdatesThrottleTime(throttleTimeInSeconds);
1190     }
1191 
getSessionCount(SparseArray<PackageInstallerSession> sessions, int installerUid)1192     private static int getSessionCount(SparseArray<PackageInstallerSession> sessions,
1193             int installerUid) {
1194         int count = 0;
1195         final int size = sessions.size();
1196         for (int i = 0; i < size; i++) {
1197             final PackageInstallerSession session = sessions.valueAt(i);
1198             if (session.getInstallerUid() == installerUid) {
1199                 count++;
1200             }
1201         }
1202         return count;
1203     }
1204 
isCallingUidOwner(PackageInstallerSession session)1205     private boolean isCallingUidOwner(PackageInstallerSession session) {
1206         final int callingUid = Binder.getCallingUid();
1207         if (callingUid == Process.ROOT_UID) {
1208             return true;
1209         } else {
1210             return (session != null) && (callingUid == session.getInstallerUid());
1211         }
1212     }
1213 
1214     static class PackageDeleteObserverAdapter extends PackageDeleteObserver {
1215         private final Context mContext;
1216         private final IntentSender mTarget;
1217         private final String mPackageName;
1218         private final Notification mNotification;
1219 
PackageDeleteObserverAdapter(Context context, IntentSender target, String packageName, boolean showNotification, int userId)1220         public PackageDeleteObserverAdapter(Context context, IntentSender target,
1221                 String packageName, boolean showNotification, int userId) {
1222             mContext = context;
1223             mTarget = target;
1224             mPackageName = packageName;
1225             if (showNotification) {
1226                 mNotification = buildSuccessNotification(mContext,
1227                         mContext.getResources().getString(R.string.package_deleted_device_owner),
1228                         packageName,
1229                         userId);
1230             } else {
1231                 mNotification = null;
1232             }
1233         }
1234 
1235         @Override
onUserActionRequired(Intent intent)1236         public void onUserActionRequired(Intent intent) {
1237             if (mTarget == null) {
1238                 return;
1239             }
1240             final Intent fillIn = new Intent();
1241             fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName);
1242             fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
1243                     PackageInstaller.STATUS_PENDING_USER_ACTION);
1244             fillIn.putExtra(Intent.EXTRA_INTENT, intent);
1245             try {
1246                 mTarget.sendIntent(mContext, 0, fillIn, null, null);
1247             } catch (SendIntentException ignored) {
1248             }
1249         }
1250 
1251         @Override
onPackageDeleted(String basePackageName, int returnCode, String msg)1252         public void onPackageDeleted(String basePackageName, int returnCode, String msg) {
1253             if (PackageManager.DELETE_SUCCEEDED == returnCode && mNotification != null) {
1254                 NotificationManager notificationManager = (NotificationManager)
1255                         mContext.getSystemService(Context.NOTIFICATION_SERVICE);
1256                 notificationManager.notify(basePackageName,
1257                         SystemMessage.NOTE_PACKAGE_STATE,
1258                         mNotification);
1259             }
1260             if (mTarget == null) {
1261                 return;
1262             }
1263             final Intent fillIn = new Intent();
1264             fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName);
1265             fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
1266                     PackageManager.deleteStatusToPublicStatus(returnCode));
1267             fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
1268                     PackageManager.deleteStatusToString(returnCode, msg));
1269             fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode);
1270             try {
1271                 mTarget.sendIntent(mContext, 0, fillIn, null, null);
1272             } catch (SendIntentException ignored) {
1273             }
1274         }
1275     }
1276 
1277     /**
1278      * Build a notification for package installation / deletion by device owners that is shown if
1279      * the operation succeeds.
1280      */
buildSuccessNotification(Context context, String contentText, String basePackageName, int userId)1281     static Notification buildSuccessNotification(Context context, String contentText,
1282             String basePackageName, int userId) {
1283         PackageInfo packageInfo = null;
1284         try {
1285             packageInfo = AppGlobals.getPackageManager().getPackageInfo(
1286                     basePackageName, PackageManager.MATCH_STATIC_SHARED_LIBRARIES, userId);
1287         } catch (RemoteException ignored) {
1288         }
1289         if (packageInfo == null || packageInfo.applicationInfo == null) {
1290             Slog.w(TAG, "Notification not built for package: " + basePackageName);
1291             return null;
1292         }
1293         PackageManager pm = context.getPackageManager();
1294         Bitmap packageIcon = ImageUtils.buildScaledBitmap(
1295                 packageInfo.applicationInfo.loadIcon(pm),
1296                 context.getResources().getDimensionPixelSize(
1297                         android.R.dimen.notification_large_icon_width),
1298                 context.getResources().getDimensionPixelSize(
1299                         android.R.dimen.notification_large_icon_height));
1300         CharSequence packageLabel = packageInfo.applicationInfo.loadLabel(pm);
1301         return new Notification.Builder(context, SystemNotificationChannels.DEVICE_ADMIN)
1302                 .setSmallIcon(R.drawable.ic_check_circle_24px)
1303                 .setColor(context.getResources().getColor(
1304                         R.color.system_notification_accent_color))
1305                 .setContentTitle(packageLabel)
1306                 .setContentText(contentText)
1307                 .setStyle(new Notification.BigTextStyle().bigText(contentText))
1308                 .setLargeIcon(packageIcon)
1309                 .build();
1310     }
1311 
newArraySet(E... elements)1312     public static <E> ArraySet<E> newArraySet(E... elements) {
1313         final ArraySet<E> set = new ArraySet<E>();
1314         if (elements != null) {
1315             set.ensureCapacity(elements.length);
1316             Collections.addAll(set, elements);
1317         }
1318         return set;
1319     }
1320 
1321     private static class Callbacks extends Handler {
1322         private static final int MSG_SESSION_CREATED = 1;
1323         private static final int MSG_SESSION_BADGING_CHANGED = 2;
1324         private static final int MSG_SESSION_ACTIVE_CHANGED = 3;
1325         private static final int MSG_SESSION_PROGRESS_CHANGED = 4;
1326         private static final int MSG_SESSION_FINISHED = 5;
1327 
1328         private final RemoteCallbackList<IPackageInstallerCallback>
1329                 mCallbacks = new RemoteCallbackList<>();
1330 
Callbacks(Looper looper)1331         public Callbacks(Looper looper) {
1332             super(looper);
1333         }
1334 
register(IPackageInstallerCallback callback, IntPredicate userCheck)1335         public void register(IPackageInstallerCallback callback, IntPredicate userCheck) {
1336             mCallbacks.register(callback, userCheck);
1337         }
1338 
unregister(IPackageInstallerCallback callback)1339         public void unregister(IPackageInstallerCallback callback) {
1340             mCallbacks.unregister(callback);
1341         }
1342 
1343         @Override
handleMessage(Message msg)1344         public void handleMessage(Message msg) {
1345             final int userId = msg.arg2;
1346             final int n = mCallbacks.beginBroadcast();
1347             for (int i = 0; i < n; i++) {
1348                 final IPackageInstallerCallback callback = mCallbacks.getBroadcastItem(i);
1349                 final IntPredicate userCheck = (IntPredicate) mCallbacks.getBroadcastCookie(i);
1350                 if (userCheck.test(userId)) {
1351                     try {
1352                         invokeCallback(callback, msg);
1353                     } catch (RemoteException ignored) {
1354                     }
1355                 }
1356             }
1357             mCallbacks.finishBroadcast();
1358         }
1359 
invokeCallback(IPackageInstallerCallback callback, Message msg)1360         private void invokeCallback(IPackageInstallerCallback callback, Message msg)
1361                 throws RemoteException {
1362             final int sessionId = msg.arg1;
1363             switch (msg.what) {
1364                 case MSG_SESSION_CREATED:
1365                     callback.onSessionCreated(sessionId);
1366                     break;
1367                 case MSG_SESSION_BADGING_CHANGED:
1368                     callback.onSessionBadgingChanged(sessionId);
1369                     break;
1370                 case MSG_SESSION_ACTIVE_CHANGED:
1371                     callback.onSessionActiveChanged(sessionId, (boolean) msg.obj);
1372                     break;
1373                 case MSG_SESSION_PROGRESS_CHANGED:
1374                     callback.onSessionProgressChanged(sessionId, (float) msg.obj);
1375                     break;
1376                 case MSG_SESSION_FINISHED:
1377                     callback.onSessionFinished(sessionId, (boolean) msg.obj);
1378                     break;
1379             }
1380         }
1381 
notifySessionCreated(int sessionId, int userId)1382         private void notifySessionCreated(int sessionId, int userId) {
1383             obtainMessage(MSG_SESSION_CREATED, sessionId, userId).sendToTarget();
1384         }
1385 
notifySessionBadgingChanged(int sessionId, int userId)1386         private void notifySessionBadgingChanged(int sessionId, int userId) {
1387             obtainMessage(MSG_SESSION_BADGING_CHANGED, sessionId, userId).sendToTarget();
1388         }
1389 
notifySessionActiveChanged(int sessionId, int userId, boolean active)1390         private void notifySessionActiveChanged(int sessionId, int userId, boolean active) {
1391             obtainMessage(MSG_SESSION_ACTIVE_CHANGED, sessionId, userId, active).sendToTarget();
1392         }
1393 
notifySessionProgressChanged(int sessionId, int userId, float progress)1394         private void notifySessionProgressChanged(int sessionId, int userId, float progress) {
1395             obtainMessage(MSG_SESSION_PROGRESS_CHANGED, sessionId, userId, progress).sendToTarget();
1396         }
1397 
notifySessionFinished(int sessionId, int userId, boolean success)1398         public void notifySessionFinished(int sessionId, int userId, boolean success) {
1399             obtainMessage(MSG_SESSION_FINISHED, sessionId, userId, success).sendToTarget();
1400         }
1401     }
1402 
dump(IndentingPrintWriter pw)1403     void dump(IndentingPrintWriter pw) {
1404         synchronized (mSessions) {
1405             pw.println("Active install sessions:");
1406             pw.increaseIndent();
1407 
1408             List<PackageInstallerSession> finalizedSessions = new ArrayList<>();
1409             List<PackageInstallerSession> orphanedChildSessions = new ArrayList<>();
1410             int N = mSessions.size();
1411             for (int i = 0; i < N; i++) {
1412                 final PackageInstallerSession session = mSessions.valueAt(i);
1413 
1414                 final PackageInstallerSession rootSession = session.hasParentSessionId()
1415                         ? getSession(session.getParentSessionId())
1416                         : session;
1417                 // Do not print orphaned child sessions as active install sessions
1418                 if (rootSession == null) {
1419                     orphanedChildSessions.add(session);
1420                     continue;
1421                 }
1422 
1423                 // Do not print finalized staged session as active install sessions
1424                 if (rootSession.isStagedAndInTerminalState()) {
1425                     finalizedSessions.add(session);
1426                     continue;
1427                 }
1428 
1429                 session.dump(pw);
1430                 pw.println();
1431             }
1432             pw.println();
1433             pw.decreaseIndent();
1434 
1435             if (!orphanedChildSessions.isEmpty()) {
1436                 // Presence of orphaned sessions indicate leak in cleanup for multi-package and
1437                 // should be cleaned up.
1438                 pw.println("Orphaned install sessions:");
1439                 pw.increaseIndent();
1440                 N = orphanedChildSessions.size();
1441                 for (int i = 0; i < N; i++) {
1442                     final PackageInstallerSession session = orphanedChildSessions.get(i);
1443                     session.dump(pw);
1444                     pw.println();
1445                 }
1446                 pw.println();
1447                 pw.decreaseIndent();
1448             }
1449 
1450             pw.println("Finalized install sessions:");
1451             pw.increaseIndent();
1452             N = finalizedSessions.size();
1453             for (int i = 0; i < N; i++) {
1454                 final PackageInstallerSession session = finalizedSessions.get(i);
1455                 session.dump(pw);
1456                 pw.println();
1457             }
1458             pw.println();
1459             pw.decreaseIndent();
1460 
1461             pw.println("Historical install sessions:");
1462             pw.increaseIndent();
1463             N = mHistoricalSessions.size();
1464             for (int i = 0; i < N; i++) {
1465                 pw.print(mHistoricalSessions.get(i));
1466                 pw.println();
1467             }
1468             pw.println();
1469             pw.decreaseIndent();
1470 
1471             pw.println("Legacy install sessions:");
1472             pw.increaseIndent();
1473             pw.println(mLegacySessions.toString());
1474             pw.println();
1475             pw.decreaseIndent();
1476         }
1477         mSilentUpdatePolicy.dump(pw);
1478     }
1479 
1480     class InternalCallback {
onSessionBadgingChanged(PackageInstallerSession session)1481         public void onSessionBadgingChanged(PackageInstallerSession session) {
1482             mCallbacks.notifySessionBadgingChanged(session.sessionId, session.userId);
1483             mSettingsWriteRequest.schedule();
1484         }
1485 
onSessionActiveChanged(PackageInstallerSession session, boolean active)1486         public void onSessionActiveChanged(PackageInstallerSession session, boolean active) {
1487             mCallbacks.notifySessionActiveChanged(session.sessionId, session.userId,
1488                     active);
1489         }
1490 
onSessionProgressChanged(PackageInstallerSession session, float progress)1491         public void onSessionProgressChanged(PackageInstallerSession session, float progress) {
1492             mCallbacks.notifySessionProgressChanged(session.sessionId, session.userId,
1493                     progress);
1494         }
1495 
onStagedSessionChanged(PackageInstallerSession session)1496         public void onStagedSessionChanged(PackageInstallerSession session) {
1497             session.markUpdated();
1498             mSettingsWriteRequest.schedule();
1499             if (mOkToSendBroadcasts && !session.isDestroyed()) {
1500                 // we don't scrub the data here as this is sent only to the installer several
1501                 // privileged system packages
1502                 mPm.sendSessionUpdatedBroadcast(
1503                         session.generateInfoForCaller(false/*icon*/, Process.SYSTEM_UID),
1504                         session.userId);
1505             }
1506         }
1507 
onSessionFinished(final PackageInstallerSession session, boolean success)1508         public void onSessionFinished(final PackageInstallerSession session, boolean success) {
1509             mCallbacks.notifySessionFinished(session.sessionId, session.userId, success);
1510 
1511             mInstallHandler.post(new Runnable() {
1512                 @Override
1513                 public void run() {
1514                     if (session.isStaged() && !success) {
1515                         mStagingManager.abortSession(session.mStagedSession);
1516                     }
1517                     synchronized (mSessions) {
1518                         if (!session.isStaged() || !success) {
1519                             mSessions.remove(session.sessionId);
1520                         }
1521                         addHistoricalSessionLocked(session);
1522 
1523                         final File appIconFile = buildAppIconFile(session.sessionId);
1524                         if (appIconFile.exists()) {
1525                             appIconFile.delete();
1526                         }
1527 
1528                         mSettingsWriteRequest.runNow();
1529                     }
1530                 }
1531             });
1532         }
1533 
onSessionPrepared(PackageInstallerSession session)1534         public void onSessionPrepared(PackageInstallerSession session) {
1535             // We prepared the destination to write into; we want to persist
1536             // this, but it's not critical enough to block for.
1537             mSettingsWriteRequest.schedule();
1538         }
1539 
onSessionSealedBlocking(PackageInstallerSession session)1540         public void onSessionSealedBlocking(PackageInstallerSession session) {
1541             // It's very important that we block until we've recorded the
1542             // session as being sealed, since we never want to allow mutation
1543             // after sealing.
1544             mSettingsWriteRequest.runNow();
1545         }
1546     }
1547 }
1548