blob: 1a5b86cfbce0dd0ead1d75594a10aa7c557ed4b1 [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;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070061import android.os.UserHandle;
62import android.os.UserManager;
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -070063import android.os.storage.StorageManager;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -070064import android.system.ErrnoException;
65import android.system.Os;
Jeff Sharkeya0907432014-08-15 10:23:11 -070066import android.text.TextUtils;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070067import android.text.format.DateUtils;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070068import android.util.ArraySet;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070069import android.util.AtomicFile;
Jeff Sharkeya1031142014-07-12 18:09:46 -070070import android.util.ExceptionUtils;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070071import android.util.Slog;
72import android.util.SparseArray;
Jeff Sharkey742e7902014-08-16 19:09:13 -070073import android.util.SparseBooleanArray;
Narayan Kamatha22a7662017-06-12 13:34:29 +010074import android.util.SparseIntArray;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070075import android.util.Xml;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070076
Benjamin Franz39fb7fd2015-02-18 16:11:18 +000077import com.android.internal.R;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070078import com.android.internal.annotations.GuardedBy;
Jeff Sharkey742e7902014-08-16 19:09:13 -070079import com.android.internal.content.PackageHelper;
Chris Wren282cfef2017-03-27 15:01:44 -040080import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
Geoffrey Pitschaf759c52017-02-15 09:35:38 -050081import com.android.internal.notification.SystemNotificationChannels;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070082import com.android.internal.util.FastXmlSerializer;
Benjamin Franz39fb7fd2015-02-18 16:11:18 +000083import com.android.internal.util.ImageUtils;
Jeff Sharkeya1031142014-07-12 18:09:46 -070084import com.android.internal.util.IndentingPrintWriter;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070085import com.android.server.IoThread;
Todd Kennedy0eb97382017-10-03 16:57:22 -070086import com.android.server.LocalServices;
87import com.android.server.pm.permission.PermissionManagerInternal;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070088
Philip P. Moltmann7460c592017-08-08 20:07:11 +000089import libcore.io.IoUtils;
90
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070091import org.xmlpull.v1.XmlPullParser;
92import org.xmlpull.v1.XmlPullParserException;
93import org.xmlpull.v1.XmlSerializer;
94
Philip P. Moltmann7460c592017-08-08 20:07:11 +000095import java.io.CharArrayWriter;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070096import java.io.File;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070097import java.io.FileInputStream;
98import java.io.FileNotFoundException;
99import java.io.FileOutputStream;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700100import java.io.FilenameFilter;
101import java.io.IOException;
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +0100102import java.nio.charset.StandardCharsets;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700103import java.security.SecureRandom;
Jeff Sharkeybb580672014-07-10 12:10:25 -0700104import java.util.ArrayList;
Jeff Sharkey54d42be2015-07-20 16:36:55 -0700105import java.util.Collections;
Jeff Sharkeybb580672014-07-10 12:10:25 -0700106import java.util.List;
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700107import java.util.Objects;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700108import java.util.Random;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700109
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000110/** The service responsible for installing packages. */
111public class PackageInstallerService extends IPackageInstaller.Stub implements
112 PackageSessionProvider {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700113 private static final String TAG = "PackageInstaller";
Jeff Sharkeye9808042014-09-11 21:15:37 -0700114 private static final boolean LOGD = false;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700115
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700116 // TODO: remove outstanding sessions when installer package goes away
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700117 // TODO: notify listeners in other users when package has been installed there
Jeff Sharkey742e7902014-08-16 19:09:13 -0700118 // TODO: purge expired sessions periodically in addition to at reboot
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700119
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700120 /** XML constants used in {@link #mSessionsFile} */
121 private static final String TAG_SESSIONS = "sessions";
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700122
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700123 /** Automatically destroy sessions older than this */
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700124 private static final long MAX_AGE_MILLIS = 3 * DateUtils.DAY_IN_MILLIS;
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700125 /** Upper bound on number of active sessions for a UID */
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700126 private static final long MAX_ACTIVE_SESSIONS = 1024;
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700127 /** Upper bound on number of historical sessions for a UID */
128 private static final long MAX_HISTORICAL_SESSIONS = 1048576;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700129
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700130 private final Context mContext;
131 private final PackageManagerService mPm;
Todd Kennedy0eb97382017-10-03 16:57:22 -0700132 private final PermissionManagerInternal mPermissionManager;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700133
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700134 private AppOpsManager mAppOps;
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700135
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700136 private final HandlerThread mInstallThread;
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700137 private final Handler mInstallHandler;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700138
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700139 private final Callbacks mCallbacks;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700140
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700141 /**
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700142 * File storing persisted {@link #mSessions} metadata.
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700143 */
144 private final AtomicFile mSessionsFile;
145
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700146 /**
147 * Directory storing persisted {@link #mSessions} metadata which is too
148 * heavy to store directly in {@link #mSessionsFile}.
149 */
150 private final File mSessionsDir;
151
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700152 private final InternalCallback mInternalCallback = new InternalCallback();
153
154 /**
155 * Used for generating session IDs. Since this is created at boot time,
156 * normal random might be predictable.
157 */
158 private final Random mRandom = new SecureRandom();
159
Todd Kennedy28c4e802016-07-13 13:20:30 -0700160 /** All sessions allocated */
161 @GuardedBy("mSessions")
162 private final SparseBooleanArray mAllocatedSessions = new SparseBooleanArray();
163
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700164 @GuardedBy("mSessions")
165 private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>();
166
Jeff Sharkey9a445772014-07-16 11:32:08 -0700167 /** Historical sessions kept around for debugging purposes */
168 @GuardedBy("mSessions")
Narayan Kamatha22a7662017-06-12 13:34:29 +0100169 private final List<String> mHistoricalSessions = new ArrayList<>();
170
171 @GuardedBy("mSessions")
172 private final SparseIntArray mHistoricalSessionsByInstaller = new SparseIntArray();
Jeff Sharkey9a445772014-07-16 11:32:08 -0700173
Jeff Sharkey742e7902014-08-16 19:09:13 -0700174 /** Sessions allocated to legacy users */
175 @GuardedBy("mSessions")
176 private final SparseBooleanArray mLegacySessions = new SparseBooleanArray();
177
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700178 private static final FilenameFilter sStageFilter = new FilenameFilter() {
179 @Override
180 public boolean accept(File dir, String name) {
Jeff Sharkey742e7902014-08-16 19:09:13 -0700181 return isStageName(name);
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700182 }
183 };
184
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700185 public PackageInstallerService(Context context, PackageManagerService pm) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700186 mContext = context;
187 mPm = pm;
Todd Kennedy0eb97382017-10-03 16:57:22 -0700188 mPermissionManager = LocalServices.getService(PermissionManagerInternal.class);
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700189
190 mInstallThread = new HandlerThread(TAG);
191 mInstallThread.start();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700192
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700193 mInstallHandler = new Handler(mInstallThread.getLooper());
194
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700195 mCallbacks = new Callbacks(mInstallThread.getLooper());
196
197 mSessionsFile = new AtomicFile(
Dianne Hackborne17b4452018-01-10 13:15:40 -0800198 new File(Environment.getDataSystemDirectory(), "install_sessions.xml"),
199 "package-session");
Jeff Sharkey8212ae02016-02-10 14:46:43 -0700200 mSessionsDir = new File(Environment.getDataSystemDirectory(), "install_sessions");
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700201 mSessionsDir.mkdirs();
Tony Mak606f8e72017-02-15 18:40:03 +0000202 }
203
204 public void systemReady() {
205 mAppOps = mContext.getSystemService(AppOpsManager.class);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700206
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700207 synchronized (mSessions) {
208 readSessionsLocked();
209
Svetoslav Ganov096d3042017-01-30 16:34:13 -0800210 reconcileStagesLocked(StorageManager.UUID_PRIVATE_INTERNAL, false /*isInstant*/);
211 reconcileStagesLocked(StorageManager.UUID_PRIVATE_INTERNAL, true /*isInstant*/);
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700212
Jeff Sharkey54d42be2015-07-20 16:36:55 -0700213 final ArraySet<File> unclaimedIcons = newArraySet(
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700214 mSessionsDir.listFiles());
Jeff Sharkey742e7902014-08-16 19:09:13 -0700215
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700216 // Ignore stages and icons claimed by active sessions
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700217 for (int i = 0; i < mSessions.size(); i++) {
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700218 final PackageInstallerSession session = mSessions.valueAt(i);
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700219 unclaimedIcons.remove(buildAppIconFile(session.sessionId));
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700220 }
Jeff Sharkey742e7902014-08-16 19:09:13 -0700221
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700222 // Clean up orphaned icons
223 for (File icon : unclaimedIcons) {
224 Slog.w(TAG, "Deleting orphan icon " + icon);
225 icon.delete();
226 }
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700227 }
228 }
229
Andreas Gampea36dc622018-02-05 17:19:22 -0800230 @GuardedBy("mSessions")
Todd Kennedy2699f062015-11-20 13:07:17 -0800231 private void reconcileStagesLocked(String volumeUuid, boolean isEphemeral) {
232 final File stagingDir = buildStagingDir(volumeUuid, isEphemeral);
Jeff Sharkey54d42be2015-07-20 16:36:55 -0700233 final ArraySet<File> unclaimedStages = newArraySet(
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700234 stagingDir.listFiles(sStageFilter));
235
236 // Ignore stages claimed by active sessions
237 for (int i = 0; i < mSessions.size(); i++) {
238 final PackageInstallerSession session = mSessions.valueAt(i);
239 unclaimedStages.remove(session.stageDir);
240 }
241
242 // Clean up orphaned staging directories
243 for (File stage : unclaimedStages) {
244 Slog.w(TAG, "Deleting orphan stage " + stage);
245 synchronized (mPm.mInstallLock) {
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -0700246 mPm.removeCodePathLI(stage);
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700247 }
248 }
249 }
250
251 public void onPrivateVolumeMounted(String volumeUuid) {
252 synchronized (mSessions) {
Svetoslav Ganov096d3042017-01-30 16:34:13 -0800253 reconcileStagesLocked(volumeUuid, false /*isInstant*/);
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700254 }
255 }
256
Jeff Sharkey742e7902014-08-16 19:09:13 -0700257 public static boolean isStageName(String name) {
258 final boolean isFile = name.startsWith("vmdl") && name.endsWith(".tmp");
259 final boolean isContainer = name.startsWith("smdl") && name.endsWith(".tmp");
260 final boolean isLegacyContainer = name.startsWith("smdl2tmp");
261 return isFile || isContainer || isLegacyContainer;
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700262 }
263
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700264 @Deprecated
Todd Kennedy2699f062015-11-20 13:07:17 -0800265 public File allocateStageDirLegacy(String volumeUuid, boolean isEphemeral) throws IOException {
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700266 synchronized (mSessions) {
267 try {
268 final int sessionId = allocateSessionIdLocked();
Jeff Sharkey742e7902014-08-16 19:09:13 -0700269 mLegacySessions.put(sessionId, true);
Todd Kennedy2699f062015-11-20 13:07:17 -0800270 final File stageDir = buildStageDir(volumeUuid, sessionId, isEphemeral);
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700271 prepareStageDir(stageDir);
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700272 return stageDir;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700273 } catch (IllegalStateException e) {
274 throw new IOException(e);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700275 }
276 }
277 }
278
Jeff Sharkey742e7902014-08-16 19:09:13 -0700279 @Deprecated
280 public String allocateExternalStageCidLegacy() {
281 synchronized (mSessions) {
282 final int sessionId = allocateSessionIdLocked();
283 mLegacySessions.put(sessionId, true);
284 return "smdl" + sessionId + ".tmp";
285 }
286 }
287
Andreas Gampea36dc622018-02-05 17:19:22 -0800288 @GuardedBy("mSessions")
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700289 private void readSessionsLocked() {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700290 if (LOGD) Slog.v(TAG, "readSessionsLocked()");
291
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700292 mSessions.clear();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700293
294 FileInputStream fis = null;
295 try {
296 fis = mSessionsFile.openRead();
297 final XmlPullParser in = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +0100298 in.setInput(fis, StandardCharsets.UTF_8.name());
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700299
300 int type;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000301 PackageInstallerSession currentSession = null;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700302 while ((type = in.next()) != END_DOCUMENT) {
303 if (type == START_TAG) {
304 final String tag = in.getName();
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000305 if (PackageInstallerSession.TAG_SESSION.equals(tag)) {
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -0700306 final PackageInstallerSession session;
307 try {
308 session = PackageInstallerSession.readFromXml(in, mInternalCallback,
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000309 mContext, mPm, mInstallThread.getLooper(), mSessionsDir, this);
310 currentSession = session;
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -0700311 } catch (Exception e) {
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000312 currentSession = null;
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -0700313 Slog.e(TAG, "Could not read session", e);
314 continue;
315 }
316
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700317 final long age = System.currentTimeMillis() - session.createdMillis;
318
319 final boolean valid;
320 if (age >= MAX_AGE_MILLIS) {
321 Slog.w(TAG, "Abandoning old session first created at "
322 + session.createdMillis);
323 valid = false;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700324 } else {
325 valid = true;
326 }
327
328 if (valid) {
329 mSessions.put(session.sessionId, session);
330 } else {
331 // Since this is early during boot we don't send
332 // any observer events about the session, but we
333 // keep details around for dumpsys.
Narayan Kamatha22a7662017-06-12 13:34:29 +0100334 addHistoricalSessionLocked(session);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700335 }
Todd Kennedy28c4e802016-07-13 13:20:30 -0700336 mAllocatedSessions.put(session.sessionId, true);
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000337 } else if (currentSession != null
338 && PackageInstallerSession.TAG_CHILD_SESSION.equals(tag)) {
339 currentSession.addChildSessionIdInternal(
340 PackageInstallerSession.readChildSessionIdFromXml(in));
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700341 }
342 }
343 }
344 } catch (FileNotFoundException e) {
345 // Missing sessions are okay, probably first boot
Svet Ganov7121e182015-07-13 22:38:12 -0700346 } catch (IOException | XmlPullParserException e) {
Dianne Hackborn8d051722014-10-01 14:59:58 -0700347 Slog.wtf(TAG, "Failed reading install sessions", e);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700348 } finally {
349 IoUtils.closeQuietly(fis);
350 }
351 }
352
Andreas Gampea36dc622018-02-05 17:19:22 -0800353 @GuardedBy("mSessions")
Narayan Kamatha22a7662017-06-12 13:34:29 +0100354 private void addHistoricalSessionLocked(PackageInstallerSession session) {
355 CharArrayWriter writer = new CharArrayWriter();
356 IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
357 session.dump(pw);
358 mHistoricalSessions.add(writer.toString());
359
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000360 int installerUid = session.getInstallerUid();
Narayan Kamatha22a7662017-06-12 13:34:29 +0100361 // Increment the number of sessions by this installerUid.
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000362 mHistoricalSessionsByInstaller.put(installerUid,
363 mHistoricalSessionsByInstaller.get(installerUid) + 1);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700364 }
365
Andreas Gampea36dc622018-02-05 17:19:22 -0800366 @GuardedBy("mSessions")
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700367 private void writeSessionsLocked() {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700368 if (LOGD) Slog.v(TAG, "writeSessionsLocked()");
369
370 FileOutputStream fos = null;
371 try {
372 fos = mSessionsFile.startWrite();
373
374 XmlSerializer out = new FastXmlSerializer();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +0100375 out.setOutput(fos, StandardCharsets.UTF_8.name());
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700376 out.startDocument(null, true);
377 out.startTag(null, TAG_SESSIONS);
378 final int size = mSessions.size();
379 for (int i = 0; i < size; i++) {
380 final PackageInstallerSession session = mSessions.valueAt(i);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000381 session.write(out, mSessionsDir);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700382 }
383 out.endTag(null, TAG_SESSIONS);
384 out.endDocument();
385
386 mSessionsFile.finishWrite(fos);
387 } catch (IOException e) {
388 if (fos != null) {
389 mSessionsFile.failWrite(fos);
390 }
391 }
392 }
393
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700394 private File buildAppIconFile(int sessionId) {
395 return new File(mSessionsDir, "app_icon." + sessionId + ".png");
396 }
397
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700398 private void writeSessionsAsync() {
399 IoThread.getHandler().post(new Runnable() {
400 @Override
401 public void run() {
402 synchronized (mSessions) {
403 writeSessionsLocked();
404 }
405 }
406 });
407 }
408
409 @Override
Jeff Sharkeya0907432014-08-15 10:23:11 -0700410 public int createSession(SessionParams params, String installerPackageName, int userId) {
Jeff Sharkey742e7902014-08-16 19:09:13 -0700411 try {
412 return createSessionInternal(params, installerPackageName, userId);
413 } catch (IOException e) {
414 throw ExceptionUtils.wrap(e);
415 }
416 }
417
418 private int createSessionInternal(SessionParams params, String installerPackageName, int userId)
419 throws IOException {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700420 final int callingUid = Binder.getCallingUid();
Todd Kennedy0eb97382017-10-03 16:57:22 -0700421 mPermissionManager.enforceCrossUserPermission(
422 callingUid, userId, true, true, "createSession");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700423
Jeff Sharkeye9808042014-09-11 21:15:37 -0700424 if (mPm.isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700425 throw new SecurityException("User restriction prevents installing");
426 }
427
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700428 if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {
Jeff Sharkeye9808042014-09-11 21:15:37 -0700429 params.installFlags |= PackageManager.INSTALL_FROM_ADB;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700430
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700431 } else {
Philip P. Moltmann79c238a2017-12-13 15:59:07 -0800432 // Only apps with INSTALL_PACKAGES are allowed to set an installer that is not the
433 // caller.
434 if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES) !=
435 PackageManager.PERMISSION_GRANTED) {
436 mAppOps.checkPackage(callingUid, installerPackageName);
437 }
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700438
Jeff Sharkeye9808042014-09-11 21:15:37 -0700439 params.installFlags &= ~PackageManager.INSTALL_FROM_ADB;
440 params.installFlags &= ~PackageManager.INSTALL_ALL_USERS;
441 params.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
Todd Kennedy78a72502017-07-19 12:49:30 -0700442 if ((params.installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0
443 && !mPm.isCallerVerifier(callingUid)) {
444 params.installFlags &= ~PackageManager.INSTALL_VIRTUAL_PRELOAD;
445 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700446 }
447
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000448 if (!params.isMultiPackage) {
449 // Only system components can circumvent runtime permissions when installing.
450 if ((params.installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0
451 && mContext.checkCallingOrSelfPermission(Manifest.permission
452 .INSTALL_GRANT_RUNTIME_PERMISSIONS) == PackageManager.PERMISSION_DENIED) {
453 throw new SecurityException("You need the "
454 + "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS permission "
455 + "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag");
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700456 }
457
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000458 if ((params.installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0
459 || (params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
460 throw new IllegalArgumentException(
461 "New installs into ASEC containers no longer supported");
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700462 }
463
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000464 // Defensively resize giant app icons
465 if (params.appIcon != null) {
466 final ActivityManager am = (ActivityManager) mContext.getSystemService(
467 Context.ACTIVITY_SERVICE);
468 final int iconSize = am.getLauncherLargeIconSize();
469 if ((params.appIcon.getWidth() > iconSize * 2)
470 || (params.appIcon.getHeight() > iconSize * 2)) {
471 params.appIcon = Bitmap.createScaledBitmap(params.appIcon, iconSize, iconSize,
472 true);
473 }
474 }
Jeff Sharkeyab234092015-06-09 21:42:22 -0700475
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000476 switch (params.mode) {
477 case SessionParams.MODE_FULL_INSTALL:
478 case SessionParams.MODE_INHERIT_EXISTING:
479 break;
480 default:
481 throw new IllegalArgumentException("Invalid install mode: " + params.mode);
482 }
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700483
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000484 // If caller requested explicit location, sanity check it, otherwise
485 // resolve the best internal or adopted location.
486 if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
487 if (!PackageHelper.fitsOnInternal(mContext, params)) {
488 throw new IOException("No suitable internal storage available");
489 }
490
491 } else if ((params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
492 if (!PackageHelper.fitsOnExternal(mContext, params)) {
493 throw new IOException("No suitable external storage available");
494 }
495
496 } else if ((params.installFlags & PackageManager.INSTALL_FORCE_VOLUME_UUID) != 0) {
497 // For now, installs to adopted media are treated as internal from
498 // an install flag point-of-view.
499 params.setInstallFlagsInternal();
500
501 } else {
502 // For now, installs to adopted media are treated as internal from
503 // an install flag point-of-view.
504 params.setInstallFlagsInternal();
505
506 // Resolve best location for install, based on combination of
507 // requested install flags, delta size, and manifest settings.
508 final long ident = Binder.clearCallingIdentity();
509 try {
510 params.volumeUuid = PackageHelper.resolveInstallVolume(mContext, params);
511 } finally {
512 Binder.restoreCallingIdentity(ident);
513 }
Robin Leee812d902014-08-21 16:51:18 +0100514 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700515 }
516
517 final int sessionId;
518 final PackageInstallerSession session;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700519 synchronized (mSessions) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700520 // Sanity check that installer isn't going crazy
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700521 final int activeCount = getSessionCount(mSessions, callingUid);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700522 if (activeCount >= MAX_ACTIVE_SESSIONS) {
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700523 throw new IllegalStateException(
524 "Too many active sessions for UID " + callingUid);
525 }
Narayan Kamatha22a7662017-06-12 13:34:29 +0100526 final int historicalCount = mHistoricalSessionsByInstaller.get(callingUid);
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700527 if (historicalCount >= MAX_HISTORICAL_SESSIONS) {
528 throw new IllegalStateException(
529 "Too many historical sessions for UID " + callingUid);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700530 }
531
Jeff Sharkeya1031142014-07-12 18:09:46 -0700532 sessionId = allocateSessionIdLocked();
Todd Kennedy04918fe2016-07-12 14:07:40 -0700533 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700534
Todd Kennedy04918fe2016-07-12 14:07:40 -0700535 final long createdMillis = System.currentTimeMillis();
536 // We're staging to exactly one location
537 File stageDir = null;
538 String stageCid = null;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000539 if (!params.isMultiPackage) {
540 if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
541 final boolean isInstant =
542 (params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
543 stageDir = buildStageDir(params.volumeUuid, sessionId, isInstant);
544 } else {
545 stageCid = buildExternalStageCid(sessionId);
546 }
Todd Kennedy04918fe2016-07-12 14:07:40 -0700547 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000548 session = new PackageInstallerSession(mInternalCallback, mContext, mPm, this,
549 mInstallThread.getLooper(), sessionId, userId, installerPackageName,
550 callingUid, params, createdMillis, stageDir, stageCid, false, false, null,
551 SessionInfo.INVALID_ID);
Todd Kennedy04918fe2016-07-12 14:07:40 -0700552
553 synchronized (mSessions) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700554 mSessions.put(sessionId, session);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700555 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700556
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700557 mCallbacks.notifySessionCreated(session.sessionId, session.userId);
Jeff Sharkeya1031142014-07-12 18:09:46 -0700558 writeSessionsAsync();
559 return sessionId;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700560 }
561
Jeff Sharkey381d94b2014-08-24 14:45:56 -0700562 @Override
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700563 public void updateSessionAppIcon(int sessionId, Bitmap appIcon) {
564 synchronized (mSessions) {
565 final PackageInstallerSession session = mSessions.get(sessionId);
566 if (session == null || !isCallingUidOwner(session)) {
567 throw new SecurityException("Caller has no access to session " + sessionId);
568 }
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700569
570 // Defensively resize giant app icons
571 if (appIcon != null) {
572 final ActivityManager am = (ActivityManager) mContext.getSystemService(
573 Context.ACTIVITY_SERVICE);
574 final int iconSize = am.getLauncherLargeIconSize();
575 if ((appIcon.getWidth() > iconSize * 2)
576 || (appIcon.getHeight() > iconSize * 2)) {
577 appIcon = Bitmap.createScaledBitmap(appIcon, iconSize, iconSize, true);
578 }
579 }
580
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700581 session.params.appIcon = appIcon;
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700582 session.params.appIconLastModified = -1;
583
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700584 mInternalCallback.onSessionBadgingChanged(session);
585 }
586 }
587
588 @Override
589 public void updateSessionAppLabel(int sessionId, String appLabel) {
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.params.appLabel = appLabel;
596 mInternalCallback.onSessionBadgingChanged(session);
597 }
598 }
599
600 @Override
Jeff Sharkey381d94b2014-08-24 14:45:56 -0700601 public void abandonSession(int sessionId) {
602 synchronized (mSessions) {
603 final PackageInstallerSession session = mSessions.get(sessionId);
604 if (session == null || !isCallingUidOwner(session)) {
605 throw new SecurityException("Caller has no access to session " + sessionId);
606 }
607 session.abandon();
608 }
609 }
610
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700611 @Override
612 public IPackageInstallerSession openSession(int sessionId) {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700613 try {
614 return openSessionInternal(sessionId);
615 } catch (IOException e) {
616 throw ExceptionUtils.wrap(e);
617 }
618 }
619
620 private IPackageInstallerSession openSessionInternal(int sessionId) throws IOException {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700621 synchronized (mSessions) {
622 final PackageInstallerSession session = mSessions.get(sessionId);
Jeff Sharkey381d94b2014-08-24 14:45:56 -0700623 if (session == null || !isCallingUidOwner(session)) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700624 throw new SecurityException("Caller has no access to session " + sessionId);
625 }
Jeff Sharkey742e7902014-08-16 19:09:13 -0700626 session.open();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700627 return session;
628 }
629 }
630
Andreas Gampea36dc622018-02-05 17:19:22 -0800631 @GuardedBy("mSessions")
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700632 private int allocateSessionIdLocked() {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700633 int n = 0;
634 int sessionId;
635 do {
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700636 sessionId = mRandom.nextInt(Integer.MAX_VALUE - 1) + 1;
Todd Kennedy28c4e802016-07-13 13:20:30 -0700637 if (!mAllocatedSessions.get(sessionId, false)) {
638 mAllocatedSessions.put(sessionId, true);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700639 return sessionId;
640 }
641 } while (n++ < 32);
642
643 throw new IllegalStateException("Failed to allocate session ID");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700644 }
645
Todd Kennedy2699f062015-11-20 13:07:17 -0800646 private File buildStagingDir(String volumeUuid, boolean isEphemeral) {
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700647 return Environment.getDataAppDirectory(volumeUuid);
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700648 }
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700649
Todd Kennedy2699f062015-11-20 13:07:17 -0800650 private File buildStageDir(String volumeUuid, int sessionId, boolean isEphemeral) {
651 final File stagingDir = buildStagingDir(volumeUuid, isEphemeral);
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700652 return new File(stagingDir, "vmdl" + sessionId + ".tmp");
653 }
654
655 static void prepareStageDir(File stageDir) throws IOException {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700656 if (stageDir.exists()) {
657 throw new IOException("Session dir already exists: " + stageDir);
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700658 }
659
660 try {
Dario Frenid8bf22e2018-08-31 14:18:04 +0100661 Os.mkdir(stageDir.getAbsolutePath(), 0775);
662 Os.chmod(stageDir.getAbsolutePath(), 0775);
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700663 } catch (ErrnoException e) {
664 // This purposefully throws if directory already exists
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700665 throw new IOException("Failed to prepare session dir: " + stageDir, e);
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700666 }
667
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700668 if (!SELinux.restorecon(stageDir)) {
669 throw new IOException("Failed to restorecon session dir: " + stageDir);
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700670 }
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700671 }
672
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700673 private String buildExternalStageCid(int sessionId) {
674 return "smdl" + sessionId + ".tmp";
675 }
Jeff Sharkey742e7902014-08-16 19:09:13 -0700676
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700677 @Override
Jeff Sharkeya0907432014-08-15 10:23:11 -0700678 public SessionInfo getSessionInfo(int sessionId) {
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700679 synchronized (mSessions) {
680 final PackageInstallerSession session = mSessions.get(sessionId);
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700681 return session != null ? session.generateInfo() : null;
682 }
683 }
684
685 @Override
Jeff Sharkey97d47ed2014-10-15 09:19:47 -0700686 public ParceledListSlice<SessionInfo> getAllSessions(int userId) {
Todd Kennedy0eb97382017-10-03 16:57:22 -0700687 mPermissionManager.enforceCrossUserPermission(
688 Binder.getCallingUid(), userId, true, false, "getAllSessions");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700689
Jeff Sharkeya0907432014-08-15 10:23:11 -0700690 final List<SessionInfo> result = new ArrayList<>();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700691 synchronized (mSessions) {
692 for (int i = 0; i < mSessions.size(); i++) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700693 final PackageInstallerSession session = mSessions.valueAt(i);
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000694 if (session.userId == userId && !session.hasParentSessionId()) {
Jeff Sharkeyda1247a2017-06-08 14:13:29 -0600695 result.add(session.generateInfo(false));
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700696 }
697 }
698 }
Jeff Sharkey97d47ed2014-10-15 09:19:47 -0700699 return new ParceledListSlice<>(result);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700700 }
701
702 @Override
Jeff Sharkey97d47ed2014-10-15 09:19:47 -0700703 public ParceledListSlice<SessionInfo> getMySessions(String installerPackageName, int userId) {
Todd Kennedy0eb97382017-10-03 16:57:22 -0700704 mPermissionManager.enforceCrossUserPermission(
705 Binder.getCallingUid(), userId, true, false, "getMySessions");
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700706 mAppOps.checkPackage(Binder.getCallingUid(), installerPackageName);
707
Jeff Sharkeya0907432014-08-15 10:23:11 -0700708 final List<SessionInfo> result = new ArrayList<>();
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700709 synchronized (mSessions) {
710 for (int i = 0; i < mSessions.size(); i++) {
711 final PackageInstallerSession session = mSessions.valueAt(i);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000712
713 SessionInfo info = session.generateInfo(false);
714 if (Objects.equals(info.getInstallerPackageName(), installerPackageName)
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000715 && session.userId == userId && !session.hasParentSessionId()) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000716 result.add(info);
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700717 }
718 }
719 }
Jeff Sharkey97d47ed2014-10-15 09:19:47 -0700720 return new ParceledListSlice<>(result);
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700721 }
722
723 @Override
Svet Ganov67882122016-12-11 16:36:34 -0800724 public void uninstall(VersionedPackage versionedPackage, String callerPackageName, int flags,
725 IntentSender statusReceiver, int userId) throws RemoteException {
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000726 final int callingUid = Binder.getCallingUid();
Todd Kennedy0eb97382017-10-03 16:57:22 -0700727 mPermissionManager.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000728 if ((callingUid != Process.SHELL_UID) && (callingUid != Process.ROOT_UID)) {
729 mAppOps.checkPackage(callingUid, callerPackageName);
730 }
731
Benjamin Franzdabae882017-08-08 12:33:19 +0100732 // Check whether the caller is device owner or affiliated profile owner, in which case we do
733 // it silently.
734 final int callingUserId = UserHandle.getUserId(callingUid);
735 DevicePolicyManagerInternal dpmi =
736 LocalServices.getService(DevicePolicyManagerInternal.class);
737 final boolean isDeviceOwnerOrAffiliatedProfileOwner =
738 dpmi != null && dpmi.isActiveAdminWithPolicy(callingUid,
739 DeviceAdminInfo.USES_POLICY_PROFILE_OWNER)
740 && dpmi.isUserAffiliatedWithDevice(callingUserId);
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700741
Jeff Sharkeya0907432014-08-15 10:23:11 -0700742 final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext,
Benjamin Franzdabae882017-08-08 12:33:19 +0100743 statusReceiver, versionedPackage.getPackageName(),
744 isDeviceOwnerOrAffiliatedProfileOwner, userId);
Sudheer Shanka72de4dd2016-07-22 15:46:37 -0700745 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES)
746 == PackageManager.PERMISSION_GRANTED) {
Jeff Sharkeyf0600952014-08-07 17:31:53 -0700747 // Sweet, call straight through!
Svet Ganov67882122016-12-11 16:36:34 -0800748 mPm.deletePackageVersioned(versionedPackage, adapter.getBinder(), userId, flags);
Benjamin Franzdabae882017-08-08 12:33:19 +0100749 } else if (isDeviceOwnerOrAffiliatedProfileOwner) {
750 // Allow the device owner and affiliated profile owner to silently delete packages
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000751 // Need to clear the calling identity to get DELETE_PACKAGES permission
752 long ident = Binder.clearCallingIdentity();
753 try {
Svet Ganov67882122016-12-11 16:36:34 -0800754 mPm.deletePackageVersioned(versionedPackage, adapter.getBinder(), userId, flags);
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000755 } finally {
756 Binder.restoreCallingIdentity(ident);
757 }
Jeff Sharkeyf0600952014-08-07 17:31:53 -0700758 } else {
Philip P. Moltmannd9bb39a2017-09-05 12:41:15 -0700759 ApplicationInfo appInfo = mPm.getApplicationInfo(callerPackageName, 0, userId);
760 if (appInfo.targetSdkVersion >= Build.VERSION_CODES.P) {
761 mContext.enforceCallingOrSelfPermission(Manifest.permission.REQUEST_DELETE_PACKAGES,
762 null);
763 }
764
Jeff Sharkeyf0600952014-08-07 17:31:53 -0700765 // Take a short detour to confirm with user
766 final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
Svet Ganov67882122016-12-11 16:36:34 -0800767 intent.setData(Uri.fromParts("package", versionedPackage.getPackageName(), null));
Jeff Sharkeya0907432014-08-15 10:23:11 -0700768 intent.putExtra(PackageInstaller.EXTRA_CALLBACK, adapter.getBinder().asBinder());
769 adapter.onUserActionRequired(intent);
Jeff Sharkeyf0600952014-08-07 17:31:53 -0700770 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700771 }
772
773 @Override
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700774 public void setPermissionsResult(int sessionId, boolean accepted) {
775 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, TAG);
776
777 synchronized (mSessions) {
Svet Ganov3baa8762016-04-08 09:22:54 -0700778 PackageInstallerSession session = mSessions.get(sessionId);
779 if (session != null) {
780 session.setPermissionsResult(accepted);
781 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700782 }
783 }
784
785 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700786 public void registerCallback(IPackageInstallerCallback callback, int userId) {
Todd Kennedy0eb97382017-10-03 16:57:22 -0700787 mPermissionManager.enforceCrossUserPermission(
788 Binder.getCallingUid(), userId, true, false, "registerCallback");
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700789 mCallbacks.register(callback, userId);
Jeff Sharkeybb580672014-07-10 12:10:25 -0700790 }
791
792 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700793 public void unregisterCallback(IPackageInstallerCallback callback) {
794 mCallbacks.unregister(callback);
Jeff Sharkeya1031142014-07-12 18:09:46 -0700795 }
796
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000797 @Override
798 public PackageInstallerSession getSession(int sessionId) {
799 synchronized (mSessions) {
800 return mSessions.get(sessionId);
801 }
802 }
803
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700804 private static int getSessionCount(SparseArray<PackageInstallerSession> sessions,
805 int installerUid) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700806 int count = 0;
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700807 final int size = sessions.size();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700808 for (int i = 0; i < size; i++) {
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700809 final PackageInstallerSession session = sessions.valueAt(i);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000810 if (session.getInstallerUid() == installerUid) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700811 count++;
812 }
813 }
814 return count;
815 }
816
817 private boolean isCallingUidOwner(PackageInstallerSession session) {
818 final int callingUid = Binder.getCallingUid();
819 if (callingUid == Process.ROOT_UID) {
820 return true;
821 } else {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000822 return (session != null) && (callingUid == session.getInstallerUid());
Jeff Sharkeya1031142014-07-12 18:09:46 -0700823 }
824 }
825
Jeff Sharkeya0907432014-08-15 10:23:11 -0700826 static class PackageDeleteObserverAdapter extends PackageDeleteObserver {
827 private final Context mContext;
828 private final IntentSender mTarget;
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700829 private final String mPackageName;
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000830 private final Notification mNotification;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700831
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700832 public PackageDeleteObserverAdapter(Context context, IntentSender target,
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000833 String packageName, boolean showNotification, int userId) {
Jeff Sharkeya0907432014-08-15 10:23:11 -0700834 mContext = context;
835 mTarget = target;
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700836 mPackageName = packageName;
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000837 if (showNotification) {
838 mNotification = buildSuccessNotification(mContext,
839 mContext.getResources().getString(R.string.package_deleted_device_owner),
840 packageName,
841 userId);
842 } else {
843 mNotification = null;
844 }
Jeff Sharkeya0907432014-08-15 10:23:11 -0700845 }
846
847 @Override
848 public void onUserActionRequired(Intent intent) {
849 final Intent fillIn = new Intent();
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700850 fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName);
Jeff Sharkeya0907432014-08-15 10:23:11 -0700851 fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
Jeff Sharkey742e7902014-08-16 19:09:13 -0700852 PackageInstaller.STATUS_PENDING_USER_ACTION);
Jeff Sharkeya0907432014-08-15 10:23:11 -0700853 fillIn.putExtra(Intent.EXTRA_INTENT, intent);
854 try {
855 mTarget.sendIntent(mContext, 0, fillIn, null, null);
856 } catch (SendIntentException ignored) {
857 }
858 }
859
860 @Override
861 public void onPackageDeleted(String basePackageName, int returnCode, String msg) {
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000862 if (PackageManager.DELETE_SUCCEEDED == returnCode && mNotification != null) {
863 NotificationManager notificationManager = (NotificationManager)
864 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
Chris Wren282cfef2017-03-27 15:01:44 -0400865 notificationManager.notify(basePackageName,
866 SystemMessage.NOTE_PACKAGE_STATE,
867 mNotification);
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000868 }
Jeff Sharkeya0907432014-08-15 10:23:11 -0700869 final Intent fillIn = new Intent();
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700870 fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName);
Jeff Sharkeya0907432014-08-15 10:23:11 -0700871 fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
872 PackageManager.deleteStatusToPublicStatus(returnCode));
873 fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
874 PackageManager.deleteStatusToString(returnCode, msg));
875 fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode);
876 try {
877 mTarget.sendIntent(mContext, 0, fillIn, null, null);
878 } catch (SendIntentException ignored) {
879 }
880 }
881 }
882
883 static class PackageInstallObserverAdapter extends PackageInstallObserver {
884 private final Context mContext;
885 private final IntentSender mTarget;
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700886 private final int mSessionId;
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000887 private final boolean mShowNotification;
888 private final int mUserId;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700889
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000890 public PackageInstallObserverAdapter(Context context, IntentSender target, int sessionId,
891 boolean showNotification, int userId) {
Jeff Sharkeya0907432014-08-15 10:23:11 -0700892 mContext = context;
893 mTarget = target;
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700894 mSessionId = sessionId;
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000895 mShowNotification = showNotification;
896 mUserId = userId;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700897 }
898
899 @Override
900 public void onUserActionRequired(Intent intent) {
901 final Intent fillIn = new Intent();
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700902 fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId);
Jeff Sharkeya0907432014-08-15 10:23:11 -0700903 fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
Jeff Sharkey742e7902014-08-16 19:09:13 -0700904 PackageInstaller.STATUS_PENDING_USER_ACTION);
Jeff Sharkeya0907432014-08-15 10:23:11 -0700905 fillIn.putExtra(Intent.EXTRA_INTENT, intent);
906 try {
907 mTarget.sendIntent(mContext, 0, fillIn, null, null);
908 } catch (SendIntentException ignored) {
909 }
910 }
911
912 @Override
913 public void onPackageInstalled(String basePackageName, int returnCode, String msg,
914 Bundle extras) {
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000915 if (PackageManager.INSTALL_SUCCEEDED == returnCode && mShowNotification) {
Benjamin Franz2e3e9432015-04-17 15:28:17 +0100916 boolean update = (extras != null) && extras.getBoolean(Intent.EXTRA_REPLACING);
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000917 Notification notification = buildSuccessNotification(mContext,
Benjamin Franz2e3e9432015-04-17 15:28:17 +0100918 mContext.getResources()
919 .getString(update ? R.string.package_updated_device_owner :
920 R.string.package_installed_device_owner),
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000921 basePackageName,
922 mUserId);
923 if (notification != null) {
924 NotificationManager notificationManager = (NotificationManager)
925 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
Chris Wren282cfef2017-03-27 15:01:44 -0400926 notificationManager.notify(basePackageName,
927 SystemMessage.NOTE_PACKAGE_STATE,
928 notification);
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000929 }
930 }
Jeff Sharkeya0907432014-08-15 10:23:11 -0700931 final Intent fillIn = new Intent();
Benjamin Franz2e3e9432015-04-17 15:28:17 +0100932 fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, basePackageName);
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700933 fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId);
Jeff Sharkeya0907432014-08-15 10:23:11 -0700934 fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
935 PackageManager.installStatusToPublicStatus(returnCode));
936 fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
937 PackageManager.installStatusToString(returnCode, msg));
938 fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode);
939 if (extras != null) {
940 final String existing = extras.getString(
941 PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE);
942 if (!TextUtils.isEmpty(existing)) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700943 fillIn.putExtra(PackageInstaller.EXTRA_OTHER_PACKAGE_NAME, existing);
Jeff Sharkeya0907432014-08-15 10:23:11 -0700944 }
945 }
946 try {
947 mTarget.sendIntent(mContext, 0, fillIn, null, null);
948 } catch (SendIntentException ignored) {
949 }
950 }
951 }
952
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000953 /**
954 * Build a notification for package installation / deletion by device owners that is shown if
955 * the operation succeeds.
956 */
957 private static Notification buildSuccessNotification(Context context, String contentText,
958 String basePackageName, int userId) {
959 PackageInfo packageInfo = null;
960 try {
961 packageInfo = AppGlobals.getPackageManager().getPackageInfo(
Svet Ganova5c867c2017-05-15 01:17:05 -0700962 basePackageName, PackageManager.MATCH_STATIC_SHARED_LIBRARIES, userId);
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000963 } catch (RemoteException ignored) {
964 }
965 if (packageInfo == null || packageInfo.applicationInfo == null) {
966 Slog.w(TAG, "Notification not built for package: " + basePackageName);
967 return null;
968 }
969 PackageManager pm = context.getPackageManager();
970 Bitmap packageIcon = ImageUtils.buildScaledBitmap(
971 packageInfo.applicationInfo.loadIcon(pm),
972 context.getResources().getDimensionPixelSize(
973 android.R.dimen.notification_large_icon_width),
974 context.getResources().getDimensionPixelSize(
975 android.R.dimen.notification_large_icon_height));
976 CharSequence packageLabel = packageInfo.applicationInfo.loadLabel(pm);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -0500977 return new Notification.Builder(context, SystemNotificationChannels.DEVICE_ADMIN)
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000978 .setSmallIcon(R.drawable.ic_check_circle_24px)
979 .setColor(context.getResources().getColor(
980 R.color.system_notification_accent_color))
981 .setContentTitle(packageLabel)
982 .setContentText(contentText)
Benjamin Franz2e3e9432015-04-17 15:28:17 +0100983 .setStyle(new Notification.BigTextStyle().bigText(contentText))
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000984 .setLargeIcon(packageIcon)
985 .build();
986 }
987
Jeff Sharkey54d42be2015-07-20 16:36:55 -0700988 public static <E> ArraySet<E> newArraySet(E... elements) {
989 final ArraySet<E> set = new ArraySet<E>();
990 if (elements != null) {
991 set.ensureCapacity(elements.length);
992 Collections.addAll(set, elements);
993 }
994 return set;
995 }
996
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700997 private static class Callbacks extends Handler {
998 private static final int MSG_SESSION_CREATED = 1;
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700999 private static final int MSG_SESSION_BADGING_CHANGED = 2;
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001000 private static final int MSG_SESSION_ACTIVE_CHANGED = 3;
Jeff Sharkeyec9bad22014-09-05 09:45:20 -07001001 private static final int MSG_SESSION_PROGRESS_CHANGED = 4;
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001002 private static final int MSG_SESSION_FINISHED = 5;
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07001003
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001004 private final RemoteCallbackList<IPackageInstallerCallback>
1005 mCallbacks = new RemoteCallbackList<>();
Jeff Sharkeya1031142014-07-12 18:09:46 -07001006
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001007 public Callbacks(Looper looper) {
1008 super(looper);
1009 }
1010
1011 public void register(IPackageInstallerCallback callback, int userId) {
1012 mCallbacks.register(callback, new UserHandle(userId));
1013 }
1014
1015 public void unregister(IPackageInstallerCallback callback) {
1016 mCallbacks.unregister(callback);
1017 }
1018
1019 @Override
1020 public void handleMessage(Message msg) {
1021 final int userId = msg.arg2;
1022 final int n = mCallbacks.beginBroadcast();
1023 for (int i = 0; i < n; i++) {
1024 final IPackageInstallerCallback callback = mCallbacks.getBroadcastItem(i);
1025 final UserHandle user = (UserHandle) mCallbacks.getBroadcastCookie(i);
1026 // TODO: dispatch notifications for slave profiles
1027 if (userId == user.getIdentifier()) {
1028 try {
1029 invokeCallback(callback, msg);
1030 } catch (RemoteException ignored) {
1031 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07001032 }
1033 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001034 mCallbacks.finishBroadcast();
Jeff Sharkeya1031142014-07-12 18:09:46 -07001035 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001036
1037 private void invokeCallback(IPackageInstallerCallback callback, Message msg)
1038 throws RemoteException {
1039 final int sessionId = msg.arg1;
1040 switch (msg.what) {
1041 case MSG_SESSION_CREATED:
1042 callback.onSessionCreated(sessionId);
1043 break;
Jeff Sharkeyec9bad22014-09-05 09:45:20 -07001044 case MSG_SESSION_BADGING_CHANGED:
1045 callback.onSessionBadgingChanged(sessionId);
1046 break;
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001047 case MSG_SESSION_ACTIVE_CHANGED:
1048 callback.onSessionActiveChanged(sessionId, (boolean) msg.obj);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001049 break;
1050 case MSG_SESSION_PROGRESS_CHANGED:
1051 callback.onSessionProgressChanged(sessionId, (float) msg.obj);
1052 break;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001053 case MSG_SESSION_FINISHED:
1054 callback.onSessionFinished(sessionId, (boolean) msg.obj);
1055 break;
1056 }
1057 }
1058
1059 private void notifySessionCreated(int sessionId, int userId) {
1060 obtainMessage(MSG_SESSION_CREATED, sessionId, userId).sendToTarget();
1061 }
1062
Jeff Sharkeyec9bad22014-09-05 09:45:20 -07001063 private void notifySessionBadgingChanged(int sessionId, int userId) {
1064 obtainMessage(MSG_SESSION_BADGING_CHANGED, sessionId, userId).sendToTarget();
1065 }
1066
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001067 private void notifySessionActiveChanged(int sessionId, int userId, boolean active) {
1068 obtainMessage(MSG_SESSION_ACTIVE_CHANGED, sessionId, userId, active).sendToTarget();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001069 }
1070
1071 private void notifySessionProgressChanged(int sessionId, int userId, float progress) {
1072 obtainMessage(MSG_SESSION_PROGRESS_CHANGED, sessionId, userId, progress).sendToTarget();
1073 }
1074
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001075 public void notifySessionFinished(int sessionId, int userId, boolean success) {
1076 obtainMessage(MSG_SESSION_FINISHED, sessionId, userId, success).sendToTarget();
1077 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07001078 }
1079
1080 void dump(IndentingPrintWriter pw) {
Jeff Sharkeya1031142014-07-12 18:09:46 -07001081 synchronized (mSessions) {
Jeff Sharkey9a445772014-07-16 11:32:08 -07001082 pw.println("Active install sessions:");
1083 pw.increaseIndent();
1084 int N = mSessions.size();
Jeff Sharkeya1031142014-07-12 18:09:46 -07001085 for (int i = 0; i < N; i++) {
1086 final PackageInstallerSession session = mSessions.valueAt(i);
1087 session.dump(pw);
1088 pw.println();
1089 }
Jeff Sharkey9a445772014-07-16 11:32:08 -07001090 pw.println();
1091 pw.decreaseIndent();
1092
1093 pw.println("Historical install sessions:");
1094 pw.increaseIndent();
1095 N = mHistoricalSessions.size();
1096 for (int i = 0; i < N; i++) {
Narayan Kamatha22a7662017-06-12 13:34:29 +01001097 pw.print(mHistoricalSessions.get(i));
Jeff Sharkey9a445772014-07-16 11:32:08 -07001098 pw.println();
1099 }
1100 pw.println();
1101 pw.decreaseIndent();
Jeff Sharkey742e7902014-08-16 19:09:13 -07001102
1103 pw.println("Legacy install sessions:");
1104 pw.increaseIndent();
1105 pw.println(mLegacySessions.toString());
1106 pw.decreaseIndent();
Jeff Sharkeya1031142014-07-12 18:09:46 -07001107 }
Jeff Sharkeybb580672014-07-10 12:10:25 -07001108 }
1109
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001110 class InternalCallback {
Jeff Sharkeyec9bad22014-09-05 09:45:20 -07001111 public void onSessionBadgingChanged(PackageInstallerSession session) {
1112 mCallbacks.notifySessionBadgingChanged(session.sessionId, session.userId);
1113 writeSessionsAsync();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001114 }
1115
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001116 public void onSessionActiveChanged(PackageInstallerSession session, boolean active) {
1117 mCallbacks.notifySessionActiveChanged(session.sessionId, session.userId, active);
Jeff Sharkey742e7902014-08-16 19:09:13 -07001118 }
1119
Jeff Sharkeyec9bad22014-09-05 09:45:20 -07001120 public void onSessionProgressChanged(PackageInstallerSession session, float progress) {
1121 mCallbacks.notifySessionProgressChanged(session.sessionId, session.userId, progress);
1122 }
1123
Jeff Sharkeycbf47912014-09-12 09:55:32 -07001124 public void onSessionFinished(final PackageInstallerSession session, boolean success) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001125 mCallbacks.notifySessionFinished(session.sessionId, session.userId, success);
Jeff Sharkeycbf47912014-09-12 09:55:32 -07001126
1127 mInstallHandler.post(new Runnable() {
1128 @Override
1129 public void run() {
1130 synchronized (mSessions) {
1131 mSessions.remove(session.sessionId);
Narayan Kamatha22a7662017-06-12 13:34:29 +01001132 addHistoricalSessionLocked(session);
Jeff Sharkey02bd7842014-10-06 15:14:27 -07001133
1134 final File appIconFile = buildAppIconFile(session.sessionId);
1135 if (appIconFile.exists()) {
1136 appIconFile.delete();
1137 }
1138
Jeff Sharkeycbf47912014-09-12 09:55:32 -07001139 writeSessionsLocked();
1140 }
1141 }
1142 });
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001143 }
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -07001144
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001145 public void onSessionPrepared(PackageInstallerSession session) {
1146 // We prepared the destination to write into; we want to persist
1147 // this, but it's not critical enough to block for.
1148 writeSessionsAsync();
1149 }
1150
Jeff Sharkeycbf47912014-09-12 09:55:32 -07001151 public void onSessionSealedBlocking(PackageInstallerSession session) {
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -07001152 // It's very important that we block until we've recorded the
1153 // session as being sealed, since we never want to allow mutation
1154 // after sealing.
Jeff Sharkeycbf47912014-09-12 09:55:32 -07001155 synchronized (mSessions) {
1156 writeSessionsLocked();
1157 }
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -07001158 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001159 }
1160}