blob: b72e83692e8aef4e3e67c9c3aeb115de93ed917b [file] [log] [blame]
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001/*
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
17package com.android.server.pm;
18
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070019import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
20import static org.xmlpull.v1.XmlPullParser.START_TAG;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070021
Svetoslav805b63e2015-04-09 17:28:54 -070022import android.Manifest;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070023import android.app.ActivityManager;
Benjamin Franz39fb7fd2015-02-18 16:11:18 +000024import android.app.AppGlobals;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070025import android.app.AppOpsManager;
Benjamin Franz39fb7fd2015-02-18 16:11:18 +000026import android.app.Notification;
27import android.app.NotificationManager;
Jeff Sharkeya0907432014-08-15 10:23:11 -070028import android.app.PackageDeleteObserver;
29import android.app.PackageInstallObserver;
Benjamin Franzdabae882017-08-08 12:33:19 +010030import android.app.admin.DevicePolicyManagerInternal;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070031import android.content.Context;
Jeff Sharkeyf0600952014-08-07 17:31:53 -070032import android.content.Intent;
Jeff Sharkeya0907432014-08-15 10:23:11 -070033import android.content.IntentSender;
34import android.content.IntentSender.SendIntentException;
Philip P. Moltmannd9bb39a2017-09-05 12:41:15 -070035import android.content.pm.ApplicationInfo;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070036import android.content.pm.IPackageInstaller;
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -070037import android.content.pm.IPackageInstallerCallback;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070038import android.content.pm.IPackageInstallerSession;
Benjamin Franz39fb7fd2015-02-18 16:11:18 +000039import android.content.pm.PackageInfo;
Jeff Sharkeyf0600952014-08-07 17:31:53 -070040import android.content.pm.PackageInstaller;
Jeff Sharkeya0907432014-08-15 10:23:11 -070041import android.content.pm.PackageInstaller.SessionInfo;
42import android.content.pm.PackageInstaller.SessionParams;
Jeff Sharkeyec9bad22014-09-05 09:45:20 -070043import android.content.pm.PackageManager;
Jeff Sharkey97d47ed2014-10-15 09:19:47 -070044import android.content.pm.ParceledListSlice;
Svet Ganov67882122016-12-11 16:36:34 -080045import android.content.pm.VersionedPackage;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070046import android.graphics.Bitmap;
Jeff Sharkeyf0600952014-08-07 17:31:53 -070047import android.net.Uri;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070048import android.os.Binder;
Philip P. Moltmannd9bb39a2017-09-05 12:41:15 -070049import android.os.Build;
Jeff Sharkeya0907432014-08-15 10:23:11 -070050import android.os.Bundle;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070051import android.os.Environment;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070052import android.os.Handler;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070053import android.os.HandlerThread;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070054import android.os.Looper;
55import android.os.Message;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070056import android.os.Process;
Jeff Sharkeya1031142014-07-12 18:09:46 -070057import android.os.RemoteCallbackList;
58import android.os.RemoteException;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -070059import android.os.SELinux;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070060import android.os.UserManager;
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -070061import android.os.storage.StorageManager;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -070062import android.system.ErrnoException;
63import android.system.Os;
Jeff Sharkeya0907432014-08-15 10:23:11 -070064import android.text.TextUtils;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070065import android.text.format.DateUtils;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070066import android.util.ArraySet;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070067import android.util.AtomicFile;
Jeff Sharkeya1031142014-07-12 18:09:46 -070068import android.util.ExceptionUtils;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070069import android.util.Slog;
70import android.util.SparseArray;
Jeff Sharkey742e7902014-08-16 19:09:13 -070071import android.util.SparseBooleanArray;
Narayan Kamatha22a7662017-06-12 13:34:29 +010072import android.util.SparseIntArray;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070073import android.util.Xml;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070074
Benjamin Franz39fb7fd2015-02-18 16:11:18 +000075import com.android.internal.R;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070076import com.android.internal.annotations.GuardedBy;
Jeff Sharkey742e7902014-08-16 19:09:13 -070077import com.android.internal.content.PackageHelper;
Chris Wren282cfef2017-03-27 15:01:44 -040078import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
Geoffrey Pitschaf759c52017-02-15 09:35:38 -050079import com.android.internal.notification.SystemNotificationChannels;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070080import com.android.internal.util.FastXmlSerializer;
Benjamin Franz39fb7fd2015-02-18 16:11:18 +000081import com.android.internal.util.ImageUtils;
Jeff Sharkeya1031142014-07-12 18:09:46 -070082import com.android.internal.util.IndentingPrintWriter;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070083import com.android.server.IoThread;
Todd Kennedy0eb97382017-10-03 16:57:22 -070084import com.android.server.LocalServices;
Philip P. Moltmann48456672019-01-20 13:14:03 -080085import com.android.server.pm.permission.PermissionManagerServiceInternal;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070086
Philip P. Moltmann7460c592017-08-08 20:07:11 +000087import libcore.io.IoUtils;
88
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070089import org.xmlpull.v1.XmlPullParser;
90import org.xmlpull.v1.XmlPullParserException;
91import org.xmlpull.v1.XmlSerializer;
92
Philip P. Moltmann7460c592017-08-08 20:07:11 +000093import java.io.CharArrayWriter;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070094import java.io.File;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070095import java.io.FileInputStream;
96import java.io.FileNotFoundException;
97import java.io.FileOutputStream;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -070098import java.io.FilenameFilter;
99import java.io.IOException;
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +0100100import java.nio.charset.StandardCharsets;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700101import java.security.SecureRandom;
Jeff Sharkeybb580672014-07-10 12:10:25 -0700102import java.util.ArrayList;
Jeff Sharkey54d42be2015-07-20 16:36:55 -0700103import java.util.Collections;
Jeff Sharkeybb580672014-07-10 12:10:25 -0700104import java.util.List;
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700105import java.util.Objects;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700106import java.util.Random;
Jon Miranda2b340a22019-01-25 14:03:49 -0800107import java.util.function.IntPredicate;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700108
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000109/** The service responsible for installing packages. */
110public class PackageInstallerService extends IPackageInstaller.Stub implements
111 PackageSessionProvider {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700112 private static final String TAG = "PackageInstaller";
Jeff Sharkeye9808042014-09-11 21:15:37 -0700113 private static final boolean LOGD = false;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700114
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700115 // TODO: remove outstanding sessions when installer package goes away
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700116 // TODO: notify listeners in other users when package has been installed there
Jeff Sharkey742e7902014-08-16 19:09:13 -0700117 // TODO: purge expired sessions periodically in addition to at reboot
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700118
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700119 /** XML constants used in {@link #mSessionsFile} */
120 private static final String TAG_SESSIONS = "sessions";
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700121
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700122 /** Automatically destroy sessions older than this */
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700123 private static final long MAX_AGE_MILLIS = 3 * DateUtils.DAY_IN_MILLIS;
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700124 /** Upper bound on number of active sessions for a UID */
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700125 private static final long MAX_ACTIVE_SESSIONS = 1024;
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700126 /** Upper bound on number of historical sessions for a UID */
127 private static final long MAX_HISTORICAL_SESSIONS = 1048576;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700128
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700129 private final Context mContext;
130 private final PackageManagerService mPm;
Dario Freni83620602019-02-18 14:30:57 +0000131 private final ApexManager mApexManager;
Dario Frenibe98c3f2018-12-22 15:25:27 +0000132 private final StagingManager mStagingManager;
Philip P. Moltmann48456672019-01-20 13:14:03 -0800133 private final PermissionManagerServiceInternal mPermissionManager;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700134
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700135 private AppOpsManager mAppOps;
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700136
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700137 private final HandlerThread mInstallThread;
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700138 private final Handler mInstallHandler;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700139
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700140 private final Callbacks mCallbacks;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700141
Dario Freni14f885b2019-02-25 12:48:47 +0000142 private volatile boolean mOkToSendBroadcasts = false;
Dario Freni9694b802019-01-27 23:26:06 +0000143
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700144 /**
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700145 * File storing persisted {@link #mSessions} metadata.
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700146 */
147 private final AtomicFile mSessionsFile;
148
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700149 /**
150 * Directory storing persisted {@link #mSessions} metadata which is too
151 * heavy to store directly in {@link #mSessionsFile}.
152 */
153 private final File mSessionsDir;
154
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700155 private final InternalCallback mInternalCallback = new InternalCallback();
156
157 /**
158 * Used for generating session IDs. Since this is created at boot time,
159 * normal random might be predictable.
160 */
161 private final Random mRandom = new SecureRandom();
162
Todd Kennedy28c4e802016-07-13 13:20:30 -0700163 /** All sessions allocated */
164 @GuardedBy("mSessions")
165 private final SparseBooleanArray mAllocatedSessions = new SparseBooleanArray();
166
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700167 @GuardedBy("mSessions")
168 private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>();
169
Jeff Sharkey9a445772014-07-16 11:32:08 -0700170 /** Historical sessions kept around for debugging purposes */
171 @GuardedBy("mSessions")
Narayan Kamatha22a7662017-06-12 13:34:29 +0100172 private final List<String> mHistoricalSessions = new ArrayList<>();
173
174 @GuardedBy("mSessions")
175 private final SparseIntArray mHistoricalSessionsByInstaller = new SparseIntArray();
Jeff Sharkey9a445772014-07-16 11:32:08 -0700176
Jeff Sharkey742e7902014-08-16 19:09:13 -0700177 /** Sessions allocated to legacy users */
178 @GuardedBy("mSessions")
179 private final SparseBooleanArray mLegacySessions = new SparseBooleanArray();
180
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700181 private static final FilenameFilter sStageFilter = new FilenameFilter() {
182 @Override
183 public boolean accept(File dir, String name) {
Jeff Sharkey742e7902014-08-16 19:09:13 -0700184 return isStageName(name);
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700185 }
186 };
187
Dario Freni2e8dffc2019-02-06 14:55:16 +0000188 public PackageInstallerService(Context context, PackageManagerService pm, ApexManager am) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700189 mContext = context;
190 mPm = pm;
Philip P. Moltmann48456672019-01-20 13:14:03 -0800191 mPermissionManager = LocalServices.getService(PermissionManagerServiceInternal.class);
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700192
193 mInstallThread = new HandlerThread(TAG);
194 mInstallThread.start();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700195
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700196 mInstallHandler = new Handler(mInstallThread.getLooper());
197
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700198 mCallbacks = new Callbacks(mInstallThread.getLooper());
199
200 mSessionsFile = new AtomicFile(
Dianne Hackborne17b4452018-01-10 13:15:40 -0800201 new File(Environment.getDataSystemDirectory(), "install_sessions.xml"),
202 "package-session");
Jeff Sharkey8212ae02016-02-10 14:46:43 -0700203 mSessionsDir = new File(Environment.getDataSystemDirectory(), "install_sessions");
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700204 mSessionsDir.mkdirs();
Dario Frenibe98c3f2018-12-22 15:25:27 +0000205
Dario Freni83620602019-02-18 14:30:57 +0000206 mApexManager = am;
Nikita Ioffe39a6a5b2019-02-26 15:36:39 +0000207
208 mStagingManager = new StagingManager(pm, this, am, context);
Tony Mak606f8e72017-02-15 18:40:03 +0000209 }
210
Dario Freni14f885b2019-02-25 12:48:47 +0000211 boolean okToSendBroadcasts() {
212 return mOkToSendBroadcasts;
Dario Freni4b572c02019-01-29 09:40:31 +0000213 }
214
Tony Mak606f8e72017-02-15 18:40:03 +0000215 public void systemReady() {
216 mAppOps = mContext.getSystemService(AppOpsManager.class);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700217
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700218 synchronized (mSessions) {
219 readSessionsLocked();
220
Dario Frenia8f4b132018-12-30 00:36:49 +0000221 reconcileStagesLocked(StorageManager.UUID_PRIVATE_INTERNAL);
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700222
Jeff Sharkey54d42be2015-07-20 16:36:55 -0700223 final ArraySet<File> unclaimedIcons = newArraySet(
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700224 mSessionsDir.listFiles());
Jeff Sharkey742e7902014-08-16 19:09:13 -0700225
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700226 // Ignore stages and icons claimed by active sessions
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700227 for (int i = 0; i < mSessions.size(); i++) {
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700228 final PackageInstallerSession session = mSessions.valueAt(i);
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700229 unclaimedIcons.remove(buildAppIconFile(session.sessionId));
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700230 }
Jeff Sharkey742e7902014-08-16 19:09:13 -0700231
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700232 // Clean up orphaned icons
233 for (File icon : unclaimedIcons) {
234 Slog.w(TAG, "Deleting orphan icon " + icon);
235 icon.delete();
236 }
Dario Freni0180d0b2019-01-11 21:08:13 +0000237
238 // Invalid sessions might have been marked while parsing. Re-write the database with
239 // the updated information.
240 writeSessionsLocked();
241
Dario Freni4b572c02019-01-29 09:40:31 +0000242 }
243 }
244
245 void restoreAndApplyStagedSessionIfNeeded() {
246 List<PackageInstallerSession> stagedSessionsToRestore = new ArrayList<>();
247 synchronized (mSessions) {
Dario Freni0180d0b2019-01-11 21:08:13 +0000248 for (int i = 0; i < mSessions.size(); i++) {
249 final PackageInstallerSession session = mSessions.valueAt(i);
250 if (session.isStaged()) {
Dario Freni4b572c02019-01-29 09:40:31 +0000251 stagedSessionsToRestore.add(session);
Dario Freni0180d0b2019-01-11 21:08:13 +0000252 }
253 }
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700254 }
Dario Freni4b572c02019-01-29 09:40:31 +0000255 // Don't hold mSessions lock when calling restoreSession, since it might trigger an APK
256 // atomic install which needs to query sessions, which requires lock on mSessions.
257 for (PackageInstallerSession session : stagedSessionsToRestore) {
258 mStagingManager.restoreSession(session);
259 }
Dario Freni14f885b2019-02-25 12:48:47 +0000260 // Broadcasts are not sent while we restore sessions on boot, since no processes would be
261 // ready to listen to them. From now on, we greedily assume that broadcasts requests are
262 // safe to send out. The worst that can happen is that a broadcast is attempted before
263 // ActivityManagerService completes its own systemReady(), in which case it will be rejected
264 // with an otherwise harmless exception.
265 // A more appropriate way to do this would be to wait until the correct boot phase is
266 // reached, but since we are not a SystemService we can't override onBootPhase.
267 // Waiting on the BOOT_COMPLETED broadcast can take several minutes, so that's not a viable
268 // way either.
269 mOkToSendBroadcasts = true;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700270 }
271
Andreas Gampea36dc622018-02-05 17:19:22 -0800272 @GuardedBy("mSessions")
Dario Frenia8f4b132018-12-30 00:36:49 +0000273 private void reconcileStagesLocked(String volumeUuid) {
274 final File stagingDir = getTmpSessionDir(volumeUuid);
Jeff Sharkey54d42be2015-07-20 16:36:55 -0700275 final ArraySet<File> unclaimedStages = newArraySet(
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700276 stagingDir.listFiles(sStageFilter));
277
278 // Ignore stages claimed by active sessions
279 for (int i = 0; i < mSessions.size(); i++) {
280 final PackageInstallerSession session = mSessions.valueAt(i);
281 unclaimedStages.remove(session.stageDir);
282 }
283
284 // Clean up orphaned staging directories
285 for (File stage : unclaimedStages) {
286 Slog.w(TAG, "Deleting orphan stage " + stage);
287 synchronized (mPm.mInstallLock) {
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -0700288 mPm.removeCodePathLI(stage);
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700289 }
290 }
291 }
292
293 public void onPrivateVolumeMounted(String volumeUuid) {
294 synchronized (mSessions) {
Dario Frenia8f4b132018-12-30 00:36:49 +0000295 reconcileStagesLocked(volumeUuid);
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700296 }
297 }
298
Jeff Sharkey742e7902014-08-16 19:09:13 -0700299 public static boolean isStageName(String name) {
300 final boolean isFile = name.startsWith("vmdl") && name.endsWith(".tmp");
301 final boolean isContainer = name.startsWith("smdl") && name.endsWith(".tmp");
302 final boolean isLegacyContainer = name.startsWith("smdl2tmp");
303 return isFile || isContainer || isLegacyContainer;
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700304 }
305
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700306 @Deprecated
Todd Kennedy2699f062015-11-20 13:07:17 -0800307 public File allocateStageDirLegacy(String volumeUuid, boolean isEphemeral) throws IOException {
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700308 synchronized (mSessions) {
309 try {
310 final int sessionId = allocateSessionIdLocked();
Jeff Sharkey742e7902014-08-16 19:09:13 -0700311 mLegacySessions.put(sessionId, true);
Dario Frenia8f4b132018-12-30 00:36:49 +0000312 final File sessionStageDir = buildTmpSessionDir(sessionId, volumeUuid);
313 prepareStageDir(sessionStageDir);
314 return sessionStageDir;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700315 } catch (IllegalStateException e) {
316 throw new IOException(e);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700317 }
318 }
319 }
320
Jeff Sharkey742e7902014-08-16 19:09:13 -0700321 @Deprecated
322 public String allocateExternalStageCidLegacy() {
323 synchronized (mSessions) {
324 final int sessionId = allocateSessionIdLocked();
325 mLegacySessions.put(sessionId, true);
326 return "smdl" + sessionId + ".tmp";
327 }
328 }
329
Andreas Gampea36dc622018-02-05 17:19:22 -0800330 @GuardedBy("mSessions")
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700331 private void readSessionsLocked() {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700332 if (LOGD) Slog.v(TAG, "readSessionsLocked()");
333
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700334 mSessions.clear();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700335
336 FileInputStream fis = null;
337 try {
338 fis = mSessionsFile.openRead();
339 final XmlPullParser in = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +0100340 in.setInput(fis, StandardCharsets.UTF_8.name());
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700341
342 int type;
343 while ((type = in.next()) != END_DOCUMENT) {
344 if (type == START_TAG) {
345 final String tag = in.getName();
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000346 if (PackageInstallerSession.TAG_SESSION.equals(tag)) {
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -0700347 final PackageInstallerSession session;
348 try {
349 session = PackageInstallerSession.readFromXml(in, mInternalCallback,
Dario Frenibe98c3f2018-12-22 15:25:27 +0000350 mContext, mPm, mInstallThread.getLooper(), mStagingManager,
351 mSessionsDir, this);
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -0700352 } catch (Exception e) {
353 Slog.e(TAG, "Could not read session", e);
354 continue;
355 }
356
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700357 final long age = System.currentTimeMillis() - session.createdMillis;
358
359 final boolean valid;
360 if (age >= MAX_AGE_MILLIS) {
361 Slog.w(TAG, "Abandoning old session first created at "
362 + session.createdMillis);
363 valid = false;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700364 } else {
365 valid = true;
366 }
367
368 if (valid) {
369 mSessions.put(session.sessionId, session);
370 } else {
371 // Since this is early during boot we don't send
372 // any observer events about the session, but we
373 // keep details around for dumpsys.
Narayan Kamatha22a7662017-06-12 13:34:29 +0100374 addHistoricalSessionLocked(session);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700375 }
Todd Kennedy28c4e802016-07-13 13:20:30 -0700376 mAllocatedSessions.put(session.sessionId, true);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700377 }
378 }
379 }
380 } catch (FileNotFoundException e) {
381 // Missing sessions are okay, probably first boot
Svet Ganov7121e182015-07-13 22:38:12 -0700382 } catch (IOException | XmlPullParserException e) {
Dianne Hackborn8d051722014-10-01 14:59:58 -0700383 Slog.wtf(TAG, "Failed reading install sessions", e);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700384 } finally {
385 IoUtils.closeQuietly(fis);
386 }
387 }
388
Andreas Gampea36dc622018-02-05 17:19:22 -0800389 @GuardedBy("mSessions")
Narayan Kamatha22a7662017-06-12 13:34:29 +0100390 private void addHistoricalSessionLocked(PackageInstallerSession session) {
391 CharArrayWriter writer = new CharArrayWriter();
392 IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
393 session.dump(pw);
394 mHistoricalSessions.add(writer.toString());
395
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000396 int installerUid = session.getInstallerUid();
Narayan Kamatha22a7662017-06-12 13:34:29 +0100397 // Increment the number of sessions by this installerUid.
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000398 mHistoricalSessionsByInstaller.put(installerUid,
399 mHistoricalSessionsByInstaller.get(installerUid) + 1);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700400 }
401
Andreas Gampea36dc622018-02-05 17:19:22 -0800402 @GuardedBy("mSessions")
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700403 private void writeSessionsLocked() {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700404 if (LOGD) Slog.v(TAG, "writeSessionsLocked()");
405
406 FileOutputStream fos = null;
407 try {
408 fos = mSessionsFile.startWrite();
409
410 XmlSerializer out = new FastXmlSerializer();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +0100411 out.setOutput(fos, StandardCharsets.UTF_8.name());
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700412 out.startDocument(null, true);
413 out.startTag(null, TAG_SESSIONS);
414 final int size = mSessions.size();
415 for (int i = 0; i < size; i++) {
416 final PackageInstallerSession session = mSessions.valueAt(i);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000417 session.write(out, mSessionsDir);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700418 }
419 out.endTag(null, TAG_SESSIONS);
420 out.endDocument();
421
422 mSessionsFile.finishWrite(fos);
423 } catch (IOException e) {
424 if (fos != null) {
425 mSessionsFile.failWrite(fos);
426 }
427 }
428 }
429
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700430 private File buildAppIconFile(int sessionId) {
431 return new File(mSessionsDir, "app_icon." + sessionId + ".png");
432 }
433
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700434 private void writeSessionsAsync() {
435 IoThread.getHandler().post(new Runnable() {
436 @Override
437 public void run() {
438 synchronized (mSessions) {
439 writeSessionsLocked();
440 }
441 }
442 });
443 }
444
445 @Override
Jeff Sharkeya0907432014-08-15 10:23:11 -0700446 public int createSession(SessionParams params, String installerPackageName, int userId) {
Jeff Sharkey742e7902014-08-16 19:09:13 -0700447 try {
448 return createSessionInternal(params, installerPackageName, userId);
449 } catch (IOException e) {
450 throw ExceptionUtils.wrap(e);
451 }
452 }
453
454 private int createSessionInternal(SessionParams params, String installerPackageName, int userId)
455 throws IOException {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700456 final int callingUid = Binder.getCallingUid();
Todd Kennedy0eb97382017-10-03 16:57:22 -0700457 mPermissionManager.enforceCrossUserPermission(
458 callingUid, userId, true, true, "createSession");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700459
Jeff Sharkeye9808042014-09-11 21:15:37 -0700460 if (mPm.isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700461 throw new SecurityException("User restriction prevents installing");
462 }
463
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700464 if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {
Jeff Sharkeye9808042014-09-11 21:15:37 -0700465 params.installFlags |= PackageManager.INSTALL_FROM_ADB;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700466
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700467 } else {
Philip P. Moltmann79c238a2017-12-13 15:59:07 -0800468 // Only apps with INSTALL_PACKAGES are allowed to set an installer that is not the
469 // caller.
470 if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES) !=
471 PackageManager.PERMISSION_GRANTED) {
472 mAppOps.checkPackage(callingUid, installerPackageName);
473 }
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700474
Jeff Sharkeye9808042014-09-11 21:15:37 -0700475 params.installFlags &= ~PackageManager.INSTALL_FROM_ADB;
476 params.installFlags &= ~PackageManager.INSTALL_ALL_USERS;
477 params.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
Todd Kennedy78a72502017-07-19 12:49:30 -0700478 if ((params.installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0
479 && !mPm.isCallerVerifier(callingUid)) {
480 params.installFlags &= ~PackageManager.INSTALL_VIRTUAL_PRELOAD;
481 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700482 }
483
Nikita Ioffe4501c112019-02-22 11:51:09 +0000484 boolean isApex = (params.installFlags & PackageManager.INSTALL_APEX) != 0;
485 if (params.isStaged || isApex) {
Dario Freni77786d92019-02-08 17:26:05 +0000486 mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, TAG);
487 }
488
Nikita Ioffe4501c112019-02-22 11:51:09 +0000489 if (isApex) {
Dario Freni83620602019-02-18 14:30:57 +0000490 if (!mApexManager.isApexSupported()) {
491 throw new IllegalArgumentException(
492 "This device doesn't support the installation of APEX files");
493 }
494 if (!params.isStaged) {
495 throw new IllegalArgumentException(
496 "APEX files can only be installed as part of a staged session.");
497 }
498 }
499
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000500 if (!params.isMultiPackage) {
501 // Only system components can circumvent runtime permissions when installing.
502 if ((params.installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0
503 && mContext.checkCallingOrSelfPermission(Manifest.permission
504 .INSTALL_GRANT_RUNTIME_PERMISSIONS) == PackageManager.PERMISSION_DENIED) {
505 throw new SecurityException("You need the "
506 + "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS permission "
507 + "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag");
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700508 }
509
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000510 // Defensively resize giant app icons
511 if (params.appIcon != null) {
512 final ActivityManager am = (ActivityManager) mContext.getSystemService(
513 Context.ACTIVITY_SERVICE);
514 final int iconSize = am.getLauncherLargeIconSize();
515 if ((params.appIcon.getWidth() > iconSize * 2)
516 || (params.appIcon.getHeight() > iconSize * 2)) {
517 params.appIcon = Bitmap.createScaledBitmap(params.appIcon, iconSize, iconSize,
518 true);
519 }
520 }
Jeff Sharkeyab234092015-06-09 21:42:22 -0700521
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000522 switch (params.mode) {
523 case SessionParams.MODE_FULL_INSTALL:
524 case SessionParams.MODE_INHERIT_EXISTING:
525 break;
526 default:
527 throw new IllegalArgumentException("Invalid install mode: " + params.mode);
528 }
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700529
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000530 // If caller requested explicit location, sanity check it, otherwise
531 // resolve the best internal or adopted location.
532 if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
533 if (!PackageHelper.fitsOnInternal(mContext, params)) {
534 throw new IOException("No suitable internal storage available");
535 }
Patrick Baumannff10c9c2018-12-11 15:17:38 -0800536 } else if ((params.installFlags & PackageManager.INSTALL_FORCE_VOLUME_UUID) != 0) {
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000537 // For now, installs to adopted media are treated as internal from
538 // an install flag point-of-view.
Patrick Baumannfc2851e2018-11-13 15:23:22 -0800539 params.installFlags |= PackageManager.INSTALL_INTERNAL;
Patrick Baumannff10c9c2018-12-11 15:17:38 -0800540 } else {
541 params.installFlags |= PackageManager.INSTALL_INTERNAL;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000542
543 // Resolve best location for install, based on combination of
544 // requested install flags, delta size, and manifest settings.
545 final long ident = Binder.clearCallingIdentity();
546 try {
547 params.volumeUuid = PackageHelper.resolveInstallVolume(mContext, params);
548 } finally {
549 Binder.restoreCallingIdentity(ident);
550 }
Robin Leee812d902014-08-21 16:51:18 +0100551 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700552 }
553
554 final int sessionId;
555 final PackageInstallerSession session;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700556 synchronized (mSessions) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700557 // Sanity check that installer isn't going crazy
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700558 final int activeCount = getSessionCount(mSessions, callingUid);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700559 if (activeCount >= MAX_ACTIVE_SESSIONS) {
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700560 throw new IllegalStateException(
561 "Too many active sessions for UID " + callingUid);
562 }
Narayan Kamatha22a7662017-06-12 13:34:29 +0100563 final int historicalCount = mHistoricalSessionsByInstaller.get(callingUid);
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700564 if (historicalCount >= MAX_HISTORICAL_SESSIONS) {
565 throw new IllegalStateException(
566 "Too many historical sessions for UID " + callingUid);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700567 }
568
Jeff Sharkeya1031142014-07-12 18:09:46 -0700569 sessionId = allocateSessionIdLocked();
Todd Kennedy04918fe2016-07-12 14:07:40 -0700570 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700571
Todd Kennedy04918fe2016-07-12 14:07:40 -0700572 final long createdMillis = System.currentTimeMillis();
573 // We're staging to exactly one location
574 File stageDir = null;
575 String stageCid = null;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000576 if (!params.isMultiPackage) {
577 if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
Dario Frenia8f4b132018-12-30 00:36:49 +0000578 stageDir = buildSessionDir(sessionId, params);
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000579 } else {
580 stageCid = buildExternalStageCid(sessionId);
581 }
Todd Kennedy04918fe2016-07-12 14:07:40 -0700582 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000583 session = new PackageInstallerSession(mInternalCallback, mContext, mPm, this,
Dario Frenibe98c3f2018-12-22 15:25:27 +0000584 mInstallThread.getLooper(), mStagingManager, sessionId, userId,
585 installerPackageName, callingUid, params, createdMillis, stageDir, stageCid, false,
Dario Frenib6d28962019-01-31 15:52:24 +0000586 false, null, SessionInfo.INVALID_ID, false, false, false,
587 SessionInfo.STAGED_SESSION_NO_ERROR, "");
Todd Kennedy04918fe2016-07-12 14:07:40 -0700588
589 synchronized (mSessions) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700590 mSessions.put(sessionId, session);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700591 }
Dario Freniaac4ba42018-12-06 15:47:16 +0000592 if (params.isStaged) {
Dario Frenibe98c3f2018-12-22 15:25:27 +0000593 mStagingManager.createSession(session);
Dario Freniaac4ba42018-12-06 15:47:16 +0000594 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700595
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700596 mCallbacks.notifySessionCreated(session.sessionId, session.userId);
Jeff Sharkeya1031142014-07-12 18:09:46 -0700597 writeSessionsAsync();
598 return sessionId;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700599 }
600
Jeff Sharkey381d94b2014-08-24 14:45:56 -0700601 @Override
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700602 public void updateSessionAppIcon(int sessionId, Bitmap appIcon) {
603 synchronized (mSessions) {
604 final PackageInstallerSession session = mSessions.get(sessionId);
605 if (session == null || !isCallingUidOwner(session)) {
606 throw new SecurityException("Caller has no access to session " + sessionId);
607 }
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700608
609 // Defensively resize giant app icons
610 if (appIcon != null) {
611 final ActivityManager am = (ActivityManager) mContext.getSystemService(
612 Context.ACTIVITY_SERVICE);
613 final int iconSize = am.getLauncherLargeIconSize();
614 if ((appIcon.getWidth() > iconSize * 2)
615 || (appIcon.getHeight() > iconSize * 2)) {
616 appIcon = Bitmap.createScaledBitmap(appIcon, iconSize, iconSize, true);
617 }
618 }
619
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700620 session.params.appIcon = appIcon;
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700621 session.params.appIconLastModified = -1;
622
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700623 mInternalCallback.onSessionBadgingChanged(session);
624 }
625 }
626
627 @Override
628 public void updateSessionAppLabel(int sessionId, String appLabel) {
629 synchronized (mSessions) {
630 final PackageInstallerSession session = mSessions.get(sessionId);
631 if (session == null || !isCallingUidOwner(session)) {
632 throw new SecurityException("Caller has no access to session " + sessionId);
633 }
634 session.params.appLabel = appLabel;
635 mInternalCallback.onSessionBadgingChanged(session);
636 }
637 }
638
639 @Override
Jeff Sharkey381d94b2014-08-24 14:45:56 -0700640 public void abandonSession(int sessionId) {
641 synchronized (mSessions) {
642 final PackageInstallerSession session = mSessions.get(sessionId);
643 if (session == null || !isCallingUidOwner(session)) {
644 throw new SecurityException("Caller has no access to session " + sessionId);
645 }
646 session.abandon();
647 }
648 }
649
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700650 @Override
651 public IPackageInstallerSession openSession(int sessionId) {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700652 try {
653 return openSessionInternal(sessionId);
654 } catch (IOException e) {
655 throw ExceptionUtils.wrap(e);
656 }
657 }
658
659 private IPackageInstallerSession openSessionInternal(int sessionId) throws IOException {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700660 synchronized (mSessions) {
661 final PackageInstallerSession session = mSessions.get(sessionId);
Jeff Sharkey381d94b2014-08-24 14:45:56 -0700662 if (session == null || !isCallingUidOwner(session)) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700663 throw new SecurityException("Caller has no access to session " + sessionId);
664 }
Jeff Sharkey742e7902014-08-16 19:09:13 -0700665 session.open();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700666 return session;
667 }
668 }
669
Andreas Gampea36dc622018-02-05 17:19:22 -0800670 @GuardedBy("mSessions")
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700671 private int allocateSessionIdLocked() {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700672 int n = 0;
673 int sessionId;
674 do {
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700675 sessionId = mRandom.nextInt(Integer.MAX_VALUE - 1) + 1;
Todd Kennedy28c4e802016-07-13 13:20:30 -0700676 if (!mAllocatedSessions.get(sessionId, false)) {
677 mAllocatedSessions.put(sessionId, true);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700678 return sessionId;
679 }
680 } while (n++ < 32);
681
682 throw new IllegalStateException("Failed to allocate session ID");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700683 }
684
Dario Frenia8f4b132018-12-30 00:36:49 +0000685 private File getTmpSessionDir(String volumeUuid) {
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700686 return Environment.getDataAppDirectory(volumeUuid);
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700687 }
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700688
Dario Frenia8f4b132018-12-30 00:36:49 +0000689 private File buildTmpSessionDir(int sessionId, String volumeUuid) {
690 final File sessionStagingDir = getTmpSessionDir(volumeUuid);
691 return new File(sessionStagingDir, "vmdl" + sessionId + ".tmp");
692 }
693
694 private File buildSessionDir(int sessionId, SessionParams params) {
695 if (params.isStaged) {
696 final File sessionStagingDir = Environment.getDataStagingDirectory(params.volumeUuid);
697 return new File(sessionStagingDir, "session_" + sessionId);
698 }
699 return buildTmpSessionDir(sessionId, params.volumeUuid);
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700700 }
701
702 static void prepareStageDir(File stageDir) throws IOException {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700703 if (stageDir.exists()) {
704 throw new IOException("Session dir already exists: " + stageDir);
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700705 }
706
707 try {
Dario Frenid8bf22e2018-08-31 14:18:04 +0100708 Os.mkdir(stageDir.getAbsolutePath(), 0775);
709 Os.chmod(stageDir.getAbsolutePath(), 0775);
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700710 } catch (ErrnoException e) {
711 // This purposefully throws if directory already exists
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700712 throw new IOException("Failed to prepare session dir: " + stageDir, e);
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700713 }
714
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700715 if (!SELinux.restorecon(stageDir)) {
716 throw new IOException("Failed to restorecon session dir: " + stageDir);
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700717 }
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700718 }
719
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700720 private String buildExternalStageCid(int sessionId) {
721 return "smdl" + sessionId + ".tmp";
722 }
Jeff Sharkey742e7902014-08-16 19:09:13 -0700723
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700724 @Override
Jeff Sharkeya0907432014-08-15 10:23:11 -0700725 public SessionInfo getSessionInfo(int sessionId) {
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700726 synchronized (mSessions) {
727 final PackageInstallerSession session = mSessions.get(sessionId);
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700728 return session != null ? session.generateInfo() : null;
729 }
730 }
731
732 @Override
Dario Freniaac4ba42018-12-06 15:47:16 +0000733 public ParceledListSlice<SessionInfo> getStagedSessions() {
Dario Frenibe98c3f2018-12-22 15:25:27 +0000734 return mStagingManager.getSessions();
Dario Freniaac4ba42018-12-06 15:47:16 +0000735 }
736
737 @Override
Jeff Sharkey97d47ed2014-10-15 09:19:47 -0700738 public ParceledListSlice<SessionInfo> getAllSessions(int userId) {
Todd Kennedy0eb97382017-10-03 16:57:22 -0700739 mPermissionManager.enforceCrossUserPermission(
740 Binder.getCallingUid(), userId, true, false, "getAllSessions");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700741
Jeff Sharkeya0907432014-08-15 10:23:11 -0700742 final List<SessionInfo> result = new ArrayList<>();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700743 synchronized (mSessions) {
744 for (int i = 0; i < mSessions.size(); i++) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700745 final PackageInstallerSession session = mSessions.valueAt(i);
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000746 if (session.userId == userId && !session.hasParentSessionId()) {
Jeff Sharkeyda1247a2017-06-08 14:13:29 -0600747 result.add(session.generateInfo(false));
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700748 }
749 }
750 }
Jeff Sharkey97d47ed2014-10-15 09:19:47 -0700751 return new ParceledListSlice<>(result);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700752 }
753
754 @Override
Jeff Sharkey97d47ed2014-10-15 09:19:47 -0700755 public ParceledListSlice<SessionInfo> getMySessions(String installerPackageName, int userId) {
Todd Kennedy0eb97382017-10-03 16:57:22 -0700756 mPermissionManager.enforceCrossUserPermission(
757 Binder.getCallingUid(), userId, true, false, "getMySessions");
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700758 mAppOps.checkPackage(Binder.getCallingUid(), installerPackageName);
759
Jeff Sharkeya0907432014-08-15 10:23:11 -0700760 final List<SessionInfo> result = new ArrayList<>();
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700761 synchronized (mSessions) {
762 for (int i = 0; i < mSessions.size(); i++) {
763 final PackageInstallerSession session = mSessions.valueAt(i);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000764
765 SessionInfo info = session.generateInfo(false);
766 if (Objects.equals(info.getInstallerPackageName(), installerPackageName)
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000767 && session.userId == userId && !session.hasParentSessionId()) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000768 result.add(info);
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700769 }
770 }
771 }
Jeff Sharkey97d47ed2014-10-15 09:19:47 -0700772 return new ParceledListSlice<>(result);
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700773 }
774
775 @Override
Svet Ganov67882122016-12-11 16:36:34 -0800776 public void uninstall(VersionedPackage versionedPackage, String callerPackageName, int flags,
777 IntentSender statusReceiver, int userId) throws RemoteException {
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000778 final int callingUid = Binder.getCallingUid();
Todd Kennedy0eb97382017-10-03 16:57:22 -0700779 mPermissionManager.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000780 if ((callingUid != Process.SHELL_UID) && (callingUid != Process.ROOT_UID)) {
781 mAppOps.checkPackage(callingUid, callerPackageName);
782 }
783
Benjamin Franzdabae882017-08-08 12:33:19 +0100784 // Check whether the caller is device owner or affiliated profile owner, in which case we do
785 // it silently.
Benjamin Franzdabae882017-08-08 12:33:19 +0100786 DevicePolicyManagerInternal dpmi =
787 LocalServices.getService(DevicePolicyManagerInternal.class);
Rubin Xufd4a3b42018-12-05 16:03:27 +0000788 final boolean canSilentlyInstallPackage =
789 dpmi != null && dpmi.canSilentlyInstallPackage(callerPackageName, callingUid);
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700790
Jeff Sharkeya0907432014-08-15 10:23:11 -0700791 final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext,
Benjamin Franzdabae882017-08-08 12:33:19 +0100792 statusReceiver, versionedPackage.getPackageName(),
Rubin Xufd4a3b42018-12-05 16:03:27 +0000793 canSilentlyInstallPackage, userId);
Sudheer Shanka72de4dd2016-07-22 15:46:37 -0700794 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES)
795 == PackageManager.PERMISSION_GRANTED) {
Jeff Sharkeyf0600952014-08-07 17:31:53 -0700796 // Sweet, call straight through!
Svet Ganov67882122016-12-11 16:36:34 -0800797 mPm.deletePackageVersioned(versionedPackage, adapter.getBinder(), userId, flags);
Rubin Xufd4a3b42018-12-05 16:03:27 +0000798 } else if (canSilentlyInstallPackage) {
Benjamin Franzdabae882017-08-08 12:33:19 +0100799 // Allow the device owner and affiliated profile owner to silently delete packages
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000800 // Need to clear the calling identity to get DELETE_PACKAGES permission
801 long ident = Binder.clearCallingIdentity();
802 try {
Svet Ganov67882122016-12-11 16:36:34 -0800803 mPm.deletePackageVersioned(versionedPackage, adapter.getBinder(), userId, flags);
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000804 } finally {
805 Binder.restoreCallingIdentity(ident);
806 }
Jeff Sharkeyf0600952014-08-07 17:31:53 -0700807 } else {
Philip P. Moltmannd9bb39a2017-09-05 12:41:15 -0700808 ApplicationInfo appInfo = mPm.getApplicationInfo(callerPackageName, 0, userId);
809 if (appInfo.targetSdkVersion >= Build.VERSION_CODES.P) {
810 mContext.enforceCallingOrSelfPermission(Manifest.permission.REQUEST_DELETE_PACKAGES,
811 null);
812 }
813
Jeff Sharkeyf0600952014-08-07 17:31:53 -0700814 // Take a short detour to confirm with user
815 final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
Svet Ganov67882122016-12-11 16:36:34 -0800816 intent.setData(Uri.fromParts("package", versionedPackage.getPackageName(), null));
Jeff Sharkeya0907432014-08-15 10:23:11 -0700817 intent.putExtra(PackageInstaller.EXTRA_CALLBACK, adapter.getBinder().asBinder());
818 adapter.onUserActionRequired(intent);
Jeff Sharkeyf0600952014-08-07 17:31:53 -0700819 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700820 }
821
822 @Override
Chandan Nathe8e463b2019-01-28 15:23:38 +0000823 public void installExistingPackage(String packageName, int installFlags, int installReason,
824 IntentSender statusReceiver, int userId) {
825 mPm.installExistingPackageAsUser(packageName, userId, installFlags, installReason,
826 statusReceiver);
827 }
828
829 @Override
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700830 public void setPermissionsResult(int sessionId, boolean accepted) {
831 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, TAG);
832
833 synchronized (mSessions) {
Svet Ganov3baa8762016-04-08 09:22:54 -0700834 PackageInstallerSession session = mSessions.get(sessionId);
835 if (session != null) {
836 session.setPermissionsResult(accepted);
837 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700838 }
839 }
840
841 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700842 public void registerCallback(IPackageInstallerCallback callback, int userId) {
Todd Kennedy0eb97382017-10-03 16:57:22 -0700843 mPermissionManager.enforceCrossUserPermission(
844 Binder.getCallingUid(), userId, true, false, "registerCallback");
Jon Miranda2b340a22019-01-25 14:03:49 -0800845 registerCallback(callback, eventUserId -> userId == eventUserId);
846 }
847
848 /**
849 * Assume permissions already checked and caller's identity cleared
850 */
851 public void registerCallback(IPackageInstallerCallback callback, IntPredicate userCheck) {
852 mCallbacks.register(callback, userCheck);
Jeff Sharkeybb580672014-07-10 12:10:25 -0700853 }
854
855 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700856 public void unregisterCallback(IPackageInstallerCallback callback) {
857 mCallbacks.unregister(callback);
Jeff Sharkeya1031142014-07-12 18:09:46 -0700858 }
859
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000860 @Override
861 public PackageInstallerSession getSession(int sessionId) {
862 synchronized (mSessions) {
863 return mSessions.get(sessionId);
864 }
865 }
866
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700867 private static int getSessionCount(SparseArray<PackageInstallerSession> sessions,
868 int installerUid) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700869 int count = 0;
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700870 final int size = sessions.size();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700871 for (int i = 0; i < size; i++) {
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700872 final PackageInstallerSession session = sessions.valueAt(i);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000873 if (session.getInstallerUid() == installerUid) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700874 count++;
875 }
876 }
877 return count;
878 }
879
880 private boolean isCallingUidOwner(PackageInstallerSession session) {
881 final int callingUid = Binder.getCallingUid();
882 if (callingUid == Process.ROOT_UID) {
883 return true;
884 } else {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000885 return (session != null) && (callingUid == session.getInstallerUid());
Jeff Sharkeya1031142014-07-12 18:09:46 -0700886 }
887 }
888
Jeff Sharkeya0907432014-08-15 10:23:11 -0700889 static class PackageDeleteObserverAdapter extends PackageDeleteObserver {
890 private final Context mContext;
891 private final IntentSender mTarget;
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700892 private final String mPackageName;
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000893 private final Notification mNotification;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700894
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700895 public PackageDeleteObserverAdapter(Context context, IntentSender target,
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000896 String packageName, boolean showNotification, int userId) {
Jeff Sharkeya0907432014-08-15 10:23:11 -0700897 mContext = context;
898 mTarget = target;
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700899 mPackageName = packageName;
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000900 if (showNotification) {
901 mNotification = buildSuccessNotification(mContext,
902 mContext.getResources().getString(R.string.package_deleted_device_owner),
903 packageName,
904 userId);
905 } else {
906 mNotification = null;
907 }
Jeff Sharkeya0907432014-08-15 10:23:11 -0700908 }
909
910 @Override
911 public void onUserActionRequired(Intent intent) {
912 final Intent fillIn = new Intent();
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700913 fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName);
Jeff Sharkeya0907432014-08-15 10:23:11 -0700914 fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
Jeff Sharkey742e7902014-08-16 19:09:13 -0700915 PackageInstaller.STATUS_PENDING_USER_ACTION);
Jeff Sharkeya0907432014-08-15 10:23:11 -0700916 fillIn.putExtra(Intent.EXTRA_INTENT, intent);
917 try {
918 mTarget.sendIntent(mContext, 0, fillIn, null, null);
919 } catch (SendIntentException ignored) {
920 }
921 }
922
923 @Override
924 public void onPackageDeleted(String basePackageName, int returnCode, String msg) {
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000925 if (PackageManager.DELETE_SUCCEEDED == returnCode && mNotification != null) {
926 NotificationManager notificationManager = (NotificationManager)
927 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
Chris Wren282cfef2017-03-27 15:01:44 -0400928 notificationManager.notify(basePackageName,
929 SystemMessage.NOTE_PACKAGE_STATE,
930 mNotification);
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000931 }
Jeff Sharkeya0907432014-08-15 10:23:11 -0700932 final Intent fillIn = new Intent();
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700933 fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName);
Jeff Sharkeya0907432014-08-15 10:23:11 -0700934 fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
935 PackageManager.deleteStatusToPublicStatus(returnCode));
936 fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
937 PackageManager.deleteStatusToString(returnCode, msg));
938 fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode);
939 try {
940 mTarget.sendIntent(mContext, 0, fillIn, null, null);
941 } catch (SendIntentException ignored) {
942 }
943 }
944 }
945
946 static class PackageInstallObserverAdapter extends PackageInstallObserver {
947 private final Context mContext;
948 private final IntentSender mTarget;
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700949 private final int mSessionId;
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000950 private final boolean mShowNotification;
951 private final int mUserId;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700952
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000953 public PackageInstallObserverAdapter(Context context, IntentSender target, int sessionId,
954 boolean showNotification, int userId) {
Jeff Sharkeya0907432014-08-15 10:23:11 -0700955 mContext = context;
956 mTarget = target;
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700957 mSessionId = sessionId;
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000958 mShowNotification = showNotification;
959 mUserId = userId;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700960 }
961
962 @Override
963 public void onUserActionRequired(Intent intent) {
964 final Intent fillIn = new Intent();
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700965 fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId);
Jeff Sharkeya0907432014-08-15 10:23:11 -0700966 fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
Jeff Sharkey742e7902014-08-16 19:09:13 -0700967 PackageInstaller.STATUS_PENDING_USER_ACTION);
Jeff Sharkeya0907432014-08-15 10:23:11 -0700968 fillIn.putExtra(Intent.EXTRA_INTENT, intent);
969 try {
970 mTarget.sendIntent(mContext, 0, fillIn, null, null);
971 } catch (SendIntentException ignored) {
972 }
973 }
974
975 @Override
976 public void onPackageInstalled(String basePackageName, int returnCode, String msg,
977 Bundle extras) {
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000978 if (PackageManager.INSTALL_SUCCEEDED == returnCode && mShowNotification) {
Benjamin Franz2e3e9432015-04-17 15:28:17 +0100979 boolean update = (extras != null) && extras.getBoolean(Intent.EXTRA_REPLACING);
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000980 Notification notification = buildSuccessNotification(mContext,
Benjamin Franz2e3e9432015-04-17 15:28:17 +0100981 mContext.getResources()
982 .getString(update ? R.string.package_updated_device_owner :
983 R.string.package_installed_device_owner),
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000984 basePackageName,
985 mUserId);
986 if (notification != null) {
987 NotificationManager notificationManager = (NotificationManager)
988 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
Chris Wren282cfef2017-03-27 15:01:44 -0400989 notificationManager.notify(basePackageName,
990 SystemMessage.NOTE_PACKAGE_STATE,
991 notification);
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000992 }
993 }
Jeff Sharkeya0907432014-08-15 10:23:11 -0700994 final Intent fillIn = new Intent();
Benjamin Franz2e3e9432015-04-17 15:28:17 +0100995 fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, basePackageName);
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700996 fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId);
Jeff Sharkeya0907432014-08-15 10:23:11 -0700997 fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
998 PackageManager.installStatusToPublicStatus(returnCode));
999 fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
1000 PackageManager.installStatusToString(returnCode, msg));
1001 fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode);
1002 if (extras != null) {
1003 final String existing = extras.getString(
1004 PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE);
1005 if (!TextUtils.isEmpty(existing)) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001006 fillIn.putExtra(PackageInstaller.EXTRA_OTHER_PACKAGE_NAME, existing);
Jeff Sharkeya0907432014-08-15 10:23:11 -07001007 }
1008 }
1009 try {
1010 mTarget.sendIntent(mContext, 0, fillIn, null, null);
1011 } catch (SendIntentException ignored) {
1012 }
1013 }
1014 }
1015
Benjamin Franz39fb7fd2015-02-18 16:11:18 +00001016 /**
1017 * Build a notification for package installation / deletion by device owners that is shown if
1018 * the operation succeeds.
1019 */
1020 private static Notification buildSuccessNotification(Context context, String contentText,
1021 String basePackageName, int userId) {
1022 PackageInfo packageInfo = null;
1023 try {
1024 packageInfo = AppGlobals.getPackageManager().getPackageInfo(
Svet Ganova5c867c2017-05-15 01:17:05 -07001025 basePackageName, PackageManager.MATCH_STATIC_SHARED_LIBRARIES, userId);
Benjamin Franz39fb7fd2015-02-18 16:11:18 +00001026 } catch (RemoteException ignored) {
1027 }
1028 if (packageInfo == null || packageInfo.applicationInfo == null) {
1029 Slog.w(TAG, "Notification not built for package: " + basePackageName);
1030 return null;
1031 }
1032 PackageManager pm = context.getPackageManager();
1033 Bitmap packageIcon = ImageUtils.buildScaledBitmap(
1034 packageInfo.applicationInfo.loadIcon(pm),
1035 context.getResources().getDimensionPixelSize(
1036 android.R.dimen.notification_large_icon_width),
1037 context.getResources().getDimensionPixelSize(
1038 android.R.dimen.notification_large_icon_height));
1039 CharSequence packageLabel = packageInfo.applicationInfo.loadLabel(pm);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05001040 return new Notification.Builder(context, SystemNotificationChannels.DEVICE_ADMIN)
Benjamin Franz39fb7fd2015-02-18 16:11:18 +00001041 .setSmallIcon(R.drawable.ic_check_circle_24px)
1042 .setColor(context.getResources().getColor(
1043 R.color.system_notification_accent_color))
1044 .setContentTitle(packageLabel)
1045 .setContentText(contentText)
Benjamin Franz2e3e9432015-04-17 15:28:17 +01001046 .setStyle(new Notification.BigTextStyle().bigText(contentText))
Benjamin Franz39fb7fd2015-02-18 16:11:18 +00001047 .setLargeIcon(packageIcon)
1048 .build();
1049 }
1050
Jeff Sharkey54d42be2015-07-20 16:36:55 -07001051 public static <E> ArraySet<E> newArraySet(E... elements) {
1052 final ArraySet<E> set = new ArraySet<E>();
1053 if (elements != null) {
1054 set.ensureCapacity(elements.length);
1055 Collections.addAll(set, elements);
1056 }
1057 return set;
1058 }
1059
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001060 private static class Callbacks extends Handler {
1061 private static final int MSG_SESSION_CREATED = 1;
Jeff Sharkeyec9bad22014-09-05 09:45:20 -07001062 private static final int MSG_SESSION_BADGING_CHANGED = 2;
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001063 private static final int MSG_SESSION_ACTIVE_CHANGED = 3;
Jeff Sharkeyec9bad22014-09-05 09:45:20 -07001064 private static final int MSG_SESSION_PROGRESS_CHANGED = 4;
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001065 private static final int MSG_SESSION_FINISHED = 5;
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07001066
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001067 private final RemoteCallbackList<IPackageInstallerCallback>
1068 mCallbacks = new RemoteCallbackList<>();
Jeff Sharkeya1031142014-07-12 18:09:46 -07001069
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001070 public Callbacks(Looper looper) {
1071 super(looper);
1072 }
1073
Jon Miranda2b340a22019-01-25 14:03:49 -08001074 public void register(IPackageInstallerCallback callback, IntPredicate userCheck) {
1075 mCallbacks.register(callback, userCheck);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001076 }
1077
1078 public void unregister(IPackageInstallerCallback callback) {
1079 mCallbacks.unregister(callback);
1080 }
1081
1082 @Override
1083 public void handleMessage(Message msg) {
1084 final int userId = msg.arg2;
1085 final int n = mCallbacks.beginBroadcast();
1086 for (int i = 0; i < n; i++) {
1087 final IPackageInstallerCallback callback = mCallbacks.getBroadcastItem(i);
Jon Miranda2b340a22019-01-25 14:03:49 -08001088 final IntPredicate userCheck = (IntPredicate) mCallbacks.getBroadcastCookie(i);
1089 if (userCheck.test(userId)) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001090 try {
1091 invokeCallback(callback, msg);
1092 } catch (RemoteException ignored) {
1093 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07001094 }
1095 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001096 mCallbacks.finishBroadcast();
Jeff Sharkeya1031142014-07-12 18:09:46 -07001097 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001098
1099 private void invokeCallback(IPackageInstallerCallback callback, Message msg)
1100 throws RemoteException {
1101 final int sessionId = msg.arg1;
1102 switch (msg.what) {
1103 case MSG_SESSION_CREATED:
1104 callback.onSessionCreated(sessionId);
1105 break;
Jeff Sharkeyec9bad22014-09-05 09:45:20 -07001106 case MSG_SESSION_BADGING_CHANGED:
1107 callback.onSessionBadgingChanged(sessionId);
1108 break;
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001109 case MSG_SESSION_ACTIVE_CHANGED:
1110 callback.onSessionActiveChanged(sessionId, (boolean) msg.obj);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001111 break;
1112 case MSG_SESSION_PROGRESS_CHANGED:
1113 callback.onSessionProgressChanged(sessionId, (float) msg.obj);
1114 break;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001115 case MSG_SESSION_FINISHED:
1116 callback.onSessionFinished(sessionId, (boolean) msg.obj);
1117 break;
1118 }
1119 }
1120
1121 private void notifySessionCreated(int sessionId, int userId) {
1122 obtainMessage(MSG_SESSION_CREATED, sessionId, userId).sendToTarget();
1123 }
1124
Jeff Sharkeyec9bad22014-09-05 09:45:20 -07001125 private void notifySessionBadgingChanged(int sessionId, int userId) {
1126 obtainMessage(MSG_SESSION_BADGING_CHANGED, sessionId, userId).sendToTarget();
1127 }
1128
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001129 private void notifySessionActiveChanged(int sessionId, int userId, boolean active) {
1130 obtainMessage(MSG_SESSION_ACTIVE_CHANGED, sessionId, userId, active).sendToTarget();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001131 }
1132
1133 private void notifySessionProgressChanged(int sessionId, int userId, float progress) {
1134 obtainMessage(MSG_SESSION_PROGRESS_CHANGED, sessionId, userId, progress).sendToTarget();
1135 }
1136
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001137 public void notifySessionFinished(int sessionId, int userId, boolean success) {
1138 obtainMessage(MSG_SESSION_FINISHED, sessionId, userId, success).sendToTarget();
1139 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07001140 }
1141
1142 void dump(IndentingPrintWriter pw) {
Jeff Sharkeya1031142014-07-12 18:09:46 -07001143 synchronized (mSessions) {
Jeff Sharkey9a445772014-07-16 11:32:08 -07001144 pw.println("Active install sessions:");
1145 pw.increaseIndent();
1146 int N = mSessions.size();
Jeff Sharkeya1031142014-07-12 18:09:46 -07001147 for (int i = 0; i < N; i++) {
1148 final PackageInstallerSession session = mSessions.valueAt(i);
1149 session.dump(pw);
1150 pw.println();
1151 }
Jeff Sharkey9a445772014-07-16 11:32:08 -07001152 pw.println();
1153 pw.decreaseIndent();
1154
1155 pw.println("Historical install sessions:");
1156 pw.increaseIndent();
1157 N = mHistoricalSessions.size();
1158 for (int i = 0; i < N; i++) {
Narayan Kamatha22a7662017-06-12 13:34:29 +01001159 pw.print(mHistoricalSessions.get(i));
Jeff Sharkey9a445772014-07-16 11:32:08 -07001160 pw.println();
1161 }
1162 pw.println();
1163 pw.decreaseIndent();
Jeff Sharkey742e7902014-08-16 19:09:13 -07001164
1165 pw.println("Legacy install sessions:");
1166 pw.increaseIndent();
1167 pw.println(mLegacySessions.toString());
1168 pw.decreaseIndent();
Jeff Sharkeya1031142014-07-12 18:09:46 -07001169 }
Jeff Sharkeybb580672014-07-10 12:10:25 -07001170 }
1171
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001172 class InternalCallback {
Jeff Sharkeyec9bad22014-09-05 09:45:20 -07001173 public void onSessionBadgingChanged(PackageInstallerSession session) {
1174 mCallbacks.notifySessionBadgingChanged(session.sessionId, session.userId);
1175 writeSessionsAsync();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001176 }
1177
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001178 public void onSessionActiveChanged(PackageInstallerSession session, boolean active) {
1179 mCallbacks.notifySessionActiveChanged(session.sessionId, session.userId, active);
Jeff Sharkey742e7902014-08-16 19:09:13 -07001180 }
1181
Jeff Sharkeyec9bad22014-09-05 09:45:20 -07001182 public void onSessionProgressChanged(PackageInstallerSession session, float progress) {
1183 mCallbacks.notifySessionProgressChanged(session.sessionId, session.userId, progress);
1184 }
1185
Dario Freni0180d0b2019-01-11 21:08:13 +00001186 public void onStagedSessionChanged(PackageInstallerSession session) {
1187 writeSessionsAsync();
Dario Freni14f885b2019-02-25 12:48:47 +00001188 if (mOkToSendBroadcasts) {
Dario Freni9694b802019-01-27 23:26:06 +00001189 mPm.sendSessionUpdatedBroadcast(session.generateInfo(false),
1190 session.userId);
1191 }
Dario Freni0180d0b2019-01-11 21:08:13 +00001192 }
1193
Jeff Sharkeycbf47912014-09-12 09:55:32 -07001194 public void onSessionFinished(final PackageInstallerSession session, boolean success) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001195 mCallbacks.notifySessionFinished(session.sessionId, session.userId, success);
Jeff Sharkeycbf47912014-09-12 09:55:32 -07001196
1197 mInstallHandler.post(new Runnable() {
1198 @Override
1199 public void run() {
Dario Freniaac4ba42018-12-06 15:47:16 +00001200 if (session.isStaged()) {
Dario Freniaac4ba42018-12-06 15:47:16 +00001201 if (!success) {
Dario Frenibe98c3f2018-12-22 15:25:27 +00001202 mStagingManager.abortSession(session);
Dario Freniaac4ba42018-12-06 15:47:16 +00001203 }
1204 }
Jeff Sharkeycbf47912014-09-12 09:55:32 -07001205 synchronized (mSessions) {
Dario Freni8e7d0ec2019-01-10 15:21:40 +00001206 if (!session.isStaged() || !success) {
1207 mSessions.remove(session.sessionId);
1208 }
Narayan Kamatha22a7662017-06-12 13:34:29 +01001209 addHistoricalSessionLocked(session);
Jeff Sharkey02bd7842014-10-06 15:14:27 -07001210
1211 final File appIconFile = buildAppIconFile(session.sessionId);
1212 if (appIconFile.exists()) {
1213 appIconFile.delete();
1214 }
1215
Jeff Sharkeycbf47912014-09-12 09:55:32 -07001216 writeSessionsLocked();
1217 }
1218 }
1219 });
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001220 }
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -07001221
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001222 public void onSessionPrepared(PackageInstallerSession session) {
1223 // We prepared the destination to write into; we want to persist
1224 // this, but it's not critical enough to block for.
1225 writeSessionsAsync();
1226 }
1227
Jeff Sharkeycbf47912014-09-12 09:55:32 -07001228 public void onSessionSealedBlocking(PackageInstallerSession session) {
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -07001229 // It's very important that we block until we've recorded the
1230 // session as being sealed, since we never want to allow mutation
1231 // after sealing.
Jeff Sharkeycbf47912014-09-12 09:55:32 -07001232 synchronized (mSessions) {
1233 writeSessionsLocked();
1234 }
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -07001235 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001236 }
1237}