blob: 0329e2c5ed45b4a46562e130673486d1a358074c [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;
Rubin Xu8b17ad02019-03-07 17:42:37 +000030import android.app.admin.DevicePolicyEventLogger;
Benjamin Franzdabae882017-08-08 12:33:19 +010031import 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.UserManager;
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -070062import android.os.storage.StorageManager;
Rubin Xu8b17ad02019-03-07 17:42:37 +000063import android.stats.devicepolicy.DevicePolicyEnums;
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;
Philip P. Moltmann48456672019-01-20 13:14:03 -080087import com.android.server.pm.permission.PermissionManagerServiceInternal;
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;
Jon Miranda2b340a22019-01-25 14:03:49 -0800109import java.util.function.IntPredicate;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700110
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000111/** The service responsible for installing packages. */
112public class PackageInstallerService extends IPackageInstaller.Stub implements
113 PackageSessionProvider {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700114 private static final String TAG = "PackageInstaller";
Jeff Sharkeye9808042014-09-11 21:15:37 -0700115 private static final boolean LOGD = false;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700116
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700117 // TODO: remove outstanding sessions when installer package goes away
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700118 // TODO: notify listeners in other users when package has been installed there
Jeff Sharkey742e7902014-08-16 19:09:13 -0700119 // TODO: purge expired sessions periodically in addition to at reboot
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700120
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700121 /** XML constants used in {@link #mSessionsFile} */
122 private static final String TAG_SESSIONS = "sessions";
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700123
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700124 /** Automatically destroy sessions older than this */
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700125 private static final long MAX_AGE_MILLIS = 3 * DateUtils.DAY_IN_MILLIS;
Gavin Corkeryd8311212019-02-22 17:52:30 +0000126 /** Automatically destroy staged sessions that have not changed state in this time */
127 private static final long MAX_TIME_SINCE_UPDATE_MILLIS = 7 * DateUtils.DAY_IN_MILLIS;
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700128 /** Upper bound on number of active sessions for a UID */
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700129 private static final long MAX_ACTIVE_SESSIONS = 1024;
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700130 /** Upper bound on number of historical sessions for a UID */
131 private static final long MAX_HISTORICAL_SESSIONS = 1048576;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700132
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700133 private final Context mContext;
134 private final PackageManagerService mPm;
Dario Freni83620602019-02-18 14:30:57 +0000135 private final ApexManager mApexManager;
Dario Frenibe98c3f2018-12-22 15:25:27 +0000136 private final StagingManager mStagingManager;
Philip P. Moltmann48456672019-01-20 13:14:03 -0800137 private final PermissionManagerServiceInternal mPermissionManager;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700138
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700139 private AppOpsManager mAppOps;
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700140
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700141 private final HandlerThread mInstallThread;
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700142 private final Handler mInstallHandler;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700143
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700144 private final Callbacks mCallbacks;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700145
Dario Freni14f885b2019-02-25 12:48:47 +0000146 private volatile boolean mOkToSendBroadcasts = false;
Dario Freni9694b802019-01-27 23:26:06 +0000147
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700148 /**
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700149 * File storing persisted {@link #mSessions} metadata.
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700150 */
151 private final AtomicFile mSessionsFile;
152
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700153 /**
154 * Directory storing persisted {@link #mSessions} metadata which is too
155 * heavy to store directly in {@link #mSessionsFile}.
156 */
157 private final File mSessionsDir;
158
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700159 private final InternalCallback mInternalCallback = new InternalCallback();
160
161 /**
162 * Used for generating session IDs. Since this is created at boot time,
163 * normal random might be predictable.
164 */
165 private final Random mRandom = new SecureRandom();
166
Todd Kennedy28c4e802016-07-13 13:20:30 -0700167 /** All sessions allocated */
168 @GuardedBy("mSessions")
169 private final SparseBooleanArray mAllocatedSessions = new SparseBooleanArray();
170
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700171 @GuardedBy("mSessions")
172 private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>();
173
Jeff Sharkey9a445772014-07-16 11:32:08 -0700174 /** Historical sessions kept around for debugging purposes */
175 @GuardedBy("mSessions")
Narayan Kamatha22a7662017-06-12 13:34:29 +0100176 private final List<String> mHistoricalSessions = new ArrayList<>();
177
178 @GuardedBy("mSessions")
179 private final SparseIntArray mHistoricalSessionsByInstaller = new SparseIntArray();
Jeff Sharkey9a445772014-07-16 11:32:08 -0700180
Jeff Sharkey742e7902014-08-16 19:09:13 -0700181 /** Sessions allocated to legacy users */
182 @GuardedBy("mSessions")
183 private final SparseBooleanArray mLegacySessions = new SparseBooleanArray();
184
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700185 private static final FilenameFilter sStageFilter = new FilenameFilter() {
186 @Override
187 public boolean accept(File dir, String name) {
Jeff Sharkey742e7902014-08-16 19:09:13 -0700188 return isStageName(name);
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700189 }
190 };
191
Dario Freni2e8dffc2019-02-06 14:55:16 +0000192 public PackageInstallerService(Context context, PackageManagerService pm, ApexManager am) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700193 mContext = context;
194 mPm = pm;
Philip P. Moltmann48456672019-01-20 13:14:03 -0800195 mPermissionManager = LocalServices.getService(PermissionManagerServiceInternal.class);
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700196
197 mInstallThread = new HandlerThread(TAG);
198 mInstallThread.start();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700199
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700200 mInstallHandler = new Handler(mInstallThread.getLooper());
201
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700202 mCallbacks = new Callbacks(mInstallThread.getLooper());
203
204 mSessionsFile = new AtomicFile(
Dianne Hackborne17b4452018-01-10 13:15:40 -0800205 new File(Environment.getDataSystemDirectory(), "install_sessions.xml"),
206 "package-session");
Jeff Sharkey8212ae02016-02-10 14:46:43 -0700207 mSessionsDir = new File(Environment.getDataSystemDirectory(), "install_sessions");
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700208 mSessionsDir.mkdirs();
Dario Frenibe98c3f2018-12-22 15:25:27 +0000209
Dario Freni83620602019-02-18 14:30:57 +0000210 mApexManager = am;
Nikita Ioffe39a6a5b2019-02-26 15:36:39 +0000211
Nikita Ioffe1a7965e2019-03-12 22:32:41 +0000212 mStagingManager = new StagingManager(this, am, context);
Tony Mak606f8e72017-02-15 18:40:03 +0000213 }
214
Dario Freni14f885b2019-02-25 12:48:47 +0000215 boolean okToSendBroadcasts() {
216 return mOkToSendBroadcasts;
Dario Freni4b572c02019-01-29 09:40:31 +0000217 }
218
Tony Mak606f8e72017-02-15 18:40:03 +0000219 public void systemReady() {
220 mAppOps = mContext.getSystemService(AppOpsManager.class);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700221
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700222 synchronized (mSessions) {
223 readSessionsLocked();
224
Dario Frenia8f4b132018-12-30 00:36:49 +0000225 reconcileStagesLocked(StorageManager.UUID_PRIVATE_INTERNAL);
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700226
Jeff Sharkey54d42be2015-07-20 16:36:55 -0700227 final ArraySet<File> unclaimedIcons = newArraySet(
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700228 mSessionsDir.listFiles());
Jeff Sharkey742e7902014-08-16 19:09:13 -0700229
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700230 // Ignore stages and icons claimed by active sessions
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700231 for (int i = 0; i < mSessions.size(); i++) {
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700232 final PackageInstallerSession session = mSessions.valueAt(i);
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700233 unclaimedIcons.remove(buildAppIconFile(session.sessionId));
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700234 }
Jeff Sharkey742e7902014-08-16 19:09:13 -0700235
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700236 // Clean up orphaned icons
237 for (File icon : unclaimedIcons) {
238 Slog.w(TAG, "Deleting orphan icon " + icon);
239 icon.delete();
240 }
Dario Freni0180d0b2019-01-11 21:08:13 +0000241
242 // Invalid sessions might have been marked while parsing. Re-write the database with
243 // the updated information.
244 writeSessionsLocked();
245
Dario Freni4b572c02019-01-29 09:40:31 +0000246 }
247 }
248
249 void restoreAndApplyStagedSessionIfNeeded() {
250 List<PackageInstallerSession> stagedSessionsToRestore = new ArrayList<>();
251 synchronized (mSessions) {
Dario Freni0180d0b2019-01-11 21:08:13 +0000252 for (int i = 0; i < mSessions.size(); i++) {
253 final PackageInstallerSession session = mSessions.valueAt(i);
254 if (session.isStaged()) {
Dario Freni4b572c02019-01-29 09:40:31 +0000255 stagedSessionsToRestore.add(session);
Dario Freni0180d0b2019-01-11 21:08:13 +0000256 }
257 }
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700258 }
Dario Freni4b572c02019-01-29 09:40:31 +0000259 // Don't hold mSessions lock when calling restoreSession, since it might trigger an APK
260 // atomic install which needs to query sessions, which requires lock on mSessions.
261 for (PackageInstallerSession session : stagedSessionsToRestore) {
262 mStagingManager.restoreSession(session);
263 }
Dario Freni14f885b2019-02-25 12:48:47 +0000264 // Broadcasts are not sent while we restore sessions on boot, since no processes would be
265 // ready to listen to them. From now on, we greedily assume that broadcasts requests are
266 // safe to send out. The worst that can happen is that a broadcast is attempted before
267 // ActivityManagerService completes its own systemReady(), in which case it will be rejected
268 // with an otherwise harmless exception.
269 // A more appropriate way to do this would be to wait until the correct boot phase is
270 // reached, but since we are not a SystemService we can't override onBootPhase.
271 // Waiting on the BOOT_COMPLETED broadcast can take several minutes, so that's not a viable
272 // way either.
273 mOkToSendBroadcasts = true;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700274 }
275
Andreas Gampea36dc622018-02-05 17:19:22 -0800276 @GuardedBy("mSessions")
Dario Frenia8f4b132018-12-30 00:36:49 +0000277 private void reconcileStagesLocked(String volumeUuid) {
278 final File stagingDir = getTmpSessionDir(volumeUuid);
Jeff Sharkey54d42be2015-07-20 16:36:55 -0700279 final ArraySet<File> unclaimedStages = newArraySet(
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700280 stagingDir.listFiles(sStageFilter));
281
282 // Ignore stages claimed by active sessions
283 for (int i = 0; i < mSessions.size(); i++) {
284 final PackageInstallerSession session = mSessions.valueAt(i);
285 unclaimedStages.remove(session.stageDir);
286 }
287
288 // Clean up orphaned staging directories
289 for (File stage : unclaimedStages) {
290 Slog.w(TAG, "Deleting orphan stage " + stage);
291 synchronized (mPm.mInstallLock) {
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -0700292 mPm.removeCodePathLI(stage);
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700293 }
294 }
295 }
296
297 public void onPrivateVolumeMounted(String volumeUuid) {
298 synchronized (mSessions) {
Dario Frenia8f4b132018-12-30 00:36:49 +0000299 reconcileStagesLocked(volumeUuid);
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700300 }
301 }
302
Jeff Sharkey742e7902014-08-16 19:09:13 -0700303 public static boolean isStageName(String name) {
304 final boolean isFile = name.startsWith("vmdl") && name.endsWith(".tmp");
305 final boolean isContainer = name.startsWith("smdl") && name.endsWith(".tmp");
306 final boolean isLegacyContainer = name.startsWith("smdl2tmp");
307 return isFile || isContainer || isLegacyContainer;
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700308 }
309
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700310 @Deprecated
Todd Kennedy2699f062015-11-20 13:07:17 -0800311 public File allocateStageDirLegacy(String volumeUuid, boolean isEphemeral) throws IOException {
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700312 synchronized (mSessions) {
313 try {
314 final int sessionId = allocateSessionIdLocked();
Jeff Sharkey742e7902014-08-16 19:09:13 -0700315 mLegacySessions.put(sessionId, true);
Dario Frenia8f4b132018-12-30 00:36:49 +0000316 final File sessionStageDir = buildTmpSessionDir(sessionId, volumeUuid);
317 prepareStageDir(sessionStageDir);
318 return sessionStageDir;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700319 } catch (IllegalStateException e) {
320 throw new IOException(e);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700321 }
322 }
323 }
324
Jeff Sharkey742e7902014-08-16 19:09:13 -0700325 @Deprecated
326 public String allocateExternalStageCidLegacy() {
327 synchronized (mSessions) {
328 final int sessionId = allocateSessionIdLocked();
329 mLegacySessions.put(sessionId, true);
330 return "smdl" + sessionId + ".tmp";
331 }
332 }
333
Andreas Gampea36dc622018-02-05 17:19:22 -0800334 @GuardedBy("mSessions")
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700335 private void readSessionsLocked() {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700336 if (LOGD) Slog.v(TAG, "readSessionsLocked()");
337
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700338 mSessions.clear();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700339
340 FileInputStream fis = null;
341 try {
342 fis = mSessionsFile.openRead();
343 final XmlPullParser in = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +0100344 in.setInput(fis, StandardCharsets.UTF_8.name());
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700345
346 int type;
347 while ((type = in.next()) != END_DOCUMENT) {
348 if (type == START_TAG) {
349 final String tag = in.getName();
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000350 if (PackageInstallerSession.TAG_SESSION.equals(tag)) {
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -0700351 final PackageInstallerSession session;
352 try {
353 session = PackageInstallerSession.readFromXml(in, mInternalCallback,
Dario Frenibe98c3f2018-12-22 15:25:27 +0000354 mContext, mPm, mInstallThread.getLooper(), mStagingManager,
355 mSessionsDir, this);
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -0700356 } catch (Exception e) {
357 Slog.e(TAG, "Could not read session", e);
358 continue;
359 }
360
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700361 final long age = System.currentTimeMillis() - session.createdMillis;
Gavin Corkeryd8311212019-02-22 17:52:30 +0000362 final long timeSinceUpdate =
Gavin Corkery13f81612019-03-20 18:22:58 +0000363 System.currentTimeMillis() - session.getUpdatedMillis();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700364 final boolean valid;
Gavin Corkeryd8311212019-02-22 17:52:30 +0000365 if (session.isStaged()) {
Dario Freni7f5a6952019-05-10 19:40:50 +0100366 if (timeSinceUpdate >= MAX_TIME_SINCE_UPDATE_MILLIS
367 && session.isStagedAndInTerminalState()) {
Gavin Corkeryd8311212019-02-22 17:52:30 +0000368 valid = false;
369 } else {
370 valid = true;
371 }
372 } else if (age >= MAX_AGE_MILLIS) {
373 Slog.w(TAG, "Abandoning old session created at "
374 + session.createdMillis);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700375 valid = false;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700376 } else {
377 valid = true;
378 }
379
380 if (valid) {
381 mSessions.put(session.sessionId, session);
382 } else {
383 // Since this is early during boot we don't send
384 // any observer events about the session, but we
385 // keep details around for dumpsys.
Narayan Kamatha22a7662017-06-12 13:34:29 +0100386 addHistoricalSessionLocked(session);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700387 }
Todd Kennedy28c4e802016-07-13 13:20:30 -0700388 mAllocatedSessions.put(session.sessionId, true);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700389 }
390 }
391 }
392 } catch (FileNotFoundException e) {
393 // Missing sessions are okay, probably first boot
Svet Ganov7121e182015-07-13 22:38:12 -0700394 } catch (IOException | XmlPullParserException e) {
Dianne Hackborn8d051722014-10-01 14:59:58 -0700395 Slog.wtf(TAG, "Failed reading install sessions", e);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700396 } finally {
397 IoUtils.closeQuietly(fis);
398 }
shafik43f1af92019-03-14 15:14:00 +0000399 // After all of the sessions were loaded, they are ready to be sealed and validated
400 for (int i = 0; i < mSessions.size(); ++i) {
401 PackageInstallerSession session = mSessions.valueAt(i);
402 session.sealAndValidateIfNecessary();
403 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700404 }
405
Andreas Gampea36dc622018-02-05 17:19:22 -0800406 @GuardedBy("mSessions")
Narayan Kamatha22a7662017-06-12 13:34:29 +0100407 private void addHistoricalSessionLocked(PackageInstallerSession session) {
408 CharArrayWriter writer = new CharArrayWriter();
409 IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
410 session.dump(pw);
411 mHistoricalSessions.add(writer.toString());
412
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000413 int installerUid = session.getInstallerUid();
Narayan Kamatha22a7662017-06-12 13:34:29 +0100414 // Increment the number of sessions by this installerUid.
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000415 mHistoricalSessionsByInstaller.put(installerUid,
416 mHistoricalSessionsByInstaller.get(installerUid) + 1);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700417 }
418
Andreas Gampea36dc622018-02-05 17:19:22 -0800419 @GuardedBy("mSessions")
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700420 private void writeSessionsLocked() {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700421 if (LOGD) Slog.v(TAG, "writeSessionsLocked()");
422
423 FileOutputStream fos = null;
424 try {
425 fos = mSessionsFile.startWrite();
426
427 XmlSerializer out = new FastXmlSerializer();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +0100428 out.setOutput(fos, StandardCharsets.UTF_8.name());
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700429 out.startDocument(null, true);
430 out.startTag(null, TAG_SESSIONS);
431 final int size = mSessions.size();
432 for (int i = 0; i < size; i++) {
433 final PackageInstallerSession session = mSessions.valueAt(i);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000434 session.write(out, mSessionsDir);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700435 }
436 out.endTag(null, TAG_SESSIONS);
437 out.endDocument();
438
439 mSessionsFile.finishWrite(fos);
440 } catch (IOException e) {
441 if (fos != null) {
442 mSessionsFile.failWrite(fos);
443 }
444 }
445 }
446
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700447 private File buildAppIconFile(int sessionId) {
448 return new File(mSessionsDir, "app_icon." + sessionId + ".png");
449 }
450
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700451 private void writeSessionsAsync() {
452 IoThread.getHandler().post(new Runnable() {
453 @Override
454 public void run() {
455 synchronized (mSessions) {
456 writeSessionsLocked();
457 }
458 }
459 });
460 }
461
462 @Override
Jeff Sharkeya0907432014-08-15 10:23:11 -0700463 public int createSession(SessionParams params, String installerPackageName, int userId) {
Jeff Sharkey742e7902014-08-16 19:09:13 -0700464 try {
465 return createSessionInternal(params, installerPackageName, userId);
466 } catch (IOException e) {
467 throw ExceptionUtils.wrap(e);
468 }
469 }
470
471 private int createSessionInternal(SessionParams params, String installerPackageName, int userId)
472 throws IOException {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700473 final int callingUid = Binder.getCallingUid();
Todd Kennedy0eb97382017-10-03 16:57:22 -0700474 mPermissionManager.enforceCrossUserPermission(
475 callingUid, userId, true, true, "createSession");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700476
Jeff Sharkeye9808042014-09-11 21:15:37 -0700477 if (mPm.isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700478 throw new SecurityException("User restriction prevents installing");
479 }
480
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700481 if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {
Jeff Sharkeye9808042014-09-11 21:15:37 -0700482 params.installFlags |= PackageManager.INSTALL_FROM_ADB;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700483
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700484 } else {
Philip P. Moltmann79c238a2017-12-13 15:59:07 -0800485 // Only apps with INSTALL_PACKAGES are allowed to set an installer that is not the
486 // caller.
487 if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES) !=
488 PackageManager.PERMISSION_GRANTED) {
489 mAppOps.checkPackage(callingUid, installerPackageName);
490 }
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700491
Jeff Sharkeye9808042014-09-11 21:15:37 -0700492 params.installFlags &= ~PackageManager.INSTALL_FROM_ADB;
493 params.installFlags &= ~PackageManager.INSTALL_ALL_USERS;
Todd Kennedydedeee82019-09-20 13:45:15 -0700494 params.installFlags &= ~PackageManager.INSTALL_ALLOW_TEST;
Jeff Sharkeye9808042014-09-11 21:15:37 -0700495 params.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
Todd Kennedy78a72502017-07-19 12:49:30 -0700496 if ((params.installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0
497 && !mPm.isCallerVerifier(callingUid)) {
498 params.installFlags &= ~PackageManager.INSTALL_VIRTUAL_PRELOAD;
499 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700500 }
501
Nikita Ioffe1962cb12019-03-27 22:59:28 +0000502 if (Build.IS_DEBUGGABLE || isDowngradeAllowedForCaller(callingUid)) {
Nikita Ioffeb1d60f12019-03-06 18:56:49 +0000503 params.installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE;
Nikita Ioffea1111ff2019-03-04 12:26:14 +0000504 } else {
Nikita Ioffeb1d60f12019-03-06 18:56:49 +0000505 params.installFlags &= ~PackageManager.INSTALL_ALLOW_DOWNGRADE;
Nikita Ioffe1962cb12019-03-27 22:59:28 +0000506 params.installFlags &= ~PackageManager.INSTALL_REQUEST_DOWNGRADE;
Nikita Ioffea1111ff2019-03-04 12:26:14 +0000507 }
508
Nikita Ioffebf8e2572019-07-30 17:10:27 +0100509 if (callingUid != Process.SYSTEM_UID) {
510 // Only system_server can use INSTALL_DISABLE_VERIFICATION.
511 params.installFlags &= ~PackageManager.INSTALL_DISABLE_VERIFICATION;
512 }
513
Nikita Ioffe4501c112019-02-22 11:51:09 +0000514 boolean isApex = (params.installFlags & PackageManager.INSTALL_APEX) != 0;
515 if (params.isStaged || isApex) {
Dario Freni77786d92019-02-08 17:26:05 +0000516 mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, TAG);
517 }
518
Nikita Ioffe4501c112019-02-22 11:51:09 +0000519 if (isApex) {
Dario Freni83620602019-02-18 14:30:57 +0000520 if (!mApexManager.isApexSupported()) {
521 throw new IllegalArgumentException(
522 "This device doesn't support the installation of APEX files");
523 }
524 if (!params.isStaged) {
525 throw new IllegalArgumentException(
526 "APEX files can only be installed as part of a staged session.");
527 }
528 }
529
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000530 if (!params.isMultiPackage) {
531 // Only system components can circumvent runtime permissions when installing.
532 if ((params.installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0
533 && mContext.checkCallingOrSelfPermission(Manifest.permission
534 .INSTALL_GRANT_RUNTIME_PERMISSIONS) == PackageManager.PERMISSION_DENIED) {
535 throw new SecurityException("You need the "
536 + "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS permission "
537 + "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag");
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700538 }
539
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000540 // Defensively resize giant app icons
541 if (params.appIcon != null) {
542 final ActivityManager am = (ActivityManager) mContext.getSystemService(
543 Context.ACTIVITY_SERVICE);
544 final int iconSize = am.getLauncherLargeIconSize();
545 if ((params.appIcon.getWidth() > iconSize * 2)
546 || (params.appIcon.getHeight() > iconSize * 2)) {
547 params.appIcon = Bitmap.createScaledBitmap(params.appIcon, iconSize, iconSize,
548 true);
549 }
550 }
Jeff Sharkeyab234092015-06-09 21:42:22 -0700551
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000552 switch (params.mode) {
553 case SessionParams.MODE_FULL_INSTALL:
554 case SessionParams.MODE_INHERIT_EXISTING:
555 break;
556 default:
557 throw new IllegalArgumentException("Invalid install mode: " + params.mode);
558 }
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700559
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000560 // If caller requested explicit location, sanity check it, otherwise
561 // resolve the best internal or adopted location.
562 if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
563 if (!PackageHelper.fitsOnInternal(mContext, params)) {
564 throw new IOException("No suitable internal storage available");
565 }
Patrick Baumannff10c9c2018-12-11 15:17:38 -0800566 } else if ((params.installFlags & PackageManager.INSTALL_FORCE_VOLUME_UUID) != 0) {
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000567 // For now, installs to adopted media are treated as internal from
568 // an install flag point-of-view.
Patrick Baumannfc2851e2018-11-13 15:23:22 -0800569 params.installFlags |= PackageManager.INSTALL_INTERNAL;
Patrick Baumannff10c9c2018-12-11 15:17:38 -0800570 } else {
571 params.installFlags |= PackageManager.INSTALL_INTERNAL;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000572
573 // Resolve best location for install, based on combination of
574 // requested install flags, delta size, and manifest settings.
575 final long ident = Binder.clearCallingIdentity();
576 try {
577 params.volumeUuid = PackageHelper.resolveInstallVolume(mContext, params);
578 } finally {
579 Binder.restoreCallingIdentity(ident);
580 }
Robin Leee812d902014-08-21 16:51:18 +0100581 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700582 }
583
584 final int sessionId;
585 final PackageInstallerSession session;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700586 synchronized (mSessions) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700587 // Sanity check that installer isn't going crazy
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700588 final int activeCount = getSessionCount(mSessions, callingUid);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700589 if (activeCount >= MAX_ACTIVE_SESSIONS) {
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700590 throw new IllegalStateException(
591 "Too many active sessions for UID " + callingUid);
592 }
Narayan Kamatha22a7662017-06-12 13:34:29 +0100593 final int historicalCount = mHistoricalSessionsByInstaller.get(callingUid);
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700594 if (historicalCount >= MAX_HISTORICAL_SESSIONS) {
595 throw new IllegalStateException(
596 "Too many historical sessions for UID " + callingUid);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700597 }
598
Jeff Sharkeya1031142014-07-12 18:09:46 -0700599 sessionId = allocateSessionIdLocked();
Todd Kennedy04918fe2016-07-12 14:07:40 -0700600 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700601
Todd Kennedy04918fe2016-07-12 14:07:40 -0700602 final long createdMillis = System.currentTimeMillis();
603 // We're staging to exactly one location
604 File stageDir = null;
605 String stageCid = null;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000606 if (!params.isMultiPackage) {
607 if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
Dario Frenia8f4b132018-12-30 00:36:49 +0000608 stageDir = buildSessionDir(sessionId, params);
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000609 } else {
610 stageCid = buildExternalStageCid(sessionId);
611 }
Todd Kennedy04918fe2016-07-12 14:07:40 -0700612 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000613 session = new PackageInstallerSession(mInternalCallback, mContext, mPm, this,
Dario Frenibe98c3f2018-12-22 15:25:27 +0000614 mInstallThread.getLooper(), mStagingManager, sessionId, userId,
615 installerPackageName, callingUid, params, createdMillis, stageDir, stageCid, false,
Dario Freni47799f42019-03-13 18:06:24 +0000616 false, false, null, SessionInfo.INVALID_ID, false, false, false,
Dario Frenib6d28962019-01-31 15:52:24 +0000617 SessionInfo.STAGED_SESSION_NO_ERROR, "");
Todd Kennedy04918fe2016-07-12 14:07:40 -0700618
619 synchronized (mSessions) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700620 mSessions.put(sessionId, session);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700621 }
Dario Freniaac4ba42018-12-06 15:47:16 +0000622 if (params.isStaged) {
Dario Frenibe98c3f2018-12-22 15:25:27 +0000623 mStagingManager.createSession(session);
Dario Freniaac4ba42018-12-06 15:47:16 +0000624 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700625
Richard Uhler1c9c5d22019-06-05 13:04:32 +0100626 if ((session.params.installFlags & PackageManager.INSTALL_DRY_RUN) == 0) {
627 mCallbacks.notifySessionCreated(session.sessionId, session.userId);
628 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700629 writeSessionsAsync();
630 return sessionId;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700631 }
632
Nikita Ioffe1962cb12019-03-27 22:59:28 +0000633 private boolean isDowngradeAllowedForCaller(int callingUid) {
634 return callingUid == Process.SYSTEM_UID || callingUid == Process.ROOT_UID
635 || callingUid == Process.SHELL_UID;
636 }
637
Jeff Sharkey381d94b2014-08-24 14:45:56 -0700638 @Override
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700639 public void updateSessionAppIcon(int sessionId, Bitmap appIcon) {
640 synchronized (mSessions) {
641 final PackageInstallerSession session = mSessions.get(sessionId);
642 if (session == null || !isCallingUidOwner(session)) {
643 throw new SecurityException("Caller has no access to session " + sessionId);
644 }
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700645
646 // Defensively resize giant app icons
647 if (appIcon != null) {
648 final ActivityManager am = (ActivityManager) mContext.getSystemService(
649 Context.ACTIVITY_SERVICE);
650 final int iconSize = am.getLauncherLargeIconSize();
651 if ((appIcon.getWidth() > iconSize * 2)
652 || (appIcon.getHeight() > iconSize * 2)) {
653 appIcon = Bitmap.createScaledBitmap(appIcon, iconSize, iconSize, true);
654 }
655 }
656
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700657 session.params.appIcon = appIcon;
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700658 session.params.appIconLastModified = -1;
659
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700660 mInternalCallback.onSessionBadgingChanged(session);
661 }
662 }
663
664 @Override
665 public void updateSessionAppLabel(int sessionId, String appLabel) {
666 synchronized (mSessions) {
667 final PackageInstallerSession session = mSessions.get(sessionId);
668 if (session == null || !isCallingUidOwner(session)) {
669 throw new SecurityException("Caller has no access to session " + sessionId);
670 }
671 session.params.appLabel = appLabel;
672 mInternalCallback.onSessionBadgingChanged(session);
673 }
674 }
675
676 @Override
Jeff Sharkey381d94b2014-08-24 14:45:56 -0700677 public void abandonSession(int sessionId) {
678 synchronized (mSessions) {
679 final PackageInstallerSession session = mSessions.get(sessionId);
680 if (session == null || !isCallingUidOwner(session)) {
681 throw new SecurityException("Caller has no access to session " + sessionId);
682 }
683 session.abandon();
684 }
685 }
686
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700687 @Override
688 public IPackageInstallerSession openSession(int sessionId) {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700689 try {
690 return openSessionInternal(sessionId);
691 } catch (IOException e) {
692 throw ExceptionUtils.wrap(e);
693 }
694 }
695
696 private IPackageInstallerSession openSessionInternal(int sessionId) throws IOException {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700697 synchronized (mSessions) {
698 final PackageInstallerSession session = mSessions.get(sessionId);
Jeff Sharkey381d94b2014-08-24 14:45:56 -0700699 if (session == null || !isCallingUidOwner(session)) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700700 throw new SecurityException("Caller has no access to session " + sessionId);
701 }
Jeff Sharkey742e7902014-08-16 19:09:13 -0700702 session.open();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700703 return session;
704 }
705 }
706
Andreas Gampea36dc622018-02-05 17:19:22 -0800707 @GuardedBy("mSessions")
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700708 private int allocateSessionIdLocked() {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700709 int n = 0;
710 int sessionId;
711 do {
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700712 sessionId = mRandom.nextInt(Integer.MAX_VALUE - 1) + 1;
Todd Kennedy28c4e802016-07-13 13:20:30 -0700713 if (!mAllocatedSessions.get(sessionId, false)) {
714 mAllocatedSessions.put(sessionId, true);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700715 return sessionId;
716 }
717 } while (n++ < 32);
718
719 throw new IllegalStateException("Failed to allocate session ID");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700720 }
721
Dario Frenia8f4b132018-12-30 00:36:49 +0000722 private File getTmpSessionDir(String volumeUuid) {
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700723 return Environment.getDataAppDirectory(volumeUuid);
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700724 }
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700725
Dario Frenia8f4b132018-12-30 00:36:49 +0000726 private File buildTmpSessionDir(int sessionId, String volumeUuid) {
727 final File sessionStagingDir = getTmpSessionDir(volumeUuid);
728 return new File(sessionStagingDir, "vmdl" + sessionId + ".tmp");
729 }
730
731 private File buildSessionDir(int sessionId, SessionParams params) {
732 if (params.isStaged) {
733 final File sessionStagingDir = Environment.getDataStagingDirectory(params.volumeUuid);
734 return new File(sessionStagingDir, "session_" + sessionId);
735 }
736 return buildTmpSessionDir(sessionId, params.volumeUuid);
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700737 }
738
739 static void prepareStageDir(File stageDir) throws IOException {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700740 if (stageDir.exists()) {
741 throw new IOException("Session dir already exists: " + stageDir);
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700742 }
743
744 try {
Dario Frenid8bf22e2018-08-31 14:18:04 +0100745 Os.mkdir(stageDir.getAbsolutePath(), 0775);
746 Os.chmod(stageDir.getAbsolutePath(), 0775);
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700747 } catch (ErrnoException e) {
748 // This purposefully throws if directory already exists
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700749 throw new IOException("Failed to prepare session dir: " + stageDir, e);
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700750 }
751
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700752 if (!SELinux.restorecon(stageDir)) {
753 throw new IOException("Failed to restorecon session dir: " + stageDir);
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700754 }
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700755 }
756
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700757 private String buildExternalStageCid(int sessionId) {
758 return "smdl" + sessionId + ".tmp";
759 }
Jeff Sharkey742e7902014-08-16 19:09:13 -0700760
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700761 @Override
Jeff Sharkeya0907432014-08-15 10:23:11 -0700762 public SessionInfo getSessionInfo(int sessionId) {
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700763 synchronized (mSessions) {
764 final PackageInstallerSession session = mSessions.get(sessionId);
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700765 return session != null ? session.generateInfo() : null;
766 }
767 }
768
769 @Override
Dario Freniaac4ba42018-12-06 15:47:16 +0000770 public ParceledListSlice<SessionInfo> getStagedSessions() {
Dario Frenibe98c3f2018-12-22 15:25:27 +0000771 return mStagingManager.getSessions();
Dario Freniaac4ba42018-12-06 15:47:16 +0000772 }
773
774 @Override
Jeff Sharkey97d47ed2014-10-15 09:19:47 -0700775 public ParceledListSlice<SessionInfo> getAllSessions(int userId) {
Todd Kennedy0eb97382017-10-03 16:57:22 -0700776 mPermissionManager.enforceCrossUserPermission(
777 Binder.getCallingUid(), userId, true, false, "getAllSessions");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700778
Jeff Sharkeya0907432014-08-15 10:23:11 -0700779 final List<SessionInfo> result = new ArrayList<>();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700780 synchronized (mSessions) {
781 for (int i = 0; i < mSessions.size(); i++) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700782 final PackageInstallerSession session = mSessions.valueAt(i);
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000783 if (session.userId == userId && !session.hasParentSessionId()) {
Jeff Sharkeyda1247a2017-06-08 14:13:29 -0600784 result.add(session.generateInfo(false));
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700785 }
786 }
787 }
Jeff Sharkey97d47ed2014-10-15 09:19:47 -0700788 return new ParceledListSlice<>(result);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700789 }
790
791 @Override
Jeff Sharkey97d47ed2014-10-15 09:19:47 -0700792 public ParceledListSlice<SessionInfo> getMySessions(String installerPackageName, int userId) {
Todd Kennedy0eb97382017-10-03 16:57:22 -0700793 mPermissionManager.enforceCrossUserPermission(
794 Binder.getCallingUid(), userId, true, false, "getMySessions");
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700795 mAppOps.checkPackage(Binder.getCallingUid(), installerPackageName);
796
Jeff Sharkeya0907432014-08-15 10:23:11 -0700797 final List<SessionInfo> result = new ArrayList<>();
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700798 synchronized (mSessions) {
799 for (int i = 0; i < mSessions.size(); i++) {
800 final PackageInstallerSession session = mSessions.valueAt(i);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000801
802 SessionInfo info = session.generateInfo(false);
803 if (Objects.equals(info.getInstallerPackageName(), installerPackageName)
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000804 && session.userId == userId && !session.hasParentSessionId()) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000805 result.add(info);
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700806 }
807 }
808 }
Jeff Sharkey97d47ed2014-10-15 09:19:47 -0700809 return new ParceledListSlice<>(result);
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700810 }
811
812 @Override
Svet Ganov67882122016-12-11 16:36:34 -0800813 public void uninstall(VersionedPackage versionedPackage, String callerPackageName, int flags,
Patrick Baumann466ddb52019-04-11 12:43:05 -0700814 IntentSender statusReceiver, int userId) {
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000815 final int callingUid = Binder.getCallingUid();
Todd Kennedy0eb97382017-10-03 16:57:22 -0700816 mPermissionManager.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000817 if ((callingUid != Process.SHELL_UID) && (callingUid != Process.ROOT_UID)) {
818 mAppOps.checkPackage(callingUid, callerPackageName);
819 }
820
Benjamin Franzdabae882017-08-08 12:33:19 +0100821 // Check whether the caller is device owner or affiliated profile owner, in which case we do
822 // it silently.
Benjamin Franzdabae882017-08-08 12:33:19 +0100823 DevicePolicyManagerInternal dpmi =
824 LocalServices.getService(DevicePolicyManagerInternal.class);
Rubin Xufd4a3b42018-12-05 16:03:27 +0000825 final boolean canSilentlyInstallPackage =
826 dpmi != null && dpmi.canSilentlyInstallPackage(callerPackageName, callingUid);
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700827
Jeff Sharkeya0907432014-08-15 10:23:11 -0700828 final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext,
Benjamin Franzdabae882017-08-08 12:33:19 +0100829 statusReceiver, versionedPackage.getPackageName(),
Rubin Xucb924152019-03-28 12:11:17 +0000830 canSilentlyInstallPackage, userId);
Sudheer Shanka72de4dd2016-07-22 15:46:37 -0700831 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES)
832 == PackageManager.PERMISSION_GRANTED) {
Jeff Sharkeyf0600952014-08-07 17:31:53 -0700833 // Sweet, call straight through!
Svet Ganov67882122016-12-11 16:36:34 -0800834 mPm.deletePackageVersioned(versionedPackage, adapter.getBinder(), userId, flags);
Rubin Xufd4a3b42018-12-05 16:03:27 +0000835 } else if (canSilentlyInstallPackage) {
Benjamin Franzdabae882017-08-08 12:33:19 +0100836 // Allow the device owner and affiliated profile owner to silently delete packages
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000837 // Need to clear the calling identity to get DELETE_PACKAGES permission
838 long ident = Binder.clearCallingIdentity();
839 try {
Svet Ganov67882122016-12-11 16:36:34 -0800840 mPm.deletePackageVersioned(versionedPackage, adapter.getBinder(), userId, flags);
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000841 } finally {
842 Binder.restoreCallingIdentity(ident);
843 }
Rubin Xu8b17ad02019-03-07 17:42:37 +0000844 DevicePolicyEventLogger
845 .createEvent(DevicePolicyEnums.UNINSTALL_PACKAGE)
846 .setAdmin(callerPackageName)
847 .write();
Jeff Sharkeyf0600952014-08-07 17:31:53 -0700848 } else {
Philip P. Moltmannd9bb39a2017-09-05 12:41:15 -0700849 ApplicationInfo appInfo = mPm.getApplicationInfo(callerPackageName, 0, userId);
850 if (appInfo.targetSdkVersion >= Build.VERSION_CODES.P) {
851 mContext.enforceCallingOrSelfPermission(Manifest.permission.REQUEST_DELETE_PACKAGES,
852 null);
853 }
854
Jeff Sharkeyf0600952014-08-07 17:31:53 -0700855 // Take a short detour to confirm with user
856 final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
Svet Ganov67882122016-12-11 16:36:34 -0800857 intent.setData(Uri.fromParts("package", versionedPackage.getPackageName(), null));
Jeff Sharkeya0907432014-08-15 10:23:11 -0700858 intent.putExtra(PackageInstaller.EXTRA_CALLBACK, adapter.getBinder().asBinder());
859 adapter.onUserActionRequired(intent);
Jeff Sharkeyf0600952014-08-07 17:31:53 -0700860 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700861 }
862
863 @Override
Chandan Nathe8e463b2019-01-28 15:23:38 +0000864 public void installExistingPackage(String packageName, int installFlags, int installReason,
Philip P. Moltmanna4bd1502019-05-13 17:10:46 -0700865 IntentSender statusReceiver, int userId, List<String> whiteListedPermissions) {
Chandan Nathe8e463b2019-01-28 15:23:38 +0000866 mPm.installExistingPackageAsUser(packageName, userId, installFlags, installReason,
Philip P. Moltmanna4bd1502019-05-13 17:10:46 -0700867 whiteListedPermissions, statusReceiver);
Chandan Nathe8e463b2019-01-28 15:23:38 +0000868 }
869
870 @Override
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700871 public void setPermissionsResult(int sessionId, boolean accepted) {
872 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, TAG);
873
874 synchronized (mSessions) {
Svet Ganov3baa8762016-04-08 09:22:54 -0700875 PackageInstallerSession session = mSessions.get(sessionId);
876 if (session != null) {
877 session.setPermissionsResult(accepted);
878 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700879 }
880 }
881
882 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700883 public void registerCallback(IPackageInstallerCallback callback, int userId) {
Todd Kennedy0eb97382017-10-03 16:57:22 -0700884 mPermissionManager.enforceCrossUserPermission(
885 Binder.getCallingUid(), userId, true, false, "registerCallback");
Jon Miranda2b340a22019-01-25 14:03:49 -0800886 registerCallback(callback, eventUserId -> userId == eventUserId);
887 }
888
889 /**
890 * Assume permissions already checked and caller's identity cleared
891 */
892 public void registerCallback(IPackageInstallerCallback callback, IntPredicate userCheck) {
893 mCallbacks.register(callback, userCheck);
Jeff Sharkeybb580672014-07-10 12:10:25 -0700894 }
895
896 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700897 public void unregisterCallback(IPackageInstallerCallback callback) {
898 mCallbacks.unregister(callback);
Jeff Sharkeya1031142014-07-12 18:09:46 -0700899 }
900
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000901 @Override
902 public PackageInstallerSession getSession(int sessionId) {
903 synchronized (mSessions) {
904 return mSessions.get(sessionId);
905 }
906 }
907
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700908 private static int getSessionCount(SparseArray<PackageInstallerSession> sessions,
909 int installerUid) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700910 int count = 0;
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700911 final int size = sessions.size();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700912 for (int i = 0; i < size; i++) {
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700913 final PackageInstallerSession session = sessions.valueAt(i);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000914 if (session.getInstallerUid() == installerUid) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700915 count++;
916 }
917 }
918 return count;
919 }
920
921 private boolean isCallingUidOwner(PackageInstallerSession session) {
922 final int callingUid = Binder.getCallingUid();
923 if (callingUid == Process.ROOT_UID) {
924 return true;
925 } else {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000926 return (session != null) && (callingUid == session.getInstallerUid());
Jeff Sharkeya1031142014-07-12 18:09:46 -0700927 }
928 }
929
Jeff Sharkeya0907432014-08-15 10:23:11 -0700930 static class PackageDeleteObserverAdapter extends PackageDeleteObserver {
931 private final Context mContext;
932 private final IntentSender mTarget;
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700933 private final String mPackageName;
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000934 private final Notification mNotification;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700935
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700936 public PackageDeleteObserverAdapter(Context context, IntentSender target,
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000937 String packageName, boolean showNotification, int userId) {
Jeff Sharkeya0907432014-08-15 10:23:11 -0700938 mContext = context;
939 mTarget = target;
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700940 mPackageName = packageName;
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000941 if (showNotification) {
942 mNotification = buildSuccessNotification(mContext,
943 mContext.getResources().getString(R.string.package_deleted_device_owner),
944 packageName,
945 userId);
946 } else {
947 mNotification = null;
948 }
Jeff Sharkeya0907432014-08-15 10:23:11 -0700949 }
950
951 @Override
952 public void onUserActionRequired(Intent intent) {
Patrick Baumann466ddb52019-04-11 12:43:05 -0700953 if (mTarget == null) {
954 return;
955 }
Jeff Sharkeya0907432014-08-15 10:23:11 -0700956 final Intent fillIn = new Intent();
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700957 fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName);
Jeff Sharkeya0907432014-08-15 10:23:11 -0700958 fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
Jeff Sharkey742e7902014-08-16 19:09:13 -0700959 PackageInstaller.STATUS_PENDING_USER_ACTION);
Jeff Sharkeya0907432014-08-15 10:23:11 -0700960 fillIn.putExtra(Intent.EXTRA_INTENT, intent);
961 try {
962 mTarget.sendIntent(mContext, 0, fillIn, null, null);
963 } catch (SendIntentException ignored) {
964 }
965 }
966
967 @Override
968 public void onPackageDeleted(String basePackageName, int returnCode, String msg) {
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000969 if (PackageManager.DELETE_SUCCEEDED == returnCode && mNotification != null) {
970 NotificationManager notificationManager = (NotificationManager)
971 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
Chris Wren282cfef2017-03-27 15:01:44 -0400972 notificationManager.notify(basePackageName,
973 SystemMessage.NOTE_PACKAGE_STATE,
974 mNotification);
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000975 }
Patrick Baumann466ddb52019-04-11 12:43:05 -0700976 if (mTarget == null) {
977 return;
978 }
Jeff Sharkeya0907432014-08-15 10:23:11 -0700979 final Intent fillIn = new Intent();
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700980 fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName);
Jeff Sharkeya0907432014-08-15 10:23:11 -0700981 fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
982 PackageManager.deleteStatusToPublicStatus(returnCode));
983 fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
984 PackageManager.deleteStatusToString(returnCode, msg));
985 fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode);
986 try {
987 mTarget.sendIntent(mContext, 0, fillIn, null, null);
988 } catch (SendIntentException ignored) {
989 }
990 }
991 }
992
993 static class PackageInstallObserverAdapter extends PackageInstallObserver {
994 private final Context mContext;
995 private final IntentSender mTarget;
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700996 private final int mSessionId;
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000997 private final boolean mShowNotification;
998 private final int mUserId;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700999
Benjamin Franz39fb7fd2015-02-18 16:11:18 +00001000 public PackageInstallObserverAdapter(Context context, IntentSender target, int sessionId,
1001 boolean showNotification, int userId) {
Jeff Sharkeya0907432014-08-15 10:23:11 -07001002 mContext = context;
1003 mTarget = target;
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -07001004 mSessionId = sessionId;
Benjamin Franz39fb7fd2015-02-18 16:11:18 +00001005 mShowNotification = showNotification;
1006 mUserId = userId;
Jeff Sharkeya0907432014-08-15 10:23:11 -07001007 }
1008
1009 @Override
1010 public void onUserActionRequired(Intent intent) {
1011 final Intent fillIn = new Intent();
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -07001012 fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId);
Jeff Sharkeya0907432014-08-15 10:23:11 -07001013 fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
Jeff Sharkey742e7902014-08-16 19:09:13 -07001014 PackageInstaller.STATUS_PENDING_USER_ACTION);
Jeff Sharkeya0907432014-08-15 10:23:11 -07001015 fillIn.putExtra(Intent.EXTRA_INTENT, intent);
1016 try {
1017 mTarget.sendIntent(mContext, 0, fillIn, null, null);
1018 } catch (SendIntentException ignored) {
1019 }
1020 }
1021
1022 @Override
1023 public void onPackageInstalled(String basePackageName, int returnCode, String msg,
1024 Bundle extras) {
Benjamin Franz39fb7fd2015-02-18 16:11:18 +00001025 if (PackageManager.INSTALL_SUCCEEDED == returnCode && mShowNotification) {
Benjamin Franz2e3e9432015-04-17 15:28:17 +01001026 boolean update = (extras != null) && extras.getBoolean(Intent.EXTRA_REPLACING);
Benjamin Franz39fb7fd2015-02-18 16:11:18 +00001027 Notification notification = buildSuccessNotification(mContext,
Benjamin Franz2e3e9432015-04-17 15:28:17 +01001028 mContext.getResources()
1029 .getString(update ? R.string.package_updated_device_owner :
1030 R.string.package_installed_device_owner),
Benjamin Franz39fb7fd2015-02-18 16:11:18 +00001031 basePackageName,
1032 mUserId);
1033 if (notification != null) {
1034 NotificationManager notificationManager = (NotificationManager)
1035 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
Chris Wren282cfef2017-03-27 15:01:44 -04001036 notificationManager.notify(basePackageName,
1037 SystemMessage.NOTE_PACKAGE_STATE,
1038 notification);
Benjamin Franz39fb7fd2015-02-18 16:11:18 +00001039 }
1040 }
Jeff Sharkeya0907432014-08-15 10:23:11 -07001041 final Intent fillIn = new Intent();
Benjamin Franz2e3e9432015-04-17 15:28:17 +01001042 fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, basePackageName);
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -07001043 fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId);
Jeff Sharkeya0907432014-08-15 10:23:11 -07001044 fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
1045 PackageManager.installStatusToPublicStatus(returnCode));
1046 fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
1047 PackageManager.installStatusToString(returnCode, msg));
1048 fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode);
1049 if (extras != null) {
1050 final String existing = extras.getString(
1051 PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE);
1052 if (!TextUtils.isEmpty(existing)) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001053 fillIn.putExtra(PackageInstaller.EXTRA_OTHER_PACKAGE_NAME, existing);
Jeff Sharkeya0907432014-08-15 10:23:11 -07001054 }
1055 }
1056 try {
1057 mTarget.sendIntent(mContext, 0, fillIn, null, null);
1058 } catch (SendIntentException ignored) {
1059 }
1060 }
1061 }
1062
Benjamin Franz39fb7fd2015-02-18 16:11:18 +00001063 /**
1064 * Build a notification for package installation / deletion by device owners that is shown if
1065 * the operation succeeds.
1066 */
1067 private static Notification buildSuccessNotification(Context context, String contentText,
1068 String basePackageName, int userId) {
1069 PackageInfo packageInfo = null;
1070 try {
1071 packageInfo = AppGlobals.getPackageManager().getPackageInfo(
Svet Ganova5c867c2017-05-15 01:17:05 -07001072 basePackageName, PackageManager.MATCH_STATIC_SHARED_LIBRARIES, userId);
Benjamin Franz39fb7fd2015-02-18 16:11:18 +00001073 } catch (RemoteException ignored) {
1074 }
1075 if (packageInfo == null || packageInfo.applicationInfo == null) {
1076 Slog.w(TAG, "Notification not built for package: " + basePackageName);
1077 return null;
1078 }
1079 PackageManager pm = context.getPackageManager();
1080 Bitmap packageIcon = ImageUtils.buildScaledBitmap(
1081 packageInfo.applicationInfo.loadIcon(pm),
1082 context.getResources().getDimensionPixelSize(
1083 android.R.dimen.notification_large_icon_width),
1084 context.getResources().getDimensionPixelSize(
1085 android.R.dimen.notification_large_icon_height));
1086 CharSequence packageLabel = packageInfo.applicationInfo.loadLabel(pm);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05001087 return new Notification.Builder(context, SystemNotificationChannels.DEVICE_ADMIN)
Benjamin Franz39fb7fd2015-02-18 16:11:18 +00001088 .setSmallIcon(R.drawable.ic_check_circle_24px)
1089 .setColor(context.getResources().getColor(
1090 R.color.system_notification_accent_color))
1091 .setContentTitle(packageLabel)
1092 .setContentText(contentText)
Benjamin Franz2e3e9432015-04-17 15:28:17 +01001093 .setStyle(new Notification.BigTextStyle().bigText(contentText))
Benjamin Franz39fb7fd2015-02-18 16:11:18 +00001094 .setLargeIcon(packageIcon)
1095 .build();
1096 }
1097
Jeff Sharkey54d42be2015-07-20 16:36:55 -07001098 public static <E> ArraySet<E> newArraySet(E... elements) {
1099 final ArraySet<E> set = new ArraySet<E>();
1100 if (elements != null) {
1101 set.ensureCapacity(elements.length);
1102 Collections.addAll(set, elements);
1103 }
1104 return set;
1105 }
1106
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001107 private static class Callbacks extends Handler {
1108 private static final int MSG_SESSION_CREATED = 1;
Jeff Sharkeyec9bad22014-09-05 09:45:20 -07001109 private static final int MSG_SESSION_BADGING_CHANGED = 2;
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001110 private static final int MSG_SESSION_ACTIVE_CHANGED = 3;
Jeff Sharkeyec9bad22014-09-05 09:45:20 -07001111 private static final int MSG_SESSION_PROGRESS_CHANGED = 4;
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001112 private static final int MSG_SESSION_FINISHED = 5;
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07001113
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001114 private final RemoteCallbackList<IPackageInstallerCallback>
1115 mCallbacks = new RemoteCallbackList<>();
Jeff Sharkeya1031142014-07-12 18:09:46 -07001116
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001117 public Callbacks(Looper looper) {
1118 super(looper);
1119 }
1120
Jon Miranda2b340a22019-01-25 14:03:49 -08001121 public void register(IPackageInstallerCallback callback, IntPredicate userCheck) {
1122 mCallbacks.register(callback, userCheck);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001123 }
1124
1125 public void unregister(IPackageInstallerCallback callback) {
1126 mCallbacks.unregister(callback);
1127 }
1128
1129 @Override
1130 public void handleMessage(Message msg) {
1131 final int userId = msg.arg2;
1132 final int n = mCallbacks.beginBroadcast();
1133 for (int i = 0; i < n; i++) {
1134 final IPackageInstallerCallback callback = mCallbacks.getBroadcastItem(i);
Jon Miranda2b340a22019-01-25 14:03:49 -08001135 final IntPredicate userCheck = (IntPredicate) mCallbacks.getBroadcastCookie(i);
1136 if (userCheck.test(userId)) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001137 try {
1138 invokeCallback(callback, msg);
1139 } catch (RemoteException ignored) {
1140 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07001141 }
1142 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001143 mCallbacks.finishBroadcast();
Jeff Sharkeya1031142014-07-12 18:09:46 -07001144 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001145
1146 private void invokeCallback(IPackageInstallerCallback callback, Message msg)
1147 throws RemoteException {
1148 final int sessionId = msg.arg1;
1149 switch (msg.what) {
1150 case MSG_SESSION_CREATED:
1151 callback.onSessionCreated(sessionId);
1152 break;
Jeff Sharkeyec9bad22014-09-05 09:45:20 -07001153 case MSG_SESSION_BADGING_CHANGED:
1154 callback.onSessionBadgingChanged(sessionId);
1155 break;
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001156 case MSG_SESSION_ACTIVE_CHANGED:
1157 callback.onSessionActiveChanged(sessionId, (boolean) msg.obj);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001158 break;
1159 case MSG_SESSION_PROGRESS_CHANGED:
1160 callback.onSessionProgressChanged(sessionId, (float) msg.obj);
1161 break;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001162 case MSG_SESSION_FINISHED:
1163 callback.onSessionFinished(sessionId, (boolean) msg.obj);
1164 break;
1165 }
1166 }
1167
1168 private void notifySessionCreated(int sessionId, int userId) {
1169 obtainMessage(MSG_SESSION_CREATED, sessionId, userId).sendToTarget();
1170 }
1171
Jeff Sharkeyec9bad22014-09-05 09:45:20 -07001172 private void notifySessionBadgingChanged(int sessionId, int userId) {
1173 obtainMessage(MSG_SESSION_BADGING_CHANGED, sessionId, userId).sendToTarget();
1174 }
1175
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001176 private void notifySessionActiveChanged(int sessionId, int userId, boolean active) {
1177 obtainMessage(MSG_SESSION_ACTIVE_CHANGED, sessionId, userId, active).sendToTarget();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001178 }
1179
1180 private void notifySessionProgressChanged(int sessionId, int userId, float progress) {
1181 obtainMessage(MSG_SESSION_PROGRESS_CHANGED, sessionId, userId, progress).sendToTarget();
1182 }
1183
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001184 public void notifySessionFinished(int sessionId, int userId, boolean success) {
1185 obtainMessage(MSG_SESSION_FINISHED, sessionId, userId, success).sendToTarget();
1186 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07001187 }
1188
1189 void dump(IndentingPrintWriter pw) {
Jeff Sharkeya1031142014-07-12 18:09:46 -07001190 synchronized (mSessions) {
Jeff Sharkey9a445772014-07-16 11:32:08 -07001191 pw.println("Active install sessions:");
1192 pw.increaseIndent();
1193 int N = mSessions.size();
Jeff Sharkeya1031142014-07-12 18:09:46 -07001194 for (int i = 0; i < N; i++) {
1195 final PackageInstallerSession session = mSessions.valueAt(i);
1196 session.dump(pw);
1197 pw.println();
1198 }
Jeff Sharkey9a445772014-07-16 11:32:08 -07001199 pw.println();
1200 pw.decreaseIndent();
1201
1202 pw.println("Historical install sessions:");
1203 pw.increaseIndent();
1204 N = mHistoricalSessions.size();
1205 for (int i = 0; i < N; i++) {
Narayan Kamatha22a7662017-06-12 13:34:29 +01001206 pw.print(mHistoricalSessions.get(i));
Jeff Sharkey9a445772014-07-16 11:32:08 -07001207 pw.println();
1208 }
1209 pw.println();
1210 pw.decreaseIndent();
Jeff Sharkey742e7902014-08-16 19:09:13 -07001211
1212 pw.println("Legacy install sessions:");
1213 pw.increaseIndent();
1214 pw.println(mLegacySessions.toString());
1215 pw.decreaseIndent();
Jeff Sharkeya1031142014-07-12 18:09:46 -07001216 }
Jeff Sharkeybb580672014-07-10 12:10:25 -07001217 }
1218
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001219 class InternalCallback {
Jeff Sharkeyec9bad22014-09-05 09:45:20 -07001220 public void onSessionBadgingChanged(PackageInstallerSession session) {
Richard Uhler1c9c5d22019-06-05 13:04:32 +01001221 if ((session.params.installFlags & PackageManager.INSTALL_DRY_RUN) == 0) {
1222 mCallbacks.notifySessionBadgingChanged(session.sessionId, session.userId);
1223 }
1224
Jeff Sharkeyec9bad22014-09-05 09:45:20 -07001225 writeSessionsAsync();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001226 }
1227
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001228 public void onSessionActiveChanged(PackageInstallerSession session, boolean active) {
Richard Uhler1c9c5d22019-06-05 13:04:32 +01001229 if ((session.params.installFlags & PackageManager.INSTALL_DRY_RUN) == 0) {
1230 mCallbacks.notifySessionActiveChanged(session.sessionId, session.userId,
1231 active);
1232 }
Jeff Sharkey742e7902014-08-16 19:09:13 -07001233 }
1234
Jeff Sharkeyec9bad22014-09-05 09:45:20 -07001235 public void onSessionProgressChanged(PackageInstallerSession session, float progress) {
Richard Uhler1c9c5d22019-06-05 13:04:32 +01001236 if ((session.params.installFlags & PackageManager.INSTALL_DRY_RUN) == 0) {
1237 mCallbacks.notifySessionProgressChanged(session.sessionId, session.userId,
1238 progress);
1239 }
Jeff Sharkeyec9bad22014-09-05 09:45:20 -07001240 }
1241
Dario Freni0180d0b2019-01-11 21:08:13 +00001242 public void onStagedSessionChanged(PackageInstallerSession session) {
Gavin Corkeryd8311212019-02-22 17:52:30 +00001243 session.markUpdated();
Dario Freni0180d0b2019-01-11 21:08:13 +00001244 writeSessionsAsync();
Dario Freni14f885b2019-02-25 12:48:47 +00001245 if (mOkToSendBroadcasts) {
Dario Freni9694b802019-01-27 23:26:06 +00001246 mPm.sendSessionUpdatedBroadcast(session.generateInfo(false),
1247 session.userId);
1248 }
Dario Freni0180d0b2019-01-11 21:08:13 +00001249 }
1250
Jeff Sharkeycbf47912014-09-12 09:55:32 -07001251 public void onSessionFinished(final PackageInstallerSession session, boolean success) {
Richard Uhler1c9c5d22019-06-05 13:04:32 +01001252 if ((session.params.installFlags & PackageManager.INSTALL_DRY_RUN) == 0) {
1253 mCallbacks.notifySessionFinished(session.sessionId, session.userId, success);
1254 }
Jeff Sharkeycbf47912014-09-12 09:55:32 -07001255
1256 mInstallHandler.post(new Runnable() {
1257 @Override
1258 public void run() {
Dario Freniaac4ba42018-12-06 15:47:16 +00001259 if (session.isStaged()) {
Dario Freniaac4ba42018-12-06 15:47:16 +00001260 if (!success) {
Dario Frenibe98c3f2018-12-22 15:25:27 +00001261 mStagingManager.abortSession(session);
Dario Freniaac4ba42018-12-06 15:47:16 +00001262 }
1263 }
Jeff Sharkeycbf47912014-09-12 09:55:32 -07001264 synchronized (mSessions) {
Dario Freni8e7d0ec2019-01-10 15:21:40 +00001265 if (!session.isStaged() || !success) {
1266 mSessions.remove(session.sessionId);
1267 }
Narayan Kamatha22a7662017-06-12 13:34:29 +01001268 addHistoricalSessionLocked(session);
Jeff Sharkey02bd7842014-10-06 15:14:27 -07001269
1270 final File appIconFile = buildAppIconFile(session.sessionId);
1271 if (appIconFile.exists()) {
1272 appIconFile.delete();
1273 }
1274
Jeff Sharkeycbf47912014-09-12 09:55:32 -07001275 writeSessionsLocked();
1276 }
1277 }
1278 });
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001279 }
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -07001280
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001281 public void onSessionPrepared(PackageInstallerSession session) {
1282 // We prepared the destination to write into; we want to persist
1283 // this, but it's not critical enough to block for.
1284 writeSessionsAsync();
1285 }
1286
Jeff Sharkeycbf47912014-09-12 09:55:32 -07001287 public void onSessionSealedBlocking(PackageInstallerSession session) {
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -07001288 // It's very important that we block until we've recorded the
1289 // session as being sealed, since we never want to allow mutation
1290 // after sealing.
Jeff Sharkeycbf47912014-09-12 09:55:32 -07001291 synchronized (mSessions) {
1292 writeSessionsLocked();
1293 }
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -07001294 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001295 }
1296}