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