blob: 14128a78fbacf203e8a3bc0bef1865d84bc6f310 [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
110public class PackageInstallerService extends IPackageInstaller.Stub {
111 private static final String TAG = "PackageInstaller";
Jeff Sharkeye9808042014-09-11 21:15:37 -0700112 private static final boolean LOGD = false;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700113
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700114 // TODO: remove outstanding sessions when installer package goes away
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700115 // TODO: notify listeners in other users when package has been installed there
Jeff Sharkey742e7902014-08-16 19:09:13 -0700116 // TODO: purge expired sessions periodically in addition to at reboot
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700117
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700118 /** XML constants used in {@link #mSessionsFile} */
119 private static final String TAG_SESSIONS = "sessions";
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700120
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700121 /** Automatically destroy sessions older than this */
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700122 private static final long MAX_AGE_MILLIS = 3 * DateUtils.DAY_IN_MILLIS;
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700123 /** Upper bound on number of active sessions for a UID */
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700124 private static final long MAX_ACTIVE_SESSIONS = 1024;
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700125 /** Upper bound on number of historical sessions for a UID */
126 private static final long MAX_HISTORICAL_SESSIONS = 1048576;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700127
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700128 private final Context mContext;
129 private final PackageManagerService mPm;
Todd Kennedy0eb97382017-10-03 16:57:22 -0700130 private final PermissionManagerInternal mPermissionManager;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700131
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700132 private AppOpsManager mAppOps;
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700133
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700134 private final HandlerThread mInstallThread;
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700135 private final Handler mInstallHandler;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700136
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700137 private final Callbacks mCallbacks;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700138
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700139 /**
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700140 * File storing persisted {@link #mSessions} metadata.
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700141 */
142 private final AtomicFile mSessionsFile;
143
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700144 /**
145 * Directory storing persisted {@link #mSessions} metadata which is too
146 * heavy to store directly in {@link #mSessionsFile}.
147 */
148 private final File mSessionsDir;
149
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700150 private final InternalCallback mInternalCallback = new InternalCallback();
151
152 /**
153 * Used for generating session IDs. Since this is created at boot time,
154 * normal random might be predictable.
155 */
156 private final Random mRandom = new SecureRandom();
157
Todd Kennedy28c4e802016-07-13 13:20:30 -0700158 /** All sessions allocated */
159 @GuardedBy("mSessions")
160 private final SparseBooleanArray mAllocatedSessions = new SparseBooleanArray();
161
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700162 @GuardedBy("mSessions")
163 private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>();
164
Jeff Sharkey9a445772014-07-16 11:32:08 -0700165 /** Historical sessions kept around for debugging purposes */
166 @GuardedBy("mSessions")
Narayan Kamatha22a7662017-06-12 13:34:29 +0100167 private final List<String> mHistoricalSessions = new ArrayList<>();
168
169 @GuardedBy("mSessions")
170 private final SparseIntArray mHistoricalSessionsByInstaller = new SparseIntArray();
Jeff Sharkey9a445772014-07-16 11:32:08 -0700171
Jeff Sharkey742e7902014-08-16 19:09:13 -0700172 /** Sessions allocated to legacy users */
173 @GuardedBy("mSessions")
174 private final SparseBooleanArray mLegacySessions = new SparseBooleanArray();
175
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700176 private static final FilenameFilter sStageFilter = new FilenameFilter() {
177 @Override
178 public boolean accept(File dir, String name) {
Jeff Sharkey742e7902014-08-16 19:09:13 -0700179 return isStageName(name);
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700180 }
181 };
182
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700183 public PackageInstallerService(Context context, PackageManagerService pm) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700184 mContext = context;
185 mPm = pm;
Todd Kennedy0eb97382017-10-03 16:57:22 -0700186 mPermissionManager = LocalServices.getService(PermissionManagerInternal.class);
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700187
188 mInstallThread = new HandlerThread(TAG);
189 mInstallThread.start();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700190
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700191 mInstallHandler = new Handler(mInstallThread.getLooper());
192
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700193 mCallbacks = new Callbacks(mInstallThread.getLooper());
194
195 mSessionsFile = new AtomicFile(
Jeff Sharkey8212ae02016-02-10 14:46:43 -0700196 new File(Environment.getDataSystemDirectory(), "install_sessions.xml"));
197 mSessionsDir = new File(Environment.getDataSystemDirectory(), "install_sessions");
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700198 mSessionsDir.mkdirs();
Tony Mak606f8e72017-02-15 18:40:03 +0000199 }
200
201 public void systemReady() {
202 mAppOps = mContext.getSystemService(AppOpsManager.class);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700203
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700204 synchronized (mSessions) {
205 readSessionsLocked();
206
Svetoslav Ganov096d3042017-01-30 16:34:13 -0800207 reconcileStagesLocked(StorageManager.UUID_PRIVATE_INTERNAL, false /*isInstant*/);
208 reconcileStagesLocked(StorageManager.UUID_PRIVATE_INTERNAL, true /*isInstant*/);
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700209
Jeff Sharkey54d42be2015-07-20 16:36:55 -0700210 final ArraySet<File> unclaimedIcons = newArraySet(
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700211 mSessionsDir.listFiles());
Jeff Sharkey742e7902014-08-16 19:09:13 -0700212
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700213 // Ignore stages and icons claimed by active sessions
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700214 for (int i = 0; i < mSessions.size(); i++) {
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700215 final PackageInstallerSession session = mSessions.valueAt(i);
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700216 unclaimedIcons.remove(buildAppIconFile(session.sessionId));
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700217 }
Jeff Sharkey742e7902014-08-16 19:09:13 -0700218
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700219 // Clean up orphaned icons
220 for (File icon : unclaimedIcons) {
221 Slog.w(TAG, "Deleting orphan icon " + icon);
222 icon.delete();
223 }
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700224 }
225 }
226
Todd Kennedy2699f062015-11-20 13:07:17 -0800227 private void reconcileStagesLocked(String volumeUuid, boolean isEphemeral) {
228 final File stagingDir = buildStagingDir(volumeUuid, isEphemeral);
Jeff Sharkey54d42be2015-07-20 16:36:55 -0700229 final ArraySet<File> unclaimedStages = newArraySet(
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700230 stagingDir.listFiles(sStageFilter));
231
232 // Ignore stages claimed by active sessions
233 for (int i = 0; i < mSessions.size(); i++) {
234 final PackageInstallerSession session = mSessions.valueAt(i);
235 unclaimedStages.remove(session.stageDir);
236 }
237
238 // Clean up orphaned staging directories
239 for (File stage : unclaimedStages) {
240 Slog.w(TAG, "Deleting orphan stage " + stage);
241 synchronized (mPm.mInstallLock) {
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -0700242 mPm.removeCodePathLI(stage);
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700243 }
244 }
245 }
246
247 public void onPrivateVolumeMounted(String volumeUuid) {
248 synchronized (mSessions) {
Svetoslav Ganov096d3042017-01-30 16:34:13 -0800249 reconcileStagesLocked(volumeUuid, false /*isInstant*/);
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700250 }
251 }
252
Jeff Sharkey742e7902014-08-16 19:09:13 -0700253 public static boolean isStageName(String name) {
254 final boolean isFile = name.startsWith("vmdl") && name.endsWith(".tmp");
255 final boolean isContainer = name.startsWith("smdl") && name.endsWith(".tmp");
256 final boolean isLegacyContainer = name.startsWith("smdl2tmp");
257 return isFile || isContainer || isLegacyContainer;
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700258 }
259
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700260 @Deprecated
Todd Kennedy2699f062015-11-20 13:07:17 -0800261 public File allocateStageDirLegacy(String volumeUuid, boolean isEphemeral) throws IOException {
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700262 synchronized (mSessions) {
263 try {
264 final int sessionId = allocateSessionIdLocked();
Jeff Sharkey742e7902014-08-16 19:09:13 -0700265 mLegacySessions.put(sessionId, true);
Todd Kennedy2699f062015-11-20 13:07:17 -0800266 final File stageDir = buildStageDir(volumeUuid, sessionId, isEphemeral);
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700267 prepareStageDir(stageDir);
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700268 return stageDir;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700269 } catch (IllegalStateException e) {
270 throw new IOException(e);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700271 }
272 }
273 }
274
Jeff Sharkey742e7902014-08-16 19:09:13 -0700275 @Deprecated
276 public String allocateExternalStageCidLegacy() {
277 synchronized (mSessions) {
278 final int sessionId = allocateSessionIdLocked();
279 mLegacySessions.put(sessionId, true);
280 return "smdl" + sessionId + ".tmp";
281 }
282 }
283
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700284 private void readSessionsLocked() {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700285 if (LOGD) Slog.v(TAG, "readSessionsLocked()");
286
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700287 mSessions.clear();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700288
289 FileInputStream fis = null;
290 try {
291 fis = mSessionsFile.openRead();
292 final XmlPullParser in = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +0100293 in.setInput(fis, StandardCharsets.UTF_8.name());
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700294
295 int type;
296 while ((type = in.next()) != END_DOCUMENT) {
297 if (type == START_TAG) {
298 final String tag = in.getName();
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000299 if (PackageInstallerSession.TAG_SESSION.equals(tag)) {
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -0700300 final PackageInstallerSession session;
301 try {
302 session = PackageInstallerSession.readFromXml(in, mInternalCallback,
303 mContext, mPm, mInstallThread.getLooper(), mSessionsDir);
304 } catch (Exception e) {
305 Slog.e(TAG, "Could not read session", e);
306 continue;
307 }
308
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700309 final long age = System.currentTimeMillis() - session.createdMillis;
310
311 final boolean valid;
312 if (age >= MAX_AGE_MILLIS) {
313 Slog.w(TAG, "Abandoning old session first created at "
314 + session.createdMillis);
315 valid = false;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700316 } else {
317 valid = true;
318 }
319
320 if (valid) {
321 mSessions.put(session.sessionId, session);
322 } else {
323 // Since this is early during boot we don't send
324 // any observer events about the session, but we
325 // keep details around for dumpsys.
Narayan Kamatha22a7662017-06-12 13:34:29 +0100326 addHistoricalSessionLocked(session);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700327 }
Todd Kennedy28c4e802016-07-13 13:20:30 -0700328 mAllocatedSessions.put(session.sessionId, true);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700329 }
330 }
331 }
332 } catch (FileNotFoundException e) {
333 // Missing sessions are okay, probably first boot
Svet Ganov7121e182015-07-13 22:38:12 -0700334 } catch (IOException | XmlPullParserException e) {
Dianne Hackborn8d051722014-10-01 14:59:58 -0700335 Slog.wtf(TAG, "Failed reading install sessions", e);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700336 } finally {
337 IoUtils.closeQuietly(fis);
338 }
339 }
340
Narayan Kamatha22a7662017-06-12 13:34:29 +0100341 private void addHistoricalSessionLocked(PackageInstallerSession session) {
342 CharArrayWriter writer = new CharArrayWriter();
343 IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
344 session.dump(pw);
345 mHistoricalSessions.add(writer.toString());
346
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000347 int installerUid = session.getInstallerUid();
Narayan Kamatha22a7662017-06-12 13:34:29 +0100348 // Increment the number of sessions by this installerUid.
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000349 mHistoricalSessionsByInstaller.put(installerUid,
350 mHistoricalSessionsByInstaller.get(installerUid) + 1);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700351 }
352
353 private void writeSessionsLocked() {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700354 if (LOGD) Slog.v(TAG, "writeSessionsLocked()");
355
356 FileOutputStream fos = null;
357 try {
358 fos = mSessionsFile.startWrite();
359
360 XmlSerializer out = new FastXmlSerializer();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +0100361 out.setOutput(fos, StandardCharsets.UTF_8.name());
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700362 out.startDocument(null, true);
363 out.startTag(null, TAG_SESSIONS);
364 final int size = mSessions.size();
365 for (int i = 0; i < size; i++) {
366 final PackageInstallerSession session = mSessions.valueAt(i);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000367 session.write(out, mSessionsDir);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700368 }
369 out.endTag(null, TAG_SESSIONS);
370 out.endDocument();
371
372 mSessionsFile.finishWrite(fos);
373 } catch (IOException e) {
374 if (fos != null) {
375 mSessionsFile.failWrite(fos);
376 }
377 }
378 }
379
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700380 private File buildAppIconFile(int sessionId) {
381 return new File(mSessionsDir, "app_icon." + sessionId + ".png");
382 }
383
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700384 private void writeSessionsAsync() {
385 IoThread.getHandler().post(new Runnable() {
386 @Override
387 public void run() {
388 synchronized (mSessions) {
389 writeSessionsLocked();
390 }
391 }
392 });
393 }
394
395 @Override
Jeff Sharkeya0907432014-08-15 10:23:11 -0700396 public int createSession(SessionParams params, String installerPackageName, int userId) {
Jeff Sharkey742e7902014-08-16 19:09:13 -0700397 try {
398 return createSessionInternal(params, installerPackageName, userId);
399 } catch (IOException e) {
400 throw ExceptionUtils.wrap(e);
401 }
402 }
403
404 private int createSessionInternal(SessionParams params, String installerPackageName, int userId)
405 throws IOException {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700406 final int callingUid = Binder.getCallingUid();
Todd Kennedy0eb97382017-10-03 16:57:22 -0700407 mPermissionManager.enforceCrossUserPermission(
408 callingUid, userId, true, true, "createSession");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700409
Jeff Sharkeye9808042014-09-11 21:15:37 -0700410 if (mPm.isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700411 throw new SecurityException("User restriction prevents installing");
412 }
413
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700414 if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {
Jeff Sharkeye9808042014-09-11 21:15:37 -0700415 params.installFlags |= PackageManager.INSTALL_FROM_ADB;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700416
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700417 } else {
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700418 mAppOps.checkPackage(callingUid, installerPackageName);
419
Jeff Sharkeye9808042014-09-11 21:15:37 -0700420 params.installFlags &= ~PackageManager.INSTALL_FROM_ADB;
421 params.installFlags &= ~PackageManager.INSTALL_ALL_USERS;
422 params.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
Todd Kennedy78a72502017-07-19 12:49:30 -0700423 if ((params.installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0
424 && !mPm.isCallerVerifier(callingUid)) {
425 params.installFlags &= ~PackageManager.INSTALL_VIRTUAL_PRELOAD;
426 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700427 }
428
Svetoslav805b63e2015-04-09 17:28:54 -0700429 // Only system components can circumvent runtime permissions when installing.
430 if ((params.installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0
431 && mContext.checkCallingOrSelfPermission(Manifest.permission
432 .INSTALL_GRANT_RUNTIME_PERMISSIONS) == PackageManager.PERMISSION_DENIED) {
433 throw new SecurityException("You need the "
434 + "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS permission "
435 + "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag");
436 }
437
Jeff Sharkey8c61e392017-02-24 09:22:48 -0700438 if ((params.installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0
439 || (params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
440 throw new IllegalArgumentException(
441 "New installs into ASEC containers no longer supported");
442 }
443
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700444 // Defensively resize giant app icons
445 if (params.appIcon != null) {
446 final ActivityManager am = (ActivityManager) mContext.getSystemService(
447 Context.ACTIVITY_SERVICE);
448 final int iconSize = am.getLauncherLargeIconSize();
449 if ((params.appIcon.getWidth() > iconSize * 2)
450 || (params.appIcon.getHeight() > iconSize * 2)) {
451 params.appIcon = Bitmap.createScaledBitmap(params.appIcon, iconSize, iconSize,
452 true);
453 }
454 }
455
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700456 switch (params.mode) {
457 case SessionParams.MODE_FULL_INSTALL:
458 case SessionParams.MODE_INHERIT_EXISTING:
459 break;
460 default:
461 throw new IllegalArgumentException("Invalid install mode: " + params.mode);
462 }
463
464 // If caller requested explicit location, sanity check it, otherwise
465 // resolve the best internal or adopted location.
466 if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
Jeff Sharkey683bcd32017-03-18 17:54:51 -0600467 if (!PackageHelper.fitsOnInternal(mContext, params)) {
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700468 throw new IOException("No suitable internal storage available");
469 }
470
471 } else if ((params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
Jeff Sharkey683bcd32017-03-18 17:54:51 -0600472 if (!PackageHelper.fitsOnExternal(mContext, params)) {
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700473 throw new IOException("No suitable external storage available");
474 }
475
Jeff Sharkeyab234092015-06-09 21:42:22 -0700476 } else if ((params.installFlags & PackageManager.INSTALL_FORCE_VOLUME_UUID) != 0) {
477 // For now, installs to adopted media are treated as internal from
478 // an install flag point-of-view.
479 params.setInstallFlagsInternal();
480
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700481 } else {
482 // For now, installs to adopted media are treated as internal from
483 // an install flag point-of-view.
484 params.setInstallFlagsInternal();
485
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700486 // Resolve best location for install, based on combination of
487 // requested install flags, delta size, and manifest settings.
Robin Leee812d902014-08-21 16:51:18 +0100488 final long ident = Binder.clearCallingIdentity();
489 try {
Jeff Sharkey683bcd32017-03-18 17:54:51 -0600490 params.volumeUuid = PackageHelper.resolveInstallVolume(mContext, params);
Robin Leee812d902014-08-21 16:51:18 +0100491 } finally {
492 Binder.restoreCallingIdentity(ident);
493 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700494 }
495
496 final int sessionId;
497 final PackageInstallerSession session;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700498 synchronized (mSessions) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700499 // Sanity check that installer isn't going crazy
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700500 final int activeCount = getSessionCount(mSessions, callingUid);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700501 if (activeCount >= MAX_ACTIVE_SESSIONS) {
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700502 throw new IllegalStateException(
503 "Too many active sessions for UID " + callingUid);
504 }
Narayan Kamatha22a7662017-06-12 13:34:29 +0100505 final int historicalCount = mHistoricalSessionsByInstaller.get(callingUid);
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700506 if (historicalCount >= MAX_HISTORICAL_SESSIONS) {
507 throw new IllegalStateException(
508 "Too many historical sessions for UID " + callingUid);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700509 }
510
Jeff Sharkeya1031142014-07-12 18:09:46 -0700511 sessionId = allocateSessionIdLocked();
Todd Kennedy04918fe2016-07-12 14:07:40 -0700512 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700513
Todd Kennedy04918fe2016-07-12 14:07:40 -0700514 final long createdMillis = System.currentTimeMillis();
515 // We're staging to exactly one location
516 File stageDir = null;
517 String stageCid = null;
518 if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
Todd Kennedybe0b8892017-02-15 14:13:52 -0800519 final boolean isInstant =
520 (params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
521 stageDir = buildStageDir(params.volumeUuid, sessionId, isInstant);
Todd Kennedy04918fe2016-07-12 14:07:40 -0700522 } else {
523 stageCid = buildExternalStageCid(sessionId);
524 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700525
Todd Kennedy04918fe2016-07-12 14:07:40 -0700526 session = new PackageInstallerSession(mInternalCallback, mContext, mPm,
527 mInstallThread.getLooper(), sessionId, userId, installerPackageName, callingUid,
528 params, createdMillis, stageDir, stageCid, false, false);
529
530 synchronized (mSessions) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700531 mSessions.put(sessionId, session);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700532 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700533
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700534 mCallbacks.notifySessionCreated(session.sessionId, session.userId);
Jeff Sharkeya1031142014-07-12 18:09:46 -0700535 writeSessionsAsync();
536 return sessionId;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700537 }
538
Jeff Sharkey381d94b2014-08-24 14:45:56 -0700539 @Override
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700540 public void updateSessionAppIcon(int sessionId, Bitmap appIcon) {
541 synchronized (mSessions) {
542 final PackageInstallerSession session = mSessions.get(sessionId);
543 if (session == null || !isCallingUidOwner(session)) {
544 throw new SecurityException("Caller has no access to session " + sessionId);
545 }
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700546
547 // Defensively resize giant app icons
548 if (appIcon != null) {
549 final ActivityManager am = (ActivityManager) mContext.getSystemService(
550 Context.ACTIVITY_SERVICE);
551 final int iconSize = am.getLauncherLargeIconSize();
552 if ((appIcon.getWidth() > iconSize * 2)
553 || (appIcon.getHeight() > iconSize * 2)) {
554 appIcon = Bitmap.createScaledBitmap(appIcon, iconSize, iconSize, true);
555 }
556 }
557
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700558 session.params.appIcon = appIcon;
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700559 session.params.appIconLastModified = -1;
560
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700561 mInternalCallback.onSessionBadgingChanged(session);
562 }
563 }
564
565 @Override
566 public void updateSessionAppLabel(int sessionId, String appLabel) {
567 synchronized (mSessions) {
568 final PackageInstallerSession session = mSessions.get(sessionId);
569 if (session == null || !isCallingUidOwner(session)) {
570 throw new SecurityException("Caller has no access to session " + sessionId);
571 }
572 session.params.appLabel = appLabel;
573 mInternalCallback.onSessionBadgingChanged(session);
574 }
575 }
576
577 @Override
Jeff Sharkey381d94b2014-08-24 14:45:56 -0700578 public void abandonSession(int sessionId) {
579 synchronized (mSessions) {
580 final PackageInstallerSession session = mSessions.get(sessionId);
581 if (session == null || !isCallingUidOwner(session)) {
582 throw new SecurityException("Caller has no access to session " + sessionId);
583 }
584 session.abandon();
585 }
586 }
587
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700588 @Override
589 public IPackageInstallerSession openSession(int sessionId) {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700590 try {
591 return openSessionInternal(sessionId);
592 } catch (IOException e) {
593 throw ExceptionUtils.wrap(e);
594 }
595 }
596
597 private IPackageInstallerSession openSessionInternal(int sessionId) throws IOException {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700598 synchronized (mSessions) {
599 final PackageInstallerSession session = mSessions.get(sessionId);
Jeff Sharkey381d94b2014-08-24 14:45:56 -0700600 if (session == null || !isCallingUidOwner(session)) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700601 throw new SecurityException("Caller has no access to session " + sessionId);
602 }
Jeff Sharkey742e7902014-08-16 19:09:13 -0700603 session.open();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700604 return session;
605 }
606 }
607
608 private int allocateSessionIdLocked() {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700609 int n = 0;
610 int sessionId;
611 do {
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700612 sessionId = mRandom.nextInt(Integer.MAX_VALUE - 1) + 1;
Todd Kennedy28c4e802016-07-13 13:20:30 -0700613 if (!mAllocatedSessions.get(sessionId, false)) {
614 mAllocatedSessions.put(sessionId, true);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700615 return sessionId;
616 }
617 } while (n++ < 32);
618
619 throw new IllegalStateException("Failed to allocate session ID");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700620 }
621
Todd Kennedy2699f062015-11-20 13:07:17 -0800622 private File buildStagingDir(String volumeUuid, boolean isEphemeral) {
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700623 return Environment.getDataAppDirectory(volumeUuid);
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700624 }
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700625
Todd Kennedy2699f062015-11-20 13:07:17 -0800626 private File buildStageDir(String volumeUuid, int sessionId, boolean isEphemeral) {
627 final File stagingDir = buildStagingDir(volumeUuid, isEphemeral);
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700628 return new File(stagingDir, "vmdl" + sessionId + ".tmp");
629 }
630
631 static void prepareStageDir(File stageDir) throws IOException {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700632 if (stageDir.exists()) {
633 throw new IOException("Session dir already exists: " + stageDir);
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700634 }
635
636 try {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700637 Os.mkdir(stageDir.getAbsolutePath(), 0755);
638 Os.chmod(stageDir.getAbsolutePath(), 0755);
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700639 } catch (ErrnoException e) {
640 // This purposefully throws if directory already exists
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700641 throw new IOException("Failed to prepare session dir: " + stageDir, e);
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700642 }
643
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700644 if (!SELinux.restorecon(stageDir)) {
645 throw new IOException("Failed to restorecon session dir: " + stageDir);
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700646 }
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700647 }
648
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700649 private String buildExternalStageCid(int sessionId) {
650 return "smdl" + sessionId + ".tmp";
651 }
Jeff Sharkey742e7902014-08-16 19:09:13 -0700652
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700653 @Override
Jeff Sharkeya0907432014-08-15 10:23:11 -0700654 public SessionInfo getSessionInfo(int sessionId) {
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700655 synchronized (mSessions) {
656 final PackageInstallerSession session = mSessions.get(sessionId);
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700657 return session != null ? session.generateInfo() : null;
658 }
659 }
660
661 @Override
Jeff Sharkey97d47ed2014-10-15 09:19:47 -0700662 public ParceledListSlice<SessionInfo> getAllSessions(int userId) {
Todd Kennedy0eb97382017-10-03 16:57:22 -0700663 mPermissionManager.enforceCrossUserPermission(
664 Binder.getCallingUid(), userId, true, false, "getAllSessions");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700665
Jeff Sharkeya0907432014-08-15 10:23:11 -0700666 final List<SessionInfo> result = new ArrayList<>();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700667 synchronized (mSessions) {
668 for (int i = 0; i < mSessions.size(); i++) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700669 final PackageInstallerSession session = mSessions.valueAt(i);
Jeff Sharkeybb580672014-07-10 12:10:25 -0700670 if (session.userId == userId) {
Jeff Sharkeyda1247a2017-06-08 14:13:29 -0600671 result.add(session.generateInfo(false));
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700672 }
673 }
674 }
Jeff Sharkey97d47ed2014-10-15 09:19:47 -0700675 return new ParceledListSlice<>(result);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700676 }
677
678 @Override
Jeff Sharkey97d47ed2014-10-15 09:19:47 -0700679 public ParceledListSlice<SessionInfo> getMySessions(String installerPackageName, int userId) {
Todd Kennedy0eb97382017-10-03 16:57:22 -0700680 mPermissionManager.enforceCrossUserPermission(
681 Binder.getCallingUid(), userId, true, false, "getMySessions");
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700682 mAppOps.checkPackage(Binder.getCallingUid(), installerPackageName);
683
Jeff Sharkeya0907432014-08-15 10:23:11 -0700684 final List<SessionInfo> result = new ArrayList<>();
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700685 synchronized (mSessions) {
686 for (int i = 0; i < mSessions.size(); i++) {
687 final PackageInstallerSession session = mSessions.valueAt(i);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000688
689 SessionInfo info = session.generateInfo(false);
690 if (Objects.equals(info.getInstallerPackageName(), installerPackageName)
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700691 && session.userId == userId) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000692 result.add(info);
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700693 }
694 }
695 }
Jeff Sharkey97d47ed2014-10-15 09:19:47 -0700696 return new ParceledListSlice<>(result);
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700697 }
698
699 @Override
Svet Ganov67882122016-12-11 16:36:34 -0800700 public void uninstall(VersionedPackage versionedPackage, String callerPackageName, int flags,
701 IntentSender statusReceiver, int userId) throws RemoteException {
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000702 final int callingUid = Binder.getCallingUid();
Todd Kennedy0eb97382017-10-03 16:57:22 -0700703 mPermissionManager.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000704 if ((callingUid != Process.SHELL_UID) && (callingUid != Process.ROOT_UID)) {
705 mAppOps.checkPackage(callingUid, callerPackageName);
706 }
707
Benjamin Franzdabae882017-08-08 12:33:19 +0100708 // Check whether the caller is device owner or affiliated profile owner, in which case we do
709 // it silently.
710 final int callingUserId = UserHandle.getUserId(callingUid);
711 DevicePolicyManagerInternal dpmi =
712 LocalServices.getService(DevicePolicyManagerInternal.class);
713 final boolean isDeviceOwnerOrAffiliatedProfileOwner =
714 dpmi != null && dpmi.isActiveAdminWithPolicy(callingUid,
715 DeviceAdminInfo.USES_POLICY_PROFILE_OWNER)
716 && dpmi.isUserAffiliatedWithDevice(callingUserId);
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700717
Jeff Sharkeya0907432014-08-15 10:23:11 -0700718 final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext,
Benjamin Franzdabae882017-08-08 12:33:19 +0100719 statusReceiver, versionedPackage.getPackageName(),
720 isDeviceOwnerOrAffiliatedProfileOwner, userId);
Sudheer Shanka72de4dd2016-07-22 15:46:37 -0700721 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES)
722 == PackageManager.PERMISSION_GRANTED) {
Jeff Sharkeyf0600952014-08-07 17:31:53 -0700723 // Sweet, call straight through!
Svet Ganov67882122016-12-11 16:36:34 -0800724 mPm.deletePackageVersioned(versionedPackage, adapter.getBinder(), userId, flags);
Benjamin Franzdabae882017-08-08 12:33:19 +0100725 } else if (isDeviceOwnerOrAffiliatedProfileOwner) {
726 // Allow the device owner and affiliated profile owner to silently delete packages
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000727 // Need to clear the calling identity to get DELETE_PACKAGES permission
728 long ident = Binder.clearCallingIdentity();
729 try {
Svet Ganov67882122016-12-11 16:36:34 -0800730 mPm.deletePackageVersioned(versionedPackage, adapter.getBinder(), userId, flags);
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000731 } finally {
732 Binder.restoreCallingIdentity(ident);
733 }
Jeff Sharkeyf0600952014-08-07 17:31:53 -0700734 } else {
Philip P. Moltmannd9bb39a2017-09-05 12:41:15 -0700735 ApplicationInfo appInfo = mPm.getApplicationInfo(callerPackageName, 0, userId);
736 if (appInfo.targetSdkVersion >= Build.VERSION_CODES.P) {
737 mContext.enforceCallingOrSelfPermission(Manifest.permission.REQUEST_DELETE_PACKAGES,
738 null);
739 }
740
Jeff Sharkeyf0600952014-08-07 17:31:53 -0700741 // Take a short detour to confirm with user
742 final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
Svet Ganov67882122016-12-11 16:36:34 -0800743 intent.setData(Uri.fromParts("package", versionedPackage.getPackageName(), null));
Jeff Sharkeya0907432014-08-15 10:23:11 -0700744 intent.putExtra(PackageInstaller.EXTRA_CALLBACK, adapter.getBinder().asBinder());
745 adapter.onUserActionRequired(intent);
Jeff Sharkeyf0600952014-08-07 17:31:53 -0700746 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700747 }
748
749 @Override
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700750 public void setPermissionsResult(int sessionId, boolean accepted) {
751 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, TAG);
752
753 synchronized (mSessions) {
Svet Ganov3baa8762016-04-08 09:22:54 -0700754 PackageInstallerSession session = mSessions.get(sessionId);
755 if (session != null) {
756 session.setPermissionsResult(accepted);
757 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700758 }
759 }
760
761 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700762 public void registerCallback(IPackageInstallerCallback callback, int userId) {
Todd Kennedy0eb97382017-10-03 16:57:22 -0700763 mPermissionManager.enforceCrossUserPermission(
764 Binder.getCallingUid(), userId, true, false, "registerCallback");
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700765 mCallbacks.register(callback, userId);
Jeff Sharkeybb580672014-07-10 12:10:25 -0700766 }
767
768 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700769 public void unregisterCallback(IPackageInstallerCallback callback) {
770 mCallbacks.unregister(callback);
Jeff Sharkeya1031142014-07-12 18:09:46 -0700771 }
772
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700773 private static int getSessionCount(SparseArray<PackageInstallerSession> sessions,
774 int installerUid) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700775 int count = 0;
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700776 final int size = sessions.size();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700777 for (int i = 0; i < size; i++) {
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700778 final PackageInstallerSession session = sessions.valueAt(i);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000779 if (session.getInstallerUid() == installerUid) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700780 count++;
781 }
782 }
783 return count;
784 }
785
786 private boolean isCallingUidOwner(PackageInstallerSession session) {
787 final int callingUid = Binder.getCallingUid();
788 if (callingUid == Process.ROOT_UID) {
789 return true;
790 } else {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000791 return (session != null) && (callingUid == session.getInstallerUid());
Jeff Sharkeya1031142014-07-12 18:09:46 -0700792 }
793 }
794
Jeff Sharkeya0907432014-08-15 10:23:11 -0700795 static class PackageDeleteObserverAdapter extends PackageDeleteObserver {
796 private final Context mContext;
797 private final IntentSender mTarget;
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700798 private final String mPackageName;
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000799 private final Notification mNotification;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700800
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700801 public PackageDeleteObserverAdapter(Context context, IntentSender target,
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000802 String packageName, boolean showNotification, int userId) {
Jeff Sharkeya0907432014-08-15 10:23:11 -0700803 mContext = context;
804 mTarget = target;
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700805 mPackageName = packageName;
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000806 if (showNotification) {
807 mNotification = buildSuccessNotification(mContext,
808 mContext.getResources().getString(R.string.package_deleted_device_owner),
809 packageName,
810 userId);
811 } else {
812 mNotification = null;
813 }
Jeff Sharkeya0907432014-08-15 10:23:11 -0700814 }
815
816 @Override
817 public void onUserActionRequired(Intent intent) {
818 final Intent fillIn = new Intent();
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700819 fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName);
Jeff Sharkeya0907432014-08-15 10:23:11 -0700820 fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
Jeff Sharkey742e7902014-08-16 19:09:13 -0700821 PackageInstaller.STATUS_PENDING_USER_ACTION);
Jeff Sharkeya0907432014-08-15 10:23:11 -0700822 fillIn.putExtra(Intent.EXTRA_INTENT, intent);
823 try {
824 mTarget.sendIntent(mContext, 0, fillIn, null, null);
825 } catch (SendIntentException ignored) {
826 }
827 }
828
829 @Override
830 public void onPackageDeleted(String basePackageName, int returnCode, String msg) {
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000831 if (PackageManager.DELETE_SUCCEEDED == returnCode && mNotification != null) {
832 NotificationManager notificationManager = (NotificationManager)
833 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
Chris Wren282cfef2017-03-27 15:01:44 -0400834 notificationManager.notify(basePackageName,
835 SystemMessage.NOTE_PACKAGE_STATE,
836 mNotification);
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000837 }
Jeff Sharkeya0907432014-08-15 10:23:11 -0700838 final Intent fillIn = new Intent();
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700839 fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName);
Jeff Sharkeya0907432014-08-15 10:23:11 -0700840 fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
841 PackageManager.deleteStatusToPublicStatus(returnCode));
842 fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
843 PackageManager.deleteStatusToString(returnCode, msg));
844 fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode);
845 try {
846 mTarget.sendIntent(mContext, 0, fillIn, null, null);
847 } catch (SendIntentException ignored) {
848 }
849 }
850 }
851
852 static class PackageInstallObserverAdapter extends PackageInstallObserver {
853 private final Context mContext;
854 private final IntentSender mTarget;
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700855 private final int mSessionId;
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000856 private final boolean mShowNotification;
857 private final int mUserId;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700858
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000859 public PackageInstallObserverAdapter(Context context, IntentSender target, int sessionId,
860 boolean showNotification, int userId) {
Jeff Sharkeya0907432014-08-15 10:23:11 -0700861 mContext = context;
862 mTarget = target;
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700863 mSessionId = sessionId;
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000864 mShowNotification = showNotification;
865 mUserId = userId;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700866 }
867
868 @Override
869 public void onUserActionRequired(Intent intent) {
870 final Intent fillIn = new Intent();
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700871 fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId);
Jeff Sharkeya0907432014-08-15 10:23:11 -0700872 fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
Jeff Sharkey742e7902014-08-16 19:09:13 -0700873 PackageInstaller.STATUS_PENDING_USER_ACTION);
Jeff Sharkeya0907432014-08-15 10:23:11 -0700874 fillIn.putExtra(Intent.EXTRA_INTENT, intent);
875 try {
876 mTarget.sendIntent(mContext, 0, fillIn, null, null);
877 } catch (SendIntentException ignored) {
878 }
879 }
880
881 @Override
882 public void onPackageInstalled(String basePackageName, int returnCode, String msg,
883 Bundle extras) {
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000884 if (PackageManager.INSTALL_SUCCEEDED == returnCode && mShowNotification) {
Benjamin Franz2e3e9432015-04-17 15:28:17 +0100885 boolean update = (extras != null) && extras.getBoolean(Intent.EXTRA_REPLACING);
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000886 Notification notification = buildSuccessNotification(mContext,
Benjamin Franz2e3e9432015-04-17 15:28:17 +0100887 mContext.getResources()
888 .getString(update ? R.string.package_updated_device_owner :
889 R.string.package_installed_device_owner),
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000890 basePackageName,
891 mUserId);
892 if (notification != null) {
893 NotificationManager notificationManager = (NotificationManager)
894 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
Chris Wren282cfef2017-03-27 15:01:44 -0400895 notificationManager.notify(basePackageName,
896 SystemMessage.NOTE_PACKAGE_STATE,
897 notification);
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000898 }
899 }
Jeff Sharkeya0907432014-08-15 10:23:11 -0700900 final Intent fillIn = new Intent();
Benjamin Franz2e3e9432015-04-17 15:28:17 +0100901 fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, basePackageName);
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,
904 PackageManager.installStatusToPublicStatus(returnCode));
905 fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
906 PackageManager.installStatusToString(returnCode, msg));
907 fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode);
908 if (extras != null) {
909 final String existing = extras.getString(
910 PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE);
911 if (!TextUtils.isEmpty(existing)) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700912 fillIn.putExtra(PackageInstaller.EXTRA_OTHER_PACKAGE_NAME, existing);
Jeff Sharkeya0907432014-08-15 10:23:11 -0700913 }
914 }
915 try {
916 mTarget.sendIntent(mContext, 0, fillIn, null, null);
917 } catch (SendIntentException ignored) {
918 }
919 }
920 }
921
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000922 /**
923 * Build a notification for package installation / deletion by device owners that is shown if
924 * the operation succeeds.
925 */
926 private static Notification buildSuccessNotification(Context context, String contentText,
927 String basePackageName, int userId) {
928 PackageInfo packageInfo = null;
929 try {
930 packageInfo = AppGlobals.getPackageManager().getPackageInfo(
Svet Ganova5c867c2017-05-15 01:17:05 -0700931 basePackageName, PackageManager.MATCH_STATIC_SHARED_LIBRARIES, userId);
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000932 } catch (RemoteException ignored) {
933 }
934 if (packageInfo == null || packageInfo.applicationInfo == null) {
935 Slog.w(TAG, "Notification not built for package: " + basePackageName);
936 return null;
937 }
938 PackageManager pm = context.getPackageManager();
939 Bitmap packageIcon = ImageUtils.buildScaledBitmap(
940 packageInfo.applicationInfo.loadIcon(pm),
941 context.getResources().getDimensionPixelSize(
942 android.R.dimen.notification_large_icon_width),
943 context.getResources().getDimensionPixelSize(
944 android.R.dimen.notification_large_icon_height));
945 CharSequence packageLabel = packageInfo.applicationInfo.loadLabel(pm);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -0500946 return new Notification.Builder(context, SystemNotificationChannels.DEVICE_ADMIN)
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000947 .setSmallIcon(R.drawable.ic_check_circle_24px)
948 .setColor(context.getResources().getColor(
949 R.color.system_notification_accent_color))
950 .setContentTitle(packageLabel)
951 .setContentText(contentText)
Benjamin Franz2e3e9432015-04-17 15:28:17 +0100952 .setStyle(new Notification.BigTextStyle().bigText(contentText))
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000953 .setLargeIcon(packageIcon)
954 .build();
955 }
956
Jeff Sharkey54d42be2015-07-20 16:36:55 -0700957 public static <E> ArraySet<E> newArraySet(E... elements) {
958 final ArraySet<E> set = new ArraySet<E>();
959 if (elements != null) {
960 set.ensureCapacity(elements.length);
961 Collections.addAll(set, elements);
962 }
963 return set;
964 }
965
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700966 private static class Callbacks extends Handler {
967 private static final int MSG_SESSION_CREATED = 1;
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700968 private static final int MSG_SESSION_BADGING_CHANGED = 2;
Jeff Sharkeybc7bce32014-09-05 15:53:05 -0700969 private static final int MSG_SESSION_ACTIVE_CHANGED = 3;
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700970 private static final int MSG_SESSION_PROGRESS_CHANGED = 4;
Jeff Sharkeybc7bce32014-09-05 15:53:05 -0700971 private static final int MSG_SESSION_FINISHED = 5;
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700972
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700973 private final RemoteCallbackList<IPackageInstallerCallback>
974 mCallbacks = new RemoteCallbackList<>();
Jeff Sharkeya1031142014-07-12 18:09:46 -0700975
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700976 public Callbacks(Looper looper) {
977 super(looper);
978 }
979
980 public void register(IPackageInstallerCallback callback, int userId) {
981 mCallbacks.register(callback, new UserHandle(userId));
982 }
983
984 public void unregister(IPackageInstallerCallback callback) {
985 mCallbacks.unregister(callback);
986 }
987
988 @Override
989 public void handleMessage(Message msg) {
990 final int userId = msg.arg2;
991 final int n = mCallbacks.beginBroadcast();
992 for (int i = 0; i < n; i++) {
993 final IPackageInstallerCallback callback = mCallbacks.getBroadcastItem(i);
994 final UserHandle user = (UserHandle) mCallbacks.getBroadcastCookie(i);
995 // TODO: dispatch notifications for slave profiles
996 if (userId == user.getIdentifier()) {
997 try {
998 invokeCallback(callback, msg);
999 } catch (RemoteException ignored) {
1000 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07001001 }
1002 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001003 mCallbacks.finishBroadcast();
Jeff Sharkeya1031142014-07-12 18:09:46 -07001004 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001005
1006 private void invokeCallback(IPackageInstallerCallback callback, Message msg)
1007 throws RemoteException {
1008 final int sessionId = msg.arg1;
1009 switch (msg.what) {
1010 case MSG_SESSION_CREATED:
1011 callback.onSessionCreated(sessionId);
1012 break;
Jeff Sharkeyec9bad22014-09-05 09:45:20 -07001013 case MSG_SESSION_BADGING_CHANGED:
1014 callback.onSessionBadgingChanged(sessionId);
1015 break;
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001016 case MSG_SESSION_ACTIVE_CHANGED:
1017 callback.onSessionActiveChanged(sessionId, (boolean) msg.obj);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001018 break;
1019 case MSG_SESSION_PROGRESS_CHANGED:
1020 callback.onSessionProgressChanged(sessionId, (float) msg.obj);
1021 break;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001022 case MSG_SESSION_FINISHED:
1023 callback.onSessionFinished(sessionId, (boolean) msg.obj);
1024 break;
1025 }
1026 }
1027
1028 private void notifySessionCreated(int sessionId, int userId) {
1029 obtainMessage(MSG_SESSION_CREATED, sessionId, userId).sendToTarget();
1030 }
1031
Jeff Sharkeyec9bad22014-09-05 09:45:20 -07001032 private void notifySessionBadgingChanged(int sessionId, int userId) {
1033 obtainMessage(MSG_SESSION_BADGING_CHANGED, sessionId, userId).sendToTarget();
1034 }
1035
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001036 private void notifySessionActiveChanged(int sessionId, int userId, boolean active) {
1037 obtainMessage(MSG_SESSION_ACTIVE_CHANGED, sessionId, userId, active).sendToTarget();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001038 }
1039
1040 private void notifySessionProgressChanged(int sessionId, int userId, float progress) {
1041 obtainMessage(MSG_SESSION_PROGRESS_CHANGED, sessionId, userId, progress).sendToTarget();
1042 }
1043
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001044 public void notifySessionFinished(int sessionId, int userId, boolean success) {
1045 obtainMessage(MSG_SESSION_FINISHED, sessionId, userId, success).sendToTarget();
1046 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07001047 }
1048
1049 void dump(IndentingPrintWriter pw) {
Jeff Sharkeya1031142014-07-12 18:09:46 -07001050 synchronized (mSessions) {
Jeff Sharkey9a445772014-07-16 11:32:08 -07001051 pw.println("Active install sessions:");
1052 pw.increaseIndent();
1053 int N = mSessions.size();
Jeff Sharkeya1031142014-07-12 18:09:46 -07001054 for (int i = 0; i < N; i++) {
1055 final PackageInstallerSession session = mSessions.valueAt(i);
1056 session.dump(pw);
1057 pw.println();
1058 }
Jeff Sharkey9a445772014-07-16 11:32:08 -07001059 pw.println();
1060 pw.decreaseIndent();
1061
1062 pw.println("Historical install sessions:");
1063 pw.increaseIndent();
1064 N = mHistoricalSessions.size();
1065 for (int i = 0; i < N; i++) {
Narayan Kamatha22a7662017-06-12 13:34:29 +01001066 pw.print(mHistoricalSessions.get(i));
Jeff Sharkey9a445772014-07-16 11:32:08 -07001067 pw.println();
1068 }
1069 pw.println();
1070 pw.decreaseIndent();
Jeff Sharkey742e7902014-08-16 19:09:13 -07001071
1072 pw.println("Legacy install sessions:");
1073 pw.increaseIndent();
1074 pw.println(mLegacySessions.toString());
1075 pw.decreaseIndent();
Jeff Sharkeya1031142014-07-12 18:09:46 -07001076 }
Jeff Sharkeybb580672014-07-10 12:10:25 -07001077 }
1078
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001079 class InternalCallback {
Jeff Sharkeyec9bad22014-09-05 09:45:20 -07001080 public void onSessionBadgingChanged(PackageInstallerSession session) {
1081 mCallbacks.notifySessionBadgingChanged(session.sessionId, session.userId);
1082 writeSessionsAsync();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001083 }
1084
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001085 public void onSessionActiveChanged(PackageInstallerSession session, boolean active) {
1086 mCallbacks.notifySessionActiveChanged(session.sessionId, session.userId, active);
Jeff Sharkey742e7902014-08-16 19:09:13 -07001087 }
1088
Jeff Sharkeyec9bad22014-09-05 09:45:20 -07001089 public void onSessionProgressChanged(PackageInstallerSession session, float progress) {
1090 mCallbacks.notifySessionProgressChanged(session.sessionId, session.userId, progress);
1091 }
1092
Jeff Sharkeycbf47912014-09-12 09:55:32 -07001093 public void onSessionFinished(final PackageInstallerSession session, boolean success) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001094 mCallbacks.notifySessionFinished(session.sessionId, session.userId, success);
Jeff Sharkeycbf47912014-09-12 09:55:32 -07001095
1096 mInstallHandler.post(new Runnable() {
1097 @Override
1098 public void run() {
1099 synchronized (mSessions) {
1100 mSessions.remove(session.sessionId);
Narayan Kamatha22a7662017-06-12 13:34:29 +01001101 addHistoricalSessionLocked(session);
Jeff Sharkey02bd7842014-10-06 15:14:27 -07001102
1103 final File appIconFile = buildAppIconFile(session.sessionId);
1104 if (appIconFile.exists()) {
1105 appIconFile.delete();
1106 }
1107
Jeff Sharkeycbf47912014-09-12 09:55:32 -07001108 writeSessionsLocked();
1109 }
1110 }
1111 });
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001112 }
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -07001113
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001114 public void onSessionPrepared(PackageInstallerSession session) {
1115 // We prepared the destination to write into; we want to persist
1116 // this, but it's not critical enough to block for.
1117 writeSessionsAsync();
1118 }
1119
Jeff Sharkeycbf47912014-09-12 09:55:32 -07001120 public void onSessionSealedBlocking(PackageInstallerSession session) {
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -07001121 // It's very important that we block until we've recorded the
1122 // session as being sealed, since we never want to allow mutation
1123 // after sealing.
Jeff Sharkeycbf47912014-09-12 09:55:32 -07001124 synchronized (mSessions) {
1125 writeSessionsLocked();
1126 }
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -07001127 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001128 }
1129}