blob: 0b32d1a5d69bd84dce76f3db3ac46d2f940725fd [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.DeviceAdminInfo;
31import android.app.admin.DevicePolicyManagerInternal;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070032import android.content.Context;
Jeff Sharkeyf0600952014-08-07 17:31:53 -070033import android.content.Intent;
Jeff Sharkeya0907432014-08-15 10:23:11 -070034import android.content.IntentSender;
35import android.content.IntentSender.SendIntentException;
Philip P. Moltmannd9bb39a2017-09-05 12:41:15 -070036import android.content.pm.ApplicationInfo;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070037import android.content.pm.IPackageInstaller;
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -070038import android.content.pm.IPackageInstallerCallback;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070039import android.content.pm.IPackageInstallerSession;
Benjamin Franz39fb7fd2015-02-18 16:11:18 +000040import android.content.pm.PackageInfo;
Jeff Sharkeyf0600952014-08-07 17:31:53 -070041import android.content.pm.PackageInstaller;
Jeff Sharkeya0907432014-08-15 10:23:11 -070042import android.content.pm.PackageInstaller.SessionInfo;
43import android.content.pm.PackageInstaller.SessionParams;
Jeff Sharkeyec9bad22014-09-05 09:45:20 -070044import android.content.pm.PackageManager;
Jeff Sharkey97d47ed2014-10-15 09:19:47 -070045import android.content.pm.ParceledListSlice;
Svet Ganov67882122016-12-11 16:36:34 -080046import android.content.pm.VersionedPackage;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070047import android.graphics.Bitmap;
Jeff Sharkeyf0600952014-08-07 17:31:53 -070048import android.net.Uri;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070049import android.os.Binder;
Philip P. Moltmannd9bb39a2017-09-05 12:41:15 -070050import android.os.Build;
Jeff Sharkeya0907432014-08-15 10:23:11 -070051import android.os.Bundle;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070052import android.os.Environment;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070053import android.os.Handler;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070054import android.os.HandlerThread;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070055import android.os.Looper;
56import android.os.Message;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070057import android.os.Process;
Jeff Sharkeya1031142014-07-12 18:09:46 -070058import android.os.RemoteCallbackList;
59import android.os.RemoteException;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -070060import android.os.SELinux;
Dianne Hackborne17b4452018-01-10 13:15:40 -080061import android.os.SystemClock;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070062import android.os.UserHandle;
63import android.os.UserManager;
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -070064import android.os.storage.StorageManager;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -070065import android.system.ErrnoException;
66import android.system.Os;
Jeff Sharkeya0907432014-08-15 10:23:11 -070067import android.text.TextUtils;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070068import android.text.format.DateUtils;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070069import android.util.ArraySet;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070070import android.util.AtomicFile;
Jeff Sharkeya1031142014-07-12 18:09:46 -070071import android.util.ExceptionUtils;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070072import android.util.Slog;
73import android.util.SparseArray;
Jeff Sharkey742e7902014-08-16 19:09:13 -070074import android.util.SparseBooleanArray;
Narayan Kamatha22a7662017-06-12 13:34:29 +010075import android.util.SparseIntArray;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070076import android.util.Xml;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070077
Benjamin Franz39fb7fd2015-02-18 16:11:18 +000078import com.android.internal.R;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070079import com.android.internal.annotations.GuardedBy;
Jeff Sharkey742e7902014-08-16 19:09:13 -070080import com.android.internal.content.PackageHelper;
Chris Wren282cfef2017-03-27 15:01:44 -040081import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
Geoffrey Pitschaf759c52017-02-15 09:35:38 -050082import com.android.internal.notification.SystemNotificationChannels;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070083import com.android.internal.util.FastXmlSerializer;
Benjamin Franz39fb7fd2015-02-18 16:11:18 +000084import com.android.internal.util.ImageUtils;
Jeff Sharkeya1031142014-07-12 18:09:46 -070085import com.android.internal.util.IndentingPrintWriter;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070086import com.android.server.IoThread;
Todd Kennedy0eb97382017-10-03 16:57:22 -070087import com.android.server.LocalServices;
88import com.android.server.pm.permission.PermissionManagerInternal;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070089
Philip P. Moltmann7460c592017-08-08 20:07:11 +000090import libcore.io.IoUtils;
91
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070092import org.xmlpull.v1.XmlPullParser;
93import org.xmlpull.v1.XmlPullParserException;
94import org.xmlpull.v1.XmlSerializer;
95
Philip P. Moltmann7460c592017-08-08 20:07:11 +000096import java.io.CharArrayWriter;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070097import java.io.File;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070098import java.io.FileInputStream;
99import java.io.FileNotFoundException;
100import java.io.FileOutputStream;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700101import java.io.FilenameFilter;
102import java.io.IOException;
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +0100103import java.nio.charset.StandardCharsets;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700104import java.security.SecureRandom;
Jeff Sharkeybb580672014-07-10 12:10:25 -0700105import java.util.ArrayList;
Jeff Sharkey54d42be2015-07-20 16:36:55 -0700106import java.util.Collections;
Jeff Sharkeybb580672014-07-10 12:10:25 -0700107import java.util.List;
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700108import java.util.Objects;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700109import java.util.Random;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700110
111public class PackageInstallerService extends IPackageInstaller.Stub {
112 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;
Todd Kennedy0eb97382017-10-03 16:57:22 -0700131 private final PermissionManagerInternal mPermissionManager;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700132
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700133 private AppOpsManager mAppOps;
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700134
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700135 private final HandlerThread mInstallThread;
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700136 private final Handler mInstallHandler;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700137
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700138 private final Callbacks mCallbacks;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700139
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700140 /**
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700141 * File storing persisted {@link #mSessions} metadata.
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700142 */
143 private final AtomicFile mSessionsFile;
144
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700145 /**
146 * Directory storing persisted {@link #mSessions} metadata which is too
147 * heavy to store directly in {@link #mSessionsFile}.
148 */
149 private final File mSessionsDir;
150
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700151 private final InternalCallback mInternalCallback = new InternalCallback();
152
153 /**
154 * Used for generating session IDs. Since this is created at boot time,
155 * normal random might be predictable.
156 */
157 private final Random mRandom = new SecureRandom();
158
Todd Kennedy28c4e802016-07-13 13:20:30 -0700159 /** All sessions allocated */
160 @GuardedBy("mSessions")
161 private final SparseBooleanArray mAllocatedSessions = new SparseBooleanArray();
162
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700163 @GuardedBy("mSessions")
164 private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>();
165
Jeff Sharkey9a445772014-07-16 11:32:08 -0700166 /** Historical sessions kept around for debugging purposes */
167 @GuardedBy("mSessions")
Narayan Kamatha22a7662017-06-12 13:34:29 +0100168 private final List<String> mHistoricalSessions = new ArrayList<>();
169
170 @GuardedBy("mSessions")
171 private final SparseIntArray mHistoricalSessionsByInstaller = new SparseIntArray();
Jeff Sharkey9a445772014-07-16 11:32:08 -0700172
Jeff Sharkey742e7902014-08-16 19:09:13 -0700173 /** Sessions allocated to legacy users */
174 @GuardedBy("mSessions")
175 private final SparseBooleanArray mLegacySessions = new SparseBooleanArray();
176
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700177 private static final FilenameFilter sStageFilter = new FilenameFilter() {
178 @Override
179 public boolean accept(File dir, String name) {
Jeff Sharkey742e7902014-08-16 19:09:13 -0700180 return isStageName(name);
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700181 }
182 };
183
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700184 public PackageInstallerService(Context context, PackageManagerService pm) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700185 mContext = context;
186 mPm = pm;
Todd Kennedy0eb97382017-10-03 16:57:22 -0700187 mPermissionManager = LocalServices.getService(PermissionManagerInternal.class);
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700188
189 mInstallThread = new HandlerThread(TAG);
190 mInstallThread.start();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700191
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700192 mInstallHandler = new Handler(mInstallThread.getLooper());
193
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700194 mCallbacks = new Callbacks(mInstallThread.getLooper());
195
196 mSessionsFile = new AtomicFile(
Dianne Hackborne17b4452018-01-10 13:15:40 -0800197 new File(Environment.getDataSystemDirectory(), "install_sessions.xml"),
198 "package-session");
Jeff Sharkey8212ae02016-02-10 14:46:43 -0700199 mSessionsDir = new File(Environment.getDataSystemDirectory(), "install_sessions");
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700200 mSessionsDir.mkdirs();
Tony Mak606f8e72017-02-15 18:40:03 +0000201 }
202
203 public void systemReady() {
204 mAppOps = mContext.getSystemService(AppOpsManager.class);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700205
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700206 synchronized (mSessions) {
207 readSessionsLocked();
208
Svetoslav Ganov096d3042017-01-30 16:34:13 -0800209 reconcileStagesLocked(StorageManager.UUID_PRIVATE_INTERNAL, false /*isInstant*/);
210 reconcileStagesLocked(StorageManager.UUID_PRIVATE_INTERNAL, true /*isInstant*/);
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700211
Jeff Sharkey54d42be2015-07-20 16:36:55 -0700212 final ArraySet<File> unclaimedIcons = newArraySet(
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700213 mSessionsDir.listFiles());
Jeff Sharkey742e7902014-08-16 19:09:13 -0700214
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700215 // Ignore stages and icons claimed by active sessions
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700216 for (int i = 0; i < mSessions.size(); i++) {
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700217 final PackageInstallerSession session = mSessions.valueAt(i);
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700218 unclaimedIcons.remove(buildAppIconFile(session.sessionId));
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700219 }
Jeff Sharkey742e7902014-08-16 19:09:13 -0700220
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700221 // Clean up orphaned icons
222 for (File icon : unclaimedIcons) {
223 Slog.w(TAG, "Deleting orphan icon " + icon);
224 icon.delete();
225 }
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700226 }
227 }
228
Andreas Gampea36dc622018-02-05 17:19:22 -0800229 @GuardedBy("mSessions")
Todd Kennedy2699f062015-11-20 13:07:17 -0800230 private void reconcileStagesLocked(String volumeUuid, boolean isEphemeral) {
231 final File stagingDir = buildStagingDir(volumeUuid, isEphemeral);
Jeff Sharkey54d42be2015-07-20 16:36:55 -0700232 final ArraySet<File> unclaimedStages = newArraySet(
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700233 stagingDir.listFiles(sStageFilter));
234
235 // Ignore stages claimed by active sessions
236 for (int i = 0; i < mSessions.size(); i++) {
237 final PackageInstallerSession session = mSessions.valueAt(i);
238 unclaimedStages.remove(session.stageDir);
239 }
240
241 // Clean up orphaned staging directories
242 for (File stage : unclaimedStages) {
243 Slog.w(TAG, "Deleting orphan stage " + stage);
244 synchronized (mPm.mInstallLock) {
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -0700245 mPm.removeCodePathLI(stage);
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700246 }
247 }
248 }
249
250 public void onPrivateVolumeMounted(String volumeUuid) {
251 synchronized (mSessions) {
Svetoslav Ganov096d3042017-01-30 16:34:13 -0800252 reconcileStagesLocked(volumeUuid, false /*isInstant*/);
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700253 }
254 }
255
Jeff Sharkey742e7902014-08-16 19:09:13 -0700256 public static boolean isStageName(String name) {
257 final boolean isFile = name.startsWith("vmdl") && name.endsWith(".tmp");
258 final boolean isContainer = name.startsWith("smdl") && name.endsWith(".tmp");
259 final boolean isLegacyContainer = name.startsWith("smdl2tmp");
260 return isFile || isContainer || isLegacyContainer;
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700261 }
262
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700263 @Deprecated
Todd Kennedy2699f062015-11-20 13:07:17 -0800264 public File allocateStageDirLegacy(String volumeUuid, boolean isEphemeral) throws IOException {
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700265 synchronized (mSessions) {
266 try {
267 final int sessionId = allocateSessionIdLocked();
Jeff Sharkey742e7902014-08-16 19:09:13 -0700268 mLegacySessions.put(sessionId, true);
Todd Kennedy2699f062015-11-20 13:07:17 -0800269 final File stageDir = buildStageDir(volumeUuid, sessionId, isEphemeral);
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700270 prepareStageDir(stageDir);
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700271 return stageDir;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700272 } catch (IllegalStateException e) {
273 throw new IOException(e);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700274 }
275 }
276 }
277
Jeff Sharkey742e7902014-08-16 19:09:13 -0700278 @Deprecated
279 public String allocateExternalStageCidLegacy() {
280 synchronized (mSessions) {
281 final int sessionId = allocateSessionIdLocked();
282 mLegacySessions.put(sessionId, true);
283 return "smdl" + sessionId + ".tmp";
284 }
285 }
286
Andreas Gampea36dc622018-02-05 17:19:22 -0800287 @GuardedBy("mSessions")
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700288 private void readSessionsLocked() {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700289 if (LOGD) Slog.v(TAG, "readSessionsLocked()");
290
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700291 mSessions.clear();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700292
293 FileInputStream fis = null;
294 try {
295 fis = mSessionsFile.openRead();
296 final XmlPullParser in = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +0100297 in.setInput(fis, StandardCharsets.UTF_8.name());
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700298
299 int type;
300 while ((type = in.next()) != END_DOCUMENT) {
301 if (type == START_TAG) {
302 final String tag = in.getName();
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000303 if (PackageInstallerSession.TAG_SESSION.equals(tag)) {
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -0700304 final PackageInstallerSession session;
305 try {
306 session = PackageInstallerSession.readFromXml(in, mInternalCallback,
307 mContext, mPm, mInstallThread.getLooper(), mSessionsDir);
308 } catch (Exception e) {
309 Slog.e(TAG, "Could not read session", e);
310 continue;
311 }
312
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700313 final long age = System.currentTimeMillis() - session.createdMillis;
314
315 final boolean valid;
316 if (age >= MAX_AGE_MILLIS) {
317 Slog.w(TAG, "Abandoning old session first created at "
318 + session.createdMillis);
319 valid = false;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700320 } else {
321 valid = true;
322 }
323
324 if (valid) {
325 mSessions.put(session.sessionId, session);
326 } else {
327 // Since this is early during boot we don't send
328 // any observer events about the session, but we
329 // keep details around for dumpsys.
Narayan Kamatha22a7662017-06-12 13:34:29 +0100330 addHistoricalSessionLocked(session);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700331 }
Todd Kennedy28c4e802016-07-13 13:20:30 -0700332 mAllocatedSessions.put(session.sessionId, true);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700333 }
334 }
335 }
336 } catch (FileNotFoundException e) {
337 // Missing sessions are okay, probably first boot
Svet Ganov7121e182015-07-13 22:38:12 -0700338 } catch (IOException | XmlPullParserException e) {
Dianne Hackborn8d051722014-10-01 14:59:58 -0700339 Slog.wtf(TAG, "Failed reading install sessions", e);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700340 } finally {
341 IoUtils.closeQuietly(fis);
342 }
343 }
344
Andreas Gampea36dc622018-02-05 17:19:22 -0800345 @GuardedBy("mSessions")
Narayan Kamatha22a7662017-06-12 13:34:29 +0100346 private void addHistoricalSessionLocked(PackageInstallerSession session) {
347 CharArrayWriter writer = new CharArrayWriter();
348 IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
349 session.dump(pw);
350 mHistoricalSessions.add(writer.toString());
351
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000352 int installerUid = session.getInstallerUid();
Narayan Kamatha22a7662017-06-12 13:34:29 +0100353 // Increment the number of sessions by this installerUid.
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000354 mHistoricalSessionsByInstaller.put(installerUid,
355 mHistoricalSessionsByInstaller.get(installerUid) + 1);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700356 }
357
Andreas Gampea36dc622018-02-05 17:19:22 -0800358 @GuardedBy("mSessions")
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700359 private void writeSessionsLocked() {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700360 if (LOGD) Slog.v(TAG, "writeSessionsLocked()");
361
362 FileOutputStream fos = null;
363 try {
364 fos = mSessionsFile.startWrite();
365
366 XmlSerializer out = new FastXmlSerializer();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +0100367 out.setOutput(fos, StandardCharsets.UTF_8.name());
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700368 out.startDocument(null, true);
369 out.startTag(null, TAG_SESSIONS);
370 final int size = mSessions.size();
371 for (int i = 0; i < size; i++) {
372 final PackageInstallerSession session = mSessions.valueAt(i);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000373 session.write(out, mSessionsDir);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700374 }
375 out.endTag(null, TAG_SESSIONS);
376 out.endDocument();
377
378 mSessionsFile.finishWrite(fos);
379 } catch (IOException e) {
380 if (fos != null) {
381 mSessionsFile.failWrite(fos);
382 }
383 }
384 }
385
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700386 private File buildAppIconFile(int sessionId) {
387 return new File(mSessionsDir, "app_icon." + sessionId + ".png");
388 }
389
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700390 private void writeSessionsAsync() {
391 IoThread.getHandler().post(new Runnable() {
392 @Override
393 public void run() {
394 synchronized (mSessions) {
395 writeSessionsLocked();
396 }
397 }
398 });
399 }
400
401 @Override
Jeff Sharkeya0907432014-08-15 10:23:11 -0700402 public int createSession(SessionParams params, String installerPackageName, int userId) {
Jeff Sharkey742e7902014-08-16 19:09:13 -0700403 try {
404 return createSessionInternal(params, installerPackageName, userId);
405 } catch (IOException e) {
406 throw ExceptionUtils.wrap(e);
407 }
408 }
409
410 private int createSessionInternal(SessionParams params, String installerPackageName, int userId)
411 throws IOException {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700412 final int callingUid = Binder.getCallingUid();
Todd Kennedy0eb97382017-10-03 16:57:22 -0700413 mPermissionManager.enforceCrossUserPermission(
414 callingUid, userId, true, true, "createSession");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700415
Jeff Sharkeye9808042014-09-11 21:15:37 -0700416 if (mPm.isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700417 throw new SecurityException("User restriction prevents installing");
418 }
419
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700420 if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {
Jeff Sharkeye9808042014-09-11 21:15:37 -0700421 params.installFlags |= PackageManager.INSTALL_FROM_ADB;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700422
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700423 } else {
Philip P. Moltmann79c238a2017-12-13 15:59:07 -0800424 // Only apps with INSTALL_PACKAGES are allowed to set an installer that is not the
425 // caller.
426 if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES) !=
427 PackageManager.PERMISSION_GRANTED) {
428 mAppOps.checkPackage(callingUid, installerPackageName);
429 }
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700430
Jeff Sharkeye9808042014-09-11 21:15:37 -0700431 params.installFlags &= ~PackageManager.INSTALL_FROM_ADB;
432 params.installFlags &= ~PackageManager.INSTALL_ALL_USERS;
433 params.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
Todd Kennedy78a72502017-07-19 12:49:30 -0700434 if ((params.installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0
435 && !mPm.isCallerVerifier(callingUid)) {
436 params.installFlags &= ~PackageManager.INSTALL_VIRTUAL_PRELOAD;
437 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700438 }
439
Svetoslav805b63e2015-04-09 17:28:54 -0700440 // Only system components can circumvent runtime permissions when installing.
441 if ((params.installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0
442 && mContext.checkCallingOrSelfPermission(Manifest.permission
443 .INSTALL_GRANT_RUNTIME_PERMISSIONS) == PackageManager.PERMISSION_DENIED) {
444 throw new SecurityException("You need the "
445 + "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS permission "
446 + "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag");
447 }
448
Jeff Sharkey8c61e392017-02-24 09:22:48 -0700449 if ((params.installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0
450 || (params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
451 throw new IllegalArgumentException(
452 "New installs into ASEC containers no longer supported");
453 }
454
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700455 // Defensively resize giant app icons
456 if (params.appIcon != null) {
457 final ActivityManager am = (ActivityManager) mContext.getSystemService(
458 Context.ACTIVITY_SERVICE);
459 final int iconSize = am.getLauncherLargeIconSize();
460 if ((params.appIcon.getWidth() > iconSize * 2)
461 || (params.appIcon.getHeight() > iconSize * 2)) {
462 params.appIcon = Bitmap.createScaledBitmap(params.appIcon, iconSize, iconSize,
463 true);
464 }
465 }
466
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700467 switch (params.mode) {
468 case SessionParams.MODE_FULL_INSTALL:
469 case SessionParams.MODE_INHERIT_EXISTING:
470 break;
471 default:
472 throw new IllegalArgumentException("Invalid install mode: " + params.mode);
473 }
474
475 // If caller requested explicit location, sanity check it, otherwise
476 // resolve the best internal or adopted location.
477 if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
Jeff Sharkey683bcd32017-03-18 17:54:51 -0600478 if (!PackageHelper.fitsOnInternal(mContext, params)) {
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700479 throw new IOException("No suitable internal storage available");
480 }
481
482 } else if ((params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
Jeff Sharkey683bcd32017-03-18 17:54:51 -0600483 if (!PackageHelper.fitsOnExternal(mContext, params)) {
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700484 throw new IOException("No suitable external storage available");
485 }
486
Jeff Sharkeyab234092015-06-09 21:42:22 -0700487 } else if ((params.installFlags & PackageManager.INSTALL_FORCE_VOLUME_UUID) != 0) {
488 // For now, installs to adopted media are treated as internal from
489 // an install flag point-of-view.
490 params.setInstallFlagsInternal();
491
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700492 } else {
493 // For now, installs to adopted media are treated as internal from
494 // an install flag point-of-view.
495 params.setInstallFlagsInternal();
496
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700497 // Resolve best location for install, based on combination of
498 // requested install flags, delta size, and manifest settings.
Robin Leee812d902014-08-21 16:51:18 +0100499 final long ident = Binder.clearCallingIdentity();
500 try {
Jeff Sharkey683bcd32017-03-18 17:54:51 -0600501 params.volumeUuid = PackageHelper.resolveInstallVolume(mContext, params);
Robin Leee812d902014-08-21 16:51:18 +0100502 } finally {
503 Binder.restoreCallingIdentity(ident);
504 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700505 }
506
507 final int sessionId;
508 final PackageInstallerSession session;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700509 synchronized (mSessions) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700510 // Sanity check that installer isn't going crazy
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700511 final int activeCount = getSessionCount(mSessions, callingUid);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700512 if (activeCount >= MAX_ACTIVE_SESSIONS) {
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700513 throw new IllegalStateException(
514 "Too many active sessions for UID " + callingUid);
515 }
Narayan Kamatha22a7662017-06-12 13:34:29 +0100516 final int historicalCount = mHistoricalSessionsByInstaller.get(callingUid);
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700517 if (historicalCount >= MAX_HISTORICAL_SESSIONS) {
518 throw new IllegalStateException(
519 "Too many historical sessions for UID " + callingUid);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700520 }
521
Jeff Sharkeya1031142014-07-12 18:09:46 -0700522 sessionId = allocateSessionIdLocked();
Todd Kennedy04918fe2016-07-12 14:07:40 -0700523 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700524
Todd Kennedy04918fe2016-07-12 14:07:40 -0700525 final long createdMillis = System.currentTimeMillis();
526 // We're staging to exactly one location
527 File stageDir = null;
528 String stageCid = null;
529 if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
Todd Kennedybe0b8892017-02-15 14:13:52 -0800530 final boolean isInstant =
531 (params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
532 stageDir = buildStageDir(params.volumeUuid, sessionId, isInstant);
Todd Kennedy04918fe2016-07-12 14:07:40 -0700533 } else {
534 stageCid = buildExternalStageCid(sessionId);
535 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700536
Todd Kennedy04918fe2016-07-12 14:07:40 -0700537 session = new PackageInstallerSession(mInternalCallback, mContext, mPm,
538 mInstallThread.getLooper(), sessionId, userId, installerPackageName, callingUid,
539 params, createdMillis, stageDir, stageCid, false, false);
540
541 synchronized (mSessions) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700542 mSessions.put(sessionId, session);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700543 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700544
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700545 mCallbacks.notifySessionCreated(session.sessionId, session.userId);
Jeff Sharkeya1031142014-07-12 18:09:46 -0700546 writeSessionsAsync();
547 return sessionId;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700548 }
549
Jeff Sharkey381d94b2014-08-24 14:45:56 -0700550 @Override
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700551 public void updateSessionAppIcon(int sessionId, Bitmap appIcon) {
552 synchronized (mSessions) {
553 final PackageInstallerSession session = mSessions.get(sessionId);
554 if (session == null || !isCallingUidOwner(session)) {
555 throw new SecurityException("Caller has no access to session " + sessionId);
556 }
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700557
558 // Defensively resize giant app icons
559 if (appIcon != null) {
560 final ActivityManager am = (ActivityManager) mContext.getSystemService(
561 Context.ACTIVITY_SERVICE);
562 final int iconSize = am.getLauncherLargeIconSize();
563 if ((appIcon.getWidth() > iconSize * 2)
564 || (appIcon.getHeight() > iconSize * 2)) {
565 appIcon = Bitmap.createScaledBitmap(appIcon, iconSize, iconSize, true);
566 }
567 }
568
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700569 session.params.appIcon = appIcon;
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700570 session.params.appIconLastModified = -1;
571
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700572 mInternalCallback.onSessionBadgingChanged(session);
573 }
574 }
575
576 @Override
577 public void updateSessionAppLabel(int sessionId, String appLabel) {
578 synchronized (mSessions) {
579 final PackageInstallerSession session = mSessions.get(sessionId);
580 if (session == null || !isCallingUidOwner(session)) {
581 throw new SecurityException("Caller has no access to session " + sessionId);
582 }
583 session.params.appLabel = appLabel;
584 mInternalCallback.onSessionBadgingChanged(session);
585 }
586 }
587
588 @Override
Jeff Sharkey381d94b2014-08-24 14:45:56 -0700589 public void abandonSession(int sessionId) {
590 synchronized (mSessions) {
591 final PackageInstallerSession session = mSessions.get(sessionId);
592 if (session == null || !isCallingUidOwner(session)) {
593 throw new SecurityException("Caller has no access to session " + sessionId);
594 }
595 session.abandon();
596 }
597 }
598
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700599 @Override
600 public IPackageInstallerSession openSession(int sessionId) {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700601 try {
602 return openSessionInternal(sessionId);
603 } catch (IOException e) {
604 throw ExceptionUtils.wrap(e);
605 }
606 }
607
608 private IPackageInstallerSession openSessionInternal(int sessionId) throws IOException {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700609 synchronized (mSessions) {
610 final PackageInstallerSession session = mSessions.get(sessionId);
Jeff Sharkey381d94b2014-08-24 14:45:56 -0700611 if (session == null || !isCallingUidOwner(session)) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700612 throw new SecurityException("Caller has no access to session " + sessionId);
613 }
Jeff Sharkey742e7902014-08-16 19:09:13 -0700614 session.open();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700615 return session;
616 }
617 }
618
Andreas Gampea36dc622018-02-05 17:19:22 -0800619 @GuardedBy("mSessions")
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700620 private int allocateSessionIdLocked() {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700621 int n = 0;
622 int sessionId;
623 do {
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700624 sessionId = mRandom.nextInt(Integer.MAX_VALUE - 1) + 1;
Todd Kennedy28c4e802016-07-13 13:20:30 -0700625 if (!mAllocatedSessions.get(sessionId, false)) {
626 mAllocatedSessions.put(sessionId, true);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700627 return sessionId;
628 }
629 } while (n++ < 32);
630
631 throw new IllegalStateException("Failed to allocate session ID");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700632 }
633
Todd Kennedy2699f062015-11-20 13:07:17 -0800634 private File buildStagingDir(String volumeUuid, boolean isEphemeral) {
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700635 return Environment.getDataAppDirectory(volumeUuid);
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700636 }
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700637
Todd Kennedy2699f062015-11-20 13:07:17 -0800638 private File buildStageDir(String volumeUuid, int sessionId, boolean isEphemeral) {
639 final File stagingDir = buildStagingDir(volumeUuid, isEphemeral);
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700640 return new File(stagingDir, "vmdl" + sessionId + ".tmp");
641 }
642
643 static void prepareStageDir(File stageDir) throws IOException {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700644 if (stageDir.exists()) {
645 throw new IOException("Session dir already exists: " + stageDir);
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700646 }
647
648 try {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700649 Os.mkdir(stageDir.getAbsolutePath(), 0755);
650 Os.chmod(stageDir.getAbsolutePath(), 0755);
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700651 } catch (ErrnoException e) {
652 // This purposefully throws if directory already exists
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700653 throw new IOException("Failed to prepare session dir: " + stageDir, e);
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700654 }
655
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700656 if (!SELinux.restorecon(stageDir)) {
657 throw new IOException("Failed to restorecon session dir: " + stageDir);
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700658 }
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700659 }
660
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700661 private String buildExternalStageCid(int sessionId) {
662 return "smdl" + sessionId + ".tmp";
663 }
Jeff Sharkey742e7902014-08-16 19:09:13 -0700664
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700665 @Override
Jeff Sharkeya0907432014-08-15 10:23:11 -0700666 public SessionInfo getSessionInfo(int sessionId) {
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700667 synchronized (mSessions) {
668 final PackageInstallerSession session = mSessions.get(sessionId);
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700669 return session != null ? session.generateInfo() : null;
670 }
671 }
672
673 @Override
Jeff Sharkey97d47ed2014-10-15 09:19:47 -0700674 public ParceledListSlice<SessionInfo> getAllSessions(int userId) {
Todd Kennedy0eb97382017-10-03 16:57:22 -0700675 mPermissionManager.enforceCrossUserPermission(
676 Binder.getCallingUid(), userId, true, false, "getAllSessions");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700677
Jeff Sharkeya0907432014-08-15 10:23:11 -0700678 final List<SessionInfo> result = new ArrayList<>();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700679 synchronized (mSessions) {
680 for (int i = 0; i < mSessions.size(); i++) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700681 final PackageInstallerSession session = mSessions.valueAt(i);
Jeff Sharkeybb580672014-07-10 12:10:25 -0700682 if (session.userId == userId) {
Jeff Sharkeyda1247a2017-06-08 14:13:29 -0600683 result.add(session.generateInfo(false));
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700684 }
685 }
686 }
Jeff Sharkey97d47ed2014-10-15 09:19:47 -0700687 return new ParceledListSlice<>(result);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700688 }
689
690 @Override
Jeff Sharkey97d47ed2014-10-15 09:19:47 -0700691 public ParceledListSlice<SessionInfo> getMySessions(String installerPackageName, int userId) {
Todd Kennedy0eb97382017-10-03 16:57:22 -0700692 mPermissionManager.enforceCrossUserPermission(
693 Binder.getCallingUid(), userId, true, false, "getMySessions");
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700694 mAppOps.checkPackage(Binder.getCallingUid(), installerPackageName);
695
Jeff Sharkeya0907432014-08-15 10:23:11 -0700696 final List<SessionInfo> result = new ArrayList<>();
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700697 synchronized (mSessions) {
698 for (int i = 0; i < mSessions.size(); i++) {
699 final PackageInstallerSession session = mSessions.valueAt(i);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000700
701 SessionInfo info = session.generateInfo(false);
702 if (Objects.equals(info.getInstallerPackageName(), installerPackageName)
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700703 && session.userId == userId) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000704 result.add(info);
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700705 }
706 }
707 }
Jeff Sharkey97d47ed2014-10-15 09:19:47 -0700708 return new ParceledListSlice<>(result);
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700709 }
710
711 @Override
Svet Ganov67882122016-12-11 16:36:34 -0800712 public void uninstall(VersionedPackage versionedPackage, String callerPackageName, int flags,
713 IntentSender statusReceiver, int userId) throws RemoteException {
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000714 final int callingUid = Binder.getCallingUid();
Todd Kennedy0eb97382017-10-03 16:57:22 -0700715 mPermissionManager.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000716 if ((callingUid != Process.SHELL_UID) && (callingUid != Process.ROOT_UID)) {
717 mAppOps.checkPackage(callingUid, callerPackageName);
718 }
719
Benjamin Franzdabae882017-08-08 12:33:19 +0100720 // Check whether the caller is device owner or affiliated profile owner, in which case we do
721 // it silently.
722 final int callingUserId = UserHandle.getUserId(callingUid);
723 DevicePolicyManagerInternal dpmi =
724 LocalServices.getService(DevicePolicyManagerInternal.class);
725 final boolean isDeviceOwnerOrAffiliatedProfileOwner =
726 dpmi != null && dpmi.isActiveAdminWithPolicy(callingUid,
727 DeviceAdminInfo.USES_POLICY_PROFILE_OWNER)
728 && dpmi.isUserAffiliatedWithDevice(callingUserId);
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700729
Jeff Sharkeya0907432014-08-15 10:23:11 -0700730 final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext,
Benjamin Franzdabae882017-08-08 12:33:19 +0100731 statusReceiver, versionedPackage.getPackageName(),
732 isDeviceOwnerOrAffiliatedProfileOwner, userId);
Sudheer Shanka72de4dd2016-07-22 15:46:37 -0700733 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES)
734 == PackageManager.PERMISSION_GRANTED) {
Jeff Sharkeyf0600952014-08-07 17:31:53 -0700735 // Sweet, call straight through!
Svet Ganov67882122016-12-11 16:36:34 -0800736 mPm.deletePackageVersioned(versionedPackage, adapter.getBinder(), userId, flags);
Benjamin Franzdabae882017-08-08 12:33:19 +0100737 } else if (isDeviceOwnerOrAffiliatedProfileOwner) {
738 // Allow the device owner and affiliated profile owner to silently delete packages
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000739 // Need to clear the calling identity to get DELETE_PACKAGES permission
740 long ident = Binder.clearCallingIdentity();
741 try {
Svet Ganov67882122016-12-11 16:36:34 -0800742 mPm.deletePackageVersioned(versionedPackage, adapter.getBinder(), userId, flags);
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000743 } finally {
744 Binder.restoreCallingIdentity(ident);
745 }
Jeff Sharkeyf0600952014-08-07 17:31:53 -0700746 } else {
Philip P. Moltmannd9bb39a2017-09-05 12:41:15 -0700747 ApplicationInfo appInfo = mPm.getApplicationInfo(callerPackageName, 0, userId);
748 if (appInfo.targetSdkVersion >= Build.VERSION_CODES.P) {
749 mContext.enforceCallingOrSelfPermission(Manifest.permission.REQUEST_DELETE_PACKAGES,
750 null);
751 }
752
Jeff Sharkeyf0600952014-08-07 17:31:53 -0700753 // Take a short detour to confirm with user
754 final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
Svet Ganov67882122016-12-11 16:36:34 -0800755 intent.setData(Uri.fromParts("package", versionedPackage.getPackageName(), null));
Jeff Sharkeya0907432014-08-15 10:23:11 -0700756 intent.putExtra(PackageInstaller.EXTRA_CALLBACK, adapter.getBinder().asBinder());
757 adapter.onUserActionRequired(intent);
Jeff Sharkeyf0600952014-08-07 17:31:53 -0700758 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700759 }
760
761 @Override
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700762 public void setPermissionsResult(int sessionId, boolean accepted) {
763 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, TAG);
764
765 synchronized (mSessions) {
Svet Ganov3baa8762016-04-08 09:22:54 -0700766 PackageInstallerSession session = mSessions.get(sessionId);
767 if (session != null) {
768 session.setPermissionsResult(accepted);
769 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700770 }
771 }
772
773 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700774 public void registerCallback(IPackageInstallerCallback callback, int userId) {
Todd Kennedy0eb97382017-10-03 16:57:22 -0700775 mPermissionManager.enforceCrossUserPermission(
776 Binder.getCallingUid(), userId, true, false, "registerCallback");
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700777 mCallbacks.register(callback, userId);
Jeff Sharkeybb580672014-07-10 12:10:25 -0700778 }
779
780 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700781 public void unregisterCallback(IPackageInstallerCallback callback) {
782 mCallbacks.unregister(callback);
Jeff Sharkeya1031142014-07-12 18:09:46 -0700783 }
784
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700785 private static int getSessionCount(SparseArray<PackageInstallerSession> sessions,
786 int installerUid) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700787 int count = 0;
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700788 final int size = sessions.size();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700789 for (int i = 0; i < size; i++) {
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700790 final PackageInstallerSession session = sessions.valueAt(i);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000791 if (session.getInstallerUid() == installerUid) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700792 count++;
793 }
794 }
795 return count;
796 }
797
798 private boolean isCallingUidOwner(PackageInstallerSession session) {
799 final int callingUid = Binder.getCallingUid();
800 if (callingUid == Process.ROOT_UID) {
801 return true;
802 } else {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000803 return (session != null) && (callingUid == session.getInstallerUid());
Jeff Sharkeya1031142014-07-12 18:09:46 -0700804 }
805 }
806
Jeff Sharkeya0907432014-08-15 10:23:11 -0700807 static class PackageDeleteObserverAdapter extends PackageDeleteObserver {
808 private final Context mContext;
809 private final IntentSender mTarget;
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700810 private final String mPackageName;
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000811 private final Notification mNotification;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700812
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700813 public PackageDeleteObserverAdapter(Context context, IntentSender target,
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000814 String packageName, boolean showNotification, int userId) {
Jeff Sharkeya0907432014-08-15 10:23:11 -0700815 mContext = context;
816 mTarget = target;
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700817 mPackageName = packageName;
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000818 if (showNotification) {
819 mNotification = buildSuccessNotification(mContext,
820 mContext.getResources().getString(R.string.package_deleted_device_owner),
821 packageName,
822 userId);
823 } else {
824 mNotification = null;
825 }
Jeff Sharkeya0907432014-08-15 10:23:11 -0700826 }
827
828 @Override
829 public void onUserActionRequired(Intent intent) {
830 final Intent fillIn = new Intent();
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700831 fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName);
Jeff Sharkeya0907432014-08-15 10:23:11 -0700832 fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
Jeff Sharkey742e7902014-08-16 19:09:13 -0700833 PackageInstaller.STATUS_PENDING_USER_ACTION);
Jeff Sharkeya0907432014-08-15 10:23:11 -0700834 fillIn.putExtra(Intent.EXTRA_INTENT, intent);
835 try {
836 mTarget.sendIntent(mContext, 0, fillIn, null, null);
837 } catch (SendIntentException ignored) {
838 }
839 }
840
841 @Override
842 public void onPackageDeleted(String basePackageName, int returnCode, String msg) {
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000843 if (PackageManager.DELETE_SUCCEEDED == returnCode && mNotification != null) {
844 NotificationManager notificationManager = (NotificationManager)
845 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
Chris Wren282cfef2017-03-27 15:01:44 -0400846 notificationManager.notify(basePackageName,
847 SystemMessage.NOTE_PACKAGE_STATE,
848 mNotification);
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000849 }
Jeff Sharkeya0907432014-08-15 10:23:11 -0700850 final Intent fillIn = new Intent();
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700851 fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName);
Jeff Sharkeya0907432014-08-15 10:23:11 -0700852 fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
853 PackageManager.deleteStatusToPublicStatus(returnCode));
854 fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
855 PackageManager.deleteStatusToString(returnCode, msg));
856 fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode);
857 try {
858 mTarget.sendIntent(mContext, 0, fillIn, null, null);
859 } catch (SendIntentException ignored) {
860 }
861 }
862 }
863
864 static class PackageInstallObserverAdapter extends PackageInstallObserver {
865 private final Context mContext;
866 private final IntentSender mTarget;
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700867 private final int mSessionId;
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000868 private final boolean mShowNotification;
869 private final int mUserId;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700870
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000871 public PackageInstallObserverAdapter(Context context, IntentSender target, int sessionId,
872 boolean showNotification, int userId) {
Jeff Sharkeya0907432014-08-15 10:23:11 -0700873 mContext = context;
874 mTarget = target;
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700875 mSessionId = sessionId;
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000876 mShowNotification = showNotification;
877 mUserId = userId;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700878 }
879
880 @Override
881 public void onUserActionRequired(Intent intent) {
882 final Intent fillIn = new Intent();
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700883 fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId);
Jeff Sharkeya0907432014-08-15 10:23:11 -0700884 fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
Jeff Sharkey742e7902014-08-16 19:09:13 -0700885 PackageInstaller.STATUS_PENDING_USER_ACTION);
Jeff Sharkeya0907432014-08-15 10:23:11 -0700886 fillIn.putExtra(Intent.EXTRA_INTENT, intent);
887 try {
888 mTarget.sendIntent(mContext, 0, fillIn, null, null);
889 } catch (SendIntentException ignored) {
890 }
891 }
892
893 @Override
894 public void onPackageInstalled(String basePackageName, int returnCode, String msg,
895 Bundle extras) {
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000896 if (PackageManager.INSTALL_SUCCEEDED == returnCode && mShowNotification) {
Benjamin Franz2e3e9432015-04-17 15:28:17 +0100897 boolean update = (extras != null) && extras.getBoolean(Intent.EXTRA_REPLACING);
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000898 Notification notification = buildSuccessNotification(mContext,
Benjamin Franz2e3e9432015-04-17 15:28:17 +0100899 mContext.getResources()
900 .getString(update ? R.string.package_updated_device_owner :
901 R.string.package_installed_device_owner),
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000902 basePackageName,
903 mUserId);
904 if (notification != null) {
905 NotificationManager notificationManager = (NotificationManager)
906 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
Chris Wren282cfef2017-03-27 15:01:44 -0400907 notificationManager.notify(basePackageName,
908 SystemMessage.NOTE_PACKAGE_STATE,
909 notification);
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000910 }
911 }
Jeff Sharkeya0907432014-08-15 10:23:11 -0700912 final Intent fillIn = new Intent();
Benjamin Franz2e3e9432015-04-17 15:28:17 +0100913 fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, basePackageName);
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700914 fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId);
Jeff Sharkeya0907432014-08-15 10:23:11 -0700915 fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
916 PackageManager.installStatusToPublicStatus(returnCode));
917 fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
918 PackageManager.installStatusToString(returnCode, msg));
919 fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode);
920 if (extras != null) {
921 final String existing = extras.getString(
922 PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE);
923 if (!TextUtils.isEmpty(existing)) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700924 fillIn.putExtra(PackageInstaller.EXTRA_OTHER_PACKAGE_NAME, existing);
Jeff Sharkeya0907432014-08-15 10:23:11 -0700925 }
926 }
927 try {
928 mTarget.sendIntent(mContext, 0, fillIn, null, null);
929 } catch (SendIntentException ignored) {
930 }
931 }
932 }
933
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000934 /**
935 * Build a notification for package installation / deletion by device owners that is shown if
936 * the operation succeeds.
937 */
938 private static Notification buildSuccessNotification(Context context, String contentText,
939 String basePackageName, int userId) {
940 PackageInfo packageInfo = null;
941 try {
942 packageInfo = AppGlobals.getPackageManager().getPackageInfo(
Svet Ganova5c867c2017-05-15 01:17:05 -0700943 basePackageName, PackageManager.MATCH_STATIC_SHARED_LIBRARIES, userId);
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000944 } catch (RemoteException ignored) {
945 }
946 if (packageInfo == null || packageInfo.applicationInfo == null) {
947 Slog.w(TAG, "Notification not built for package: " + basePackageName);
948 return null;
949 }
950 PackageManager pm = context.getPackageManager();
951 Bitmap packageIcon = ImageUtils.buildScaledBitmap(
952 packageInfo.applicationInfo.loadIcon(pm),
953 context.getResources().getDimensionPixelSize(
954 android.R.dimen.notification_large_icon_width),
955 context.getResources().getDimensionPixelSize(
956 android.R.dimen.notification_large_icon_height));
957 CharSequence packageLabel = packageInfo.applicationInfo.loadLabel(pm);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -0500958 return new Notification.Builder(context, SystemNotificationChannels.DEVICE_ADMIN)
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000959 .setSmallIcon(R.drawable.ic_check_circle_24px)
960 .setColor(context.getResources().getColor(
961 R.color.system_notification_accent_color))
962 .setContentTitle(packageLabel)
963 .setContentText(contentText)
Benjamin Franz2e3e9432015-04-17 15:28:17 +0100964 .setStyle(new Notification.BigTextStyle().bigText(contentText))
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000965 .setLargeIcon(packageIcon)
966 .build();
967 }
968
Jeff Sharkey54d42be2015-07-20 16:36:55 -0700969 public static <E> ArraySet<E> newArraySet(E... elements) {
970 final ArraySet<E> set = new ArraySet<E>();
971 if (elements != null) {
972 set.ensureCapacity(elements.length);
973 Collections.addAll(set, elements);
974 }
975 return set;
976 }
977
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700978 private static class Callbacks extends Handler {
979 private static final int MSG_SESSION_CREATED = 1;
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700980 private static final int MSG_SESSION_BADGING_CHANGED = 2;
Jeff Sharkeybc7bce32014-09-05 15:53:05 -0700981 private static final int MSG_SESSION_ACTIVE_CHANGED = 3;
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700982 private static final int MSG_SESSION_PROGRESS_CHANGED = 4;
Jeff Sharkeybc7bce32014-09-05 15:53:05 -0700983 private static final int MSG_SESSION_FINISHED = 5;
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700984
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700985 private final RemoteCallbackList<IPackageInstallerCallback>
986 mCallbacks = new RemoteCallbackList<>();
Jeff Sharkeya1031142014-07-12 18:09:46 -0700987
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700988 public Callbacks(Looper looper) {
989 super(looper);
990 }
991
992 public void register(IPackageInstallerCallback callback, int userId) {
993 mCallbacks.register(callback, new UserHandle(userId));
994 }
995
996 public void unregister(IPackageInstallerCallback callback) {
997 mCallbacks.unregister(callback);
998 }
999
1000 @Override
1001 public void handleMessage(Message msg) {
1002 final int userId = msg.arg2;
1003 final int n = mCallbacks.beginBroadcast();
1004 for (int i = 0; i < n; i++) {
1005 final IPackageInstallerCallback callback = mCallbacks.getBroadcastItem(i);
1006 final UserHandle user = (UserHandle) mCallbacks.getBroadcastCookie(i);
1007 // TODO: dispatch notifications for slave profiles
1008 if (userId == user.getIdentifier()) {
1009 try {
1010 invokeCallback(callback, msg);
1011 } catch (RemoteException ignored) {
1012 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07001013 }
1014 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001015 mCallbacks.finishBroadcast();
Jeff Sharkeya1031142014-07-12 18:09:46 -07001016 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001017
1018 private void invokeCallback(IPackageInstallerCallback callback, Message msg)
1019 throws RemoteException {
1020 final int sessionId = msg.arg1;
1021 switch (msg.what) {
1022 case MSG_SESSION_CREATED:
1023 callback.onSessionCreated(sessionId);
1024 break;
Jeff Sharkeyec9bad22014-09-05 09:45:20 -07001025 case MSG_SESSION_BADGING_CHANGED:
1026 callback.onSessionBadgingChanged(sessionId);
1027 break;
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001028 case MSG_SESSION_ACTIVE_CHANGED:
1029 callback.onSessionActiveChanged(sessionId, (boolean) msg.obj);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001030 break;
1031 case MSG_SESSION_PROGRESS_CHANGED:
1032 callback.onSessionProgressChanged(sessionId, (float) msg.obj);
1033 break;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001034 case MSG_SESSION_FINISHED:
1035 callback.onSessionFinished(sessionId, (boolean) msg.obj);
1036 break;
1037 }
1038 }
1039
1040 private void notifySessionCreated(int sessionId, int userId) {
1041 obtainMessage(MSG_SESSION_CREATED, sessionId, userId).sendToTarget();
1042 }
1043
Jeff Sharkeyec9bad22014-09-05 09:45:20 -07001044 private void notifySessionBadgingChanged(int sessionId, int userId) {
1045 obtainMessage(MSG_SESSION_BADGING_CHANGED, sessionId, userId).sendToTarget();
1046 }
1047
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001048 private void notifySessionActiveChanged(int sessionId, int userId, boolean active) {
1049 obtainMessage(MSG_SESSION_ACTIVE_CHANGED, sessionId, userId, active).sendToTarget();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001050 }
1051
1052 private void notifySessionProgressChanged(int sessionId, int userId, float progress) {
1053 obtainMessage(MSG_SESSION_PROGRESS_CHANGED, sessionId, userId, progress).sendToTarget();
1054 }
1055
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001056 public void notifySessionFinished(int sessionId, int userId, boolean success) {
1057 obtainMessage(MSG_SESSION_FINISHED, sessionId, userId, success).sendToTarget();
1058 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07001059 }
1060
1061 void dump(IndentingPrintWriter pw) {
Jeff Sharkeya1031142014-07-12 18:09:46 -07001062 synchronized (mSessions) {
Jeff Sharkey9a445772014-07-16 11:32:08 -07001063 pw.println("Active install sessions:");
1064 pw.increaseIndent();
1065 int N = mSessions.size();
Jeff Sharkeya1031142014-07-12 18:09:46 -07001066 for (int i = 0; i < N; i++) {
1067 final PackageInstallerSession session = mSessions.valueAt(i);
1068 session.dump(pw);
1069 pw.println();
1070 }
Jeff Sharkey9a445772014-07-16 11:32:08 -07001071 pw.println();
1072 pw.decreaseIndent();
1073
1074 pw.println("Historical install sessions:");
1075 pw.increaseIndent();
1076 N = mHistoricalSessions.size();
1077 for (int i = 0; i < N; i++) {
Narayan Kamatha22a7662017-06-12 13:34:29 +01001078 pw.print(mHistoricalSessions.get(i));
Jeff Sharkey9a445772014-07-16 11:32:08 -07001079 pw.println();
1080 }
1081 pw.println();
1082 pw.decreaseIndent();
Jeff Sharkey742e7902014-08-16 19:09:13 -07001083
1084 pw.println("Legacy install sessions:");
1085 pw.increaseIndent();
1086 pw.println(mLegacySessions.toString());
1087 pw.decreaseIndent();
Jeff Sharkeya1031142014-07-12 18:09:46 -07001088 }
Jeff Sharkeybb580672014-07-10 12:10:25 -07001089 }
1090
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001091 class InternalCallback {
Jeff Sharkeyec9bad22014-09-05 09:45:20 -07001092 public void onSessionBadgingChanged(PackageInstallerSession session) {
1093 mCallbacks.notifySessionBadgingChanged(session.sessionId, session.userId);
1094 writeSessionsAsync();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001095 }
1096
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001097 public void onSessionActiveChanged(PackageInstallerSession session, boolean active) {
1098 mCallbacks.notifySessionActiveChanged(session.sessionId, session.userId, active);
Jeff Sharkey742e7902014-08-16 19:09:13 -07001099 }
1100
Jeff Sharkeyec9bad22014-09-05 09:45:20 -07001101 public void onSessionProgressChanged(PackageInstallerSession session, float progress) {
1102 mCallbacks.notifySessionProgressChanged(session.sessionId, session.userId, progress);
1103 }
1104
Jeff Sharkeycbf47912014-09-12 09:55:32 -07001105 public void onSessionFinished(final PackageInstallerSession session, boolean success) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001106 mCallbacks.notifySessionFinished(session.sessionId, session.userId, success);
Jeff Sharkeycbf47912014-09-12 09:55:32 -07001107
1108 mInstallHandler.post(new Runnable() {
1109 @Override
1110 public void run() {
1111 synchronized (mSessions) {
1112 mSessions.remove(session.sessionId);
Narayan Kamatha22a7662017-06-12 13:34:29 +01001113 addHistoricalSessionLocked(session);
Jeff Sharkey02bd7842014-10-06 15:14:27 -07001114
1115 final File appIconFile = buildAppIconFile(session.sessionId);
1116 if (appIconFile.exists()) {
1117 appIconFile.delete();
1118 }
1119
Jeff Sharkeycbf47912014-09-12 09:55:32 -07001120 writeSessionsLocked();
1121 }
1122 }
1123 });
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001124 }
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -07001125
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001126 public void onSessionPrepared(PackageInstallerSession session) {
1127 // We prepared the destination to write into; we want to persist
1128 // this, but it's not critical enough to block for.
1129 writeSessionsAsync();
1130 }
1131
Jeff Sharkeycbf47912014-09-12 09:55:32 -07001132 public void onSessionSealedBlocking(PackageInstallerSession session) {
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -07001133 // It's very important that we block until we've recorded the
1134 // session as being sealed, since we never want to allow mutation
1135 // after sealing.
Jeff Sharkeycbf47912014-09-12 09:55:32 -07001136 synchronized (mSessions) {
1137 writeSessionsLocked();
1138 }
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -07001139 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001140 }
1141}