blob: 93249e9e311c3c41da5e5e48c05d8079f210e179 [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;
Rubin Xu8b17ad02019-03-07 17:42:37 +000029import android.app.admin.DevicePolicyEventLogger;
Benjamin Franzdabae882017-08-08 12:33:19 +010030import android.app.admin.DevicePolicyManagerInternal;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070031import android.content.Context;
Jeff Sharkeyf0600952014-08-07 17:31:53 -070032import android.content.Intent;
Jeff Sharkeya0907432014-08-15 10:23:11 -070033import android.content.IntentSender;
34import android.content.IntentSender.SendIntentException;
Philip P. Moltmannd9bb39a2017-09-05 12:41:15 -070035import android.content.pm.ApplicationInfo;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070036import android.content.pm.IPackageInstaller;
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -070037import android.content.pm.IPackageInstallerCallback;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070038import android.content.pm.IPackageInstallerSession;
Benjamin Franz39fb7fd2015-02-18 16:11:18 +000039import android.content.pm.PackageInfo;
Jeff Sharkeyf0600952014-08-07 17:31:53 -070040import android.content.pm.PackageInstaller;
Jeff Sharkeya0907432014-08-15 10:23:11 -070041import android.content.pm.PackageInstaller.SessionInfo;
42import android.content.pm.PackageInstaller.SessionParams;
Jeff Sharkeyec9bad22014-09-05 09:45:20 -070043import android.content.pm.PackageManager;
Jeff Sharkey97d47ed2014-10-15 09:19:47 -070044import android.content.pm.ParceledListSlice;
Svet Ganov67882122016-12-11 16:36:34 -080045import android.content.pm.VersionedPackage;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070046import android.graphics.Bitmap;
Jeff Sharkeyf0600952014-08-07 17:31:53 -070047import android.net.Uri;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070048import android.os.Binder;
Philip P. Moltmannd9bb39a2017-09-05 12:41:15 -070049import android.os.Build;
Jeff Sharkeya0907432014-08-15 10:23:11 -070050import android.os.Bundle;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070051import android.os.Environment;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070052import android.os.Handler;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070053import android.os.HandlerThread;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070054import android.os.Looper;
55import android.os.Message;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070056import android.os.Process;
Jeff Sharkeya1031142014-07-12 18:09:46 -070057import android.os.RemoteCallbackList;
58import android.os.RemoteException;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -070059import android.os.SELinux;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070060import android.os.UserManager;
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -070061import android.os.storage.StorageManager;
Rubin Xu8b17ad02019-03-07 17:42:37 +000062import android.stats.devicepolicy.DevicePolicyEnums;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -070063import android.system.ErrnoException;
64import android.system.Os;
Jeff Sharkeya0907432014-08-15 10:23:11 -070065import android.text.TextUtils;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070066import android.text.format.DateUtils;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070067import android.util.ArraySet;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070068import android.util.AtomicFile;
Jeff Sharkeya1031142014-07-12 18:09:46 -070069import android.util.ExceptionUtils;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070070import android.util.Slog;
71import android.util.SparseArray;
Jeff Sharkey742e7902014-08-16 19:09:13 -070072import android.util.SparseBooleanArray;
Narayan Kamatha22a7662017-06-12 13:34:29 +010073import android.util.SparseIntArray;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070074import android.util.Xml;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070075
Benjamin Franz39fb7fd2015-02-18 16:11:18 +000076import com.android.internal.R;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070077import com.android.internal.annotations.GuardedBy;
Jeff Sharkey742e7902014-08-16 19:09:13 -070078import com.android.internal.content.PackageHelper;
Chris Wren282cfef2017-03-27 15:01:44 -040079import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
Geoffrey Pitschaf759c52017-02-15 09:35:38 -050080import com.android.internal.notification.SystemNotificationChannels;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070081import com.android.internal.util.FastXmlSerializer;
Benjamin Franz39fb7fd2015-02-18 16:11:18 +000082import com.android.internal.util.ImageUtils;
Jeff Sharkeya1031142014-07-12 18:09:46 -070083import com.android.internal.util.IndentingPrintWriter;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070084import com.android.server.IoThread;
Todd Kennedy0eb97382017-10-03 16:57:22 -070085import com.android.server.LocalServices;
Philip P. Moltmann48456672019-01-20 13:14:03 -080086import com.android.server.pm.permission.PermissionManagerServiceInternal;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070087
Philip P. Moltmann7460c592017-08-08 20:07:11 +000088import libcore.io.IoUtils;
89
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070090import org.xmlpull.v1.XmlPullParser;
91import org.xmlpull.v1.XmlPullParserException;
92import org.xmlpull.v1.XmlSerializer;
93
Philip P. Moltmann7460c592017-08-08 20:07:11 +000094import java.io.CharArrayWriter;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070095import java.io.File;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070096import java.io.FileInputStream;
97import java.io.FileNotFoundException;
98import java.io.FileOutputStream;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -070099import java.io.FilenameFilter;
100import java.io.IOException;
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +0100101import java.nio.charset.StandardCharsets;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700102import java.security.SecureRandom;
Jeff Sharkeybb580672014-07-10 12:10:25 -0700103import java.util.ArrayList;
Jeff Sharkey54d42be2015-07-20 16:36:55 -0700104import java.util.Collections;
Jeff Sharkeybb580672014-07-10 12:10:25 -0700105import java.util.List;
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700106import java.util.Objects;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700107import java.util.Random;
Jon Miranda2b340a22019-01-25 14:03:49 -0800108import java.util.function.IntPredicate;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700109
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000110/** The service responsible for installing packages. */
111public class PackageInstallerService extends IPackageInstaller.Stub implements
112 PackageSessionProvider {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700113 private static final String TAG = "PackageInstaller";
Jeff Sharkeye9808042014-09-11 21:15:37 -0700114 private static final boolean LOGD = false;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700115
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700116 // TODO: remove outstanding sessions when installer package goes away
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700117 // TODO: notify listeners in other users when package has been installed there
Jeff Sharkey742e7902014-08-16 19:09:13 -0700118 // TODO: purge expired sessions periodically in addition to at reboot
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700119
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700120 /** XML constants used in {@link #mSessionsFile} */
121 private static final String TAG_SESSIONS = "sessions";
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700122
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700123 /** Automatically destroy sessions older than this */
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700124 private static final long MAX_AGE_MILLIS = 3 * DateUtils.DAY_IN_MILLIS;
Gavin Corkeryd8311212019-02-22 17:52:30 +0000125 /** Automatically destroy staged sessions that have not changed state in this time */
126 private static final long MAX_TIME_SINCE_UPDATE_MILLIS = 7 * DateUtils.DAY_IN_MILLIS;
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700127 /** Upper bound on number of active sessions for a UID */
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700128 private static final long MAX_ACTIVE_SESSIONS = 1024;
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700129 /** Upper bound on number of historical sessions for a UID */
130 private static final long MAX_HISTORICAL_SESSIONS = 1048576;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700131
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700132 private final Context mContext;
133 private final PackageManagerService mPm;
Dario Freni83620602019-02-18 14:30:57 +0000134 private final ApexManager mApexManager;
Dario Frenibe98c3f2018-12-22 15:25:27 +0000135 private final StagingManager mStagingManager;
Philip P. Moltmann48456672019-01-20 13:14:03 -0800136 private final PermissionManagerServiceInternal mPermissionManager;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700137
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700138 private AppOpsManager mAppOps;
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700139
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700140 private final HandlerThread mInstallThread;
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700141 private final Handler mInstallHandler;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700142
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700143 private final Callbacks mCallbacks;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700144
Dario Freni14f885b2019-02-25 12:48:47 +0000145 private volatile boolean mOkToSendBroadcasts = false;
Dario Freni9694b802019-01-27 23:26:06 +0000146
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700147 /**
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700148 * File storing persisted {@link #mSessions} metadata.
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700149 */
150 private final AtomicFile mSessionsFile;
151
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700152 /**
153 * Directory storing persisted {@link #mSessions} metadata which is too
154 * heavy to store directly in {@link #mSessionsFile}.
155 */
156 private final File mSessionsDir;
157
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700158 private final InternalCallback mInternalCallback = new InternalCallback();
159
160 /**
161 * Used for generating session IDs. Since this is created at boot time,
162 * normal random might be predictable.
163 */
164 private final Random mRandom = new SecureRandom();
165
Todd Kennedy28c4e802016-07-13 13:20:30 -0700166 /** All sessions allocated */
167 @GuardedBy("mSessions")
168 private final SparseBooleanArray mAllocatedSessions = new SparseBooleanArray();
169
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700170 @GuardedBy("mSessions")
171 private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>();
172
Jeff Sharkey9a445772014-07-16 11:32:08 -0700173 /** Historical sessions kept around for debugging purposes */
174 @GuardedBy("mSessions")
Narayan Kamatha22a7662017-06-12 13:34:29 +0100175 private final List<String> mHistoricalSessions = new ArrayList<>();
176
177 @GuardedBy("mSessions")
178 private final SparseIntArray mHistoricalSessionsByInstaller = new SparseIntArray();
Jeff Sharkey9a445772014-07-16 11:32:08 -0700179
Jeff Sharkey742e7902014-08-16 19:09:13 -0700180 /** Sessions allocated to legacy users */
181 @GuardedBy("mSessions")
182 private final SparseBooleanArray mLegacySessions = new SparseBooleanArray();
183
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700184 private static final FilenameFilter sStageFilter = new FilenameFilter() {
185 @Override
186 public boolean accept(File dir, String name) {
Jeff Sharkey742e7902014-08-16 19:09:13 -0700187 return isStageName(name);
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700188 }
189 };
190
Dario Freni2e8dffc2019-02-06 14:55:16 +0000191 public PackageInstallerService(Context context, PackageManagerService pm, ApexManager am) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700192 mContext = context;
193 mPm = pm;
Philip P. Moltmann48456672019-01-20 13:14:03 -0800194 mPermissionManager = LocalServices.getService(PermissionManagerServiceInternal.class);
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700195
196 mInstallThread = new HandlerThread(TAG);
197 mInstallThread.start();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700198
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700199 mInstallHandler = new Handler(mInstallThread.getLooper());
200
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700201 mCallbacks = new Callbacks(mInstallThread.getLooper());
202
203 mSessionsFile = new AtomicFile(
Dianne Hackborne17b4452018-01-10 13:15:40 -0800204 new File(Environment.getDataSystemDirectory(), "install_sessions.xml"),
205 "package-session");
Jeff Sharkey8212ae02016-02-10 14:46:43 -0700206 mSessionsDir = new File(Environment.getDataSystemDirectory(), "install_sessions");
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700207 mSessionsDir.mkdirs();
Dario Frenibe98c3f2018-12-22 15:25:27 +0000208
Dario Freni83620602019-02-18 14:30:57 +0000209 mApexManager = am;
Nikita Ioffe39a6a5b2019-02-26 15:36:39 +0000210
Nikita Ioffe1a7965e2019-03-12 22:32:41 +0000211 mStagingManager = new StagingManager(this, am, context);
Tony Mak606f8e72017-02-15 18:40:03 +0000212 }
213
Dario Freni14f885b2019-02-25 12:48:47 +0000214 boolean okToSendBroadcasts() {
215 return mOkToSendBroadcasts;
Dario Freni4b572c02019-01-29 09:40:31 +0000216 }
217
Tony Mak606f8e72017-02-15 18:40:03 +0000218 public void systemReady() {
219 mAppOps = mContext.getSystemService(AppOpsManager.class);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700220
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700221 synchronized (mSessions) {
222 readSessionsLocked();
223
Dario Frenia8f4b132018-12-30 00:36:49 +0000224 reconcileStagesLocked(StorageManager.UUID_PRIVATE_INTERNAL);
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700225
Jeff Sharkey54d42be2015-07-20 16:36:55 -0700226 final ArraySet<File> unclaimedIcons = newArraySet(
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700227 mSessionsDir.listFiles());
Jeff Sharkey742e7902014-08-16 19:09:13 -0700228
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700229 // Ignore stages and icons claimed by active sessions
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700230 for (int i = 0; i < mSessions.size(); i++) {
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700231 final PackageInstallerSession session = mSessions.valueAt(i);
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700232 unclaimedIcons.remove(buildAppIconFile(session.sessionId));
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700233 }
Jeff Sharkey742e7902014-08-16 19:09:13 -0700234
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700235 // Clean up orphaned icons
236 for (File icon : unclaimedIcons) {
237 Slog.w(TAG, "Deleting orphan icon " + icon);
238 icon.delete();
239 }
Dario Freni0180d0b2019-01-11 21:08:13 +0000240
241 // Invalid sessions might have been marked while parsing. Re-write the database with
242 // the updated information.
243 writeSessionsLocked();
244
Dario Freni4b572c02019-01-29 09:40:31 +0000245 }
246 }
247
248 void restoreAndApplyStagedSessionIfNeeded() {
249 List<PackageInstallerSession> stagedSessionsToRestore = new ArrayList<>();
250 synchronized (mSessions) {
Dario Freni0180d0b2019-01-11 21:08:13 +0000251 for (int i = 0; i < mSessions.size(); i++) {
252 final PackageInstallerSession session = mSessions.valueAt(i);
253 if (session.isStaged()) {
Dario Freni4b572c02019-01-29 09:40:31 +0000254 stagedSessionsToRestore.add(session);
Dario Freni0180d0b2019-01-11 21:08:13 +0000255 }
256 }
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700257 }
Dario Freni4b572c02019-01-29 09:40:31 +0000258 // Don't hold mSessions lock when calling restoreSession, since it might trigger an APK
259 // atomic install which needs to query sessions, which requires lock on mSessions.
260 for (PackageInstallerSession session : stagedSessionsToRestore) {
Gavin Corkery67ce22c2019-10-22 14:55:54 +0100261 if (mPm.isDeviceUpgrading() && !session.isStagedAndInTerminalState()) {
Gavin Corkeryde8174b2019-09-27 15:02:28 +0100262 session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
263 "Build fingerprint has changed");
264 }
Dario Freni4b572c02019-01-29 09:40:31 +0000265 mStagingManager.restoreSession(session);
266 }
Dario Freni14f885b2019-02-25 12:48:47 +0000267 // Broadcasts are not sent while we restore sessions on boot, since no processes would be
268 // ready to listen to them. From now on, we greedily assume that broadcasts requests are
269 // safe to send out. The worst that can happen is that a broadcast is attempted before
270 // ActivityManagerService completes its own systemReady(), in which case it will be rejected
271 // with an otherwise harmless exception.
272 // A more appropriate way to do this would be to wait until the correct boot phase is
273 // reached, but since we are not a SystemService we can't override onBootPhase.
274 // Waiting on the BOOT_COMPLETED broadcast can take several minutes, so that's not a viable
275 // way either.
276 mOkToSendBroadcasts = true;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700277 }
278
Andreas Gampea36dc622018-02-05 17:19:22 -0800279 @GuardedBy("mSessions")
Dario Frenia8f4b132018-12-30 00:36:49 +0000280 private void reconcileStagesLocked(String volumeUuid) {
281 final File stagingDir = getTmpSessionDir(volumeUuid);
Jeff Sharkey54d42be2015-07-20 16:36:55 -0700282 final ArraySet<File> unclaimedStages = newArraySet(
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700283 stagingDir.listFiles(sStageFilter));
284
285 // Ignore stages claimed by active sessions
286 for (int i = 0; i < mSessions.size(); i++) {
287 final PackageInstallerSession session = mSessions.valueAt(i);
288 unclaimedStages.remove(session.stageDir);
289 }
290
291 // Clean up orphaned staging directories
292 for (File stage : unclaimedStages) {
293 Slog.w(TAG, "Deleting orphan stage " + stage);
294 synchronized (mPm.mInstallLock) {
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -0700295 mPm.removeCodePathLI(stage);
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700296 }
297 }
298 }
299
300 public void onPrivateVolumeMounted(String volumeUuid) {
301 synchronized (mSessions) {
Dario Frenia8f4b132018-12-30 00:36:49 +0000302 reconcileStagesLocked(volumeUuid);
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700303 }
304 }
305
Jeff Sharkey742e7902014-08-16 19:09:13 -0700306 public static boolean isStageName(String name) {
307 final boolean isFile = name.startsWith("vmdl") && name.endsWith(".tmp");
308 final boolean isContainer = name.startsWith("smdl") && name.endsWith(".tmp");
309 final boolean isLegacyContainer = name.startsWith("smdl2tmp");
310 return isFile || isContainer || isLegacyContainer;
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700311 }
312
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700313 @Deprecated
Todd Kennedy2699f062015-11-20 13:07:17 -0800314 public File allocateStageDirLegacy(String volumeUuid, boolean isEphemeral) throws IOException {
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700315 synchronized (mSessions) {
316 try {
317 final int sessionId = allocateSessionIdLocked();
Jeff Sharkey742e7902014-08-16 19:09:13 -0700318 mLegacySessions.put(sessionId, true);
Dario Frenia8f4b132018-12-30 00:36:49 +0000319 final File sessionStageDir = buildTmpSessionDir(sessionId, volumeUuid);
320 prepareStageDir(sessionStageDir);
321 return sessionStageDir;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700322 } catch (IllegalStateException e) {
323 throw new IOException(e);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700324 }
325 }
326 }
327
Jeff Sharkey742e7902014-08-16 19:09:13 -0700328 @Deprecated
329 public String allocateExternalStageCidLegacy() {
330 synchronized (mSessions) {
331 final int sessionId = allocateSessionIdLocked();
332 mLegacySessions.put(sessionId, true);
333 return "smdl" + sessionId + ".tmp";
334 }
335 }
336
Andreas Gampea36dc622018-02-05 17:19:22 -0800337 @GuardedBy("mSessions")
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700338 private void readSessionsLocked() {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700339 if (LOGD) Slog.v(TAG, "readSessionsLocked()");
340
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700341 mSessions.clear();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700342
343 FileInputStream fis = null;
344 try {
345 fis = mSessionsFile.openRead();
346 final XmlPullParser in = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +0100347 in.setInput(fis, StandardCharsets.UTF_8.name());
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700348
349 int type;
350 while ((type = in.next()) != END_DOCUMENT) {
351 if (type == START_TAG) {
352 final String tag = in.getName();
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000353 if (PackageInstallerSession.TAG_SESSION.equals(tag)) {
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -0700354 final PackageInstallerSession session;
355 try {
356 session = PackageInstallerSession.readFromXml(in, mInternalCallback,
Dario Frenibe98c3f2018-12-22 15:25:27 +0000357 mContext, mPm, mInstallThread.getLooper(), mStagingManager,
358 mSessionsDir, this);
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -0700359 } catch (Exception e) {
360 Slog.e(TAG, "Could not read session", e);
361 continue;
362 }
363
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700364 final long age = System.currentTimeMillis() - session.createdMillis;
Gavin Corkeryd8311212019-02-22 17:52:30 +0000365 final long timeSinceUpdate =
Gavin Corkery13f81612019-03-20 18:22:58 +0000366 System.currentTimeMillis() - session.getUpdatedMillis();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700367 final boolean valid;
Gavin Corkeryd8311212019-02-22 17:52:30 +0000368 if (session.isStaged()) {
Dario Freni7f5a6952019-05-10 19:40:50 +0100369 if (timeSinceUpdate >= MAX_TIME_SINCE_UPDATE_MILLIS
370 && session.isStagedAndInTerminalState()) {
Gavin Corkeryd8311212019-02-22 17:52:30 +0000371 valid = false;
372 } else {
373 valid = true;
374 }
375 } else if (age >= MAX_AGE_MILLIS) {
376 Slog.w(TAG, "Abandoning old session created at "
377 + session.createdMillis);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700378 valid = false;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700379 } else {
380 valid = true;
381 }
382
383 if (valid) {
384 mSessions.put(session.sessionId, session);
385 } else {
386 // Since this is early during boot we don't send
387 // any observer events about the session, but we
388 // keep details around for dumpsys.
Narayan Kamatha22a7662017-06-12 13:34:29 +0100389 addHistoricalSessionLocked(session);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700390 }
Todd Kennedy28c4e802016-07-13 13:20:30 -0700391 mAllocatedSessions.put(session.sessionId, true);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700392 }
393 }
394 }
395 } catch (FileNotFoundException e) {
396 // Missing sessions are okay, probably first boot
Svet Ganov7121e182015-07-13 22:38:12 -0700397 } catch (IOException | XmlPullParserException e) {
Dianne Hackborn8d051722014-10-01 14:59:58 -0700398 Slog.wtf(TAG, "Failed reading install sessions", e);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700399 } finally {
400 IoUtils.closeQuietly(fis);
401 }
shafik43f1af92019-03-14 15:14:00 +0000402 // After all of the sessions were loaded, they are ready to be sealed and validated
403 for (int i = 0; i < mSessions.size(); ++i) {
404 PackageInstallerSession session = mSessions.valueAt(i);
405 session.sealAndValidateIfNecessary();
406 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700407 }
408
Andreas Gampea36dc622018-02-05 17:19:22 -0800409 @GuardedBy("mSessions")
Narayan Kamatha22a7662017-06-12 13:34:29 +0100410 private void addHistoricalSessionLocked(PackageInstallerSession session) {
411 CharArrayWriter writer = new CharArrayWriter();
412 IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
413 session.dump(pw);
414 mHistoricalSessions.add(writer.toString());
415
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000416 int installerUid = session.getInstallerUid();
Narayan Kamatha22a7662017-06-12 13:34:29 +0100417 // Increment the number of sessions by this installerUid.
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000418 mHistoricalSessionsByInstaller.put(installerUid,
419 mHistoricalSessionsByInstaller.get(installerUid) + 1);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700420 }
421
Andreas Gampea36dc622018-02-05 17:19:22 -0800422 @GuardedBy("mSessions")
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700423 private void writeSessionsLocked() {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700424 if (LOGD) Slog.v(TAG, "writeSessionsLocked()");
425
426 FileOutputStream fos = null;
427 try {
428 fos = mSessionsFile.startWrite();
429
430 XmlSerializer out = new FastXmlSerializer();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +0100431 out.setOutput(fos, StandardCharsets.UTF_8.name());
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700432 out.startDocument(null, true);
433 out.startTag(null, TAG_SESSIONS);
434 final int size = mSessions.size();
435 for (int i = 0; i < size; i++) {
436 final PackageInstallerSession session = mSessions.valueAt(i);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000437 session.write(out, mSessionsDir);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700438 }
439 out.endTag(null, TAG_SESSIONS);
440 out.endDocument();
441
442 mSessionsFile.finishWrite(fos);
443 } catch (IOException e) {
444 if (fos != null) {
445 mSessionsFile.failWrite(fos);
446 }
447 }
448 }
449
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700450 private File buildAppIconFile(int sessionId) {
451 return new File(mSessionsDir, "app_icon." + sessionId + ".png");
452 }
453
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700454 private void writeSessionsAsync() {
455 IoThread.getHandler().post(new Runnable() {
456 @Override
457 public void run() {
458 synchronized (mSessions) {
459 writeSessionsLocked();
460 }
461 }
462 });
463 }
464
465 @Override
Jeff Sharkeya0907432014-08-15 10:23:11 -0700466 public int createSession(SessionParams params, String installerPackageName, int userId) {
Jeff Sharkey742e7902014-08-16 19:09:13 -0700467 try {
468 return createSessionInternal(params, installerPackageName, userId);
469 } catch (IOException e) {
470 throw ExceptionUtils.wrap(e);
471 }
472 }
473
474 private int createSessionInternal(SessionParams params, String installerPackageName, int userId)
475 throws IOException {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700476 final int callingUid = Binder.getCallingUid();
Todd Kennedy0eb97382017-10-03 16:57:22 -0700477 mPermissionManager.enforceCrossUserPermission(
478 callingUid, userId, true, true, "createSession");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700479
Jeff Sharkeye9808042014-09-11 21:15:37 -0700480 if (mPm.isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700481 throw new SecurityException("User restriction prevents installing");
482 }
483
Alan Stokes69d2abf2019-10-10 11:02:38 +0100484 String requestedInstallerPackageName = params.installerPackageName != null
485 ? params.installerPackageName : installerPackageName;
486
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700487 if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {
Jeff Sharkeye9808042014-09-11 21:15:37 -0700488 params.installFlags |= PackageManager.INSTALL_FROM_ADB;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700489
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700490 } else {
Alan Stokes69d2abf2019-10-10 11:02:38 +0100491 if (callingUid != Process.SYSTEM_UID) {
492 // The supplied installerPackageName must always belong to the calling app.
493 mAppOps.checkPackage(callingUid, installerPackageName);
494 }
Philip P. Moltmann79c238a2017-12-13 15:59:07 -0800495 // Only apps with INSTALL_PACKAGES are allowed to set an installer that is not the
496 // caller.
Alan Stokes69d2abf2019-10-10 11:02:38 +0100497 if (!requestedInstallerPackageName.equals(installerPackageName)) {
498 if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES)
499 != PackageManager.PERMISSION_GRANTED) {
500 mAppOps.checkPackage(callingUid, requestedInstallerPackageName);
501 }
Philip P. Moltmann79c238a2017-12-13 15:59:07 -0800502 }
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700503
Jeff Sharkeye9808042014-09-11 21:15:37 -0700504 params.installFlags &= ~PackageManager.INSTALL_FROM_ADB;
505 params.installFlags &= ~PackageManager.INSTALL_ALL_USERS;
Todd Kennedy01519162019-09-20 13:45:15 -0700506 params.installFlags &= ~PackageManager.INSTALL_ALLOW_TEST;
Jeff Sharkeye9808042014-09-11 21:15:37 -0700507 params.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
Todd Kennedy78a72502017-07-19 12:49:30 -0700508 if ((params.installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0
509 && !mPm.isCallerVerifier(callingUid)) {
510 params.installFlags &= ~PackageManager.INSTALL_VIRTUAL_PRELOAD;
511 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700512 }
513
Alan Stokes5ed85372019-11-06 09:32:49 +0000514 String originatingPackageName = null;
515 if (params.originatingUid != SessionParams.UID_UNKNOWN
516 && params.originatingUid != callingUid) {
517 String[] packages = mPm.getPackagesForUid(params.originatingUid);
518 if (packages != null && packages.length > 0) {
519 // Choose an arbitrary representative package in the case of a shared UID.
520 originatingPackageName = packages[0];
521 }
522 }
523
Nikita Ioffe1962cb12019-03-27 22:59:28 +0000524 if (Build.IS_DEBUGGABLE || isDowngradeAllowedForCaller(callingUid)) {
Nikita Ioffeb1d60f12019-03-06 18:56:49 +0000525 params.installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE;
Nikita Ioffea1111ff2019-03-04 12:26:14 +0000526 } else {
Nikita Ioffeb1d60f12019-03-06 18:56:49 +0000527 params.installFlags &= ~PackageManager.INSTALL_ALLOW_DOWNGRADE;
Nikita Ioffe1962cb12019-03-27 22:59:28 +0000528 params.installFlags &= ~PackageManager.INSTALL_REQUEST_DOWNGRADE;
Nikita Ioffea1111ff2019-03-04 12:26:14 +0000529 }
530
Nikita Ioffea9543492019-07-30 17:10:27 +0100531 if (callingUid != Process.SYSTEM_UID) {
532 // Only system_server can use INSTALL_DISABLE_VERIFICATION.
533 params.installFlags &= ~PackageManager.INSTALL_DISABLE_VERIFICATION;
534 }
535
Nikita Ioffe4501c112019-02-22 11:51:09 +0000536 boolean isApex = (params.installFlags & PackageManager.INSTALL_APEX) != 0;
537 if (params.isStaged || isApex) {
Dario Freni77786d92019-02-08 17:26:05 +0000538 mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, TAG);
539 }
540
Nikita Ioffe4501c112019-02-22 11:51:09 +0000541 if (isApex) {
Dario Freni83620602019-02-18 14:30:57 +0000542 if (!mApexManager.isApexSupported()) {
543 throw new IllegalArgumentException(
544 "This device doesn't support the installation of APEX files");
545 }
546 if (!params.isStaged) {
547 throw new IllegalArgumentException(
548 "APEX files can only be installed as part of a staged session.");
549 }
550 }
551
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000552 if (!params.isMultiPackage) {
553 // Only system components can circumvent runtime permissions when installing.
554 if ((params.installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0
555 && mContext.checkCallingOrSelfPermission(Manifest.permission
556 .INSTALL_GRANT_RUNTIME_PERMISSIONS) == PackageManager.PERMISSION_DENIED) {
557 throw new SecurityException("You need the "
558 + "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS permission "
559 + "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag");
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700560 }
561
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000562 // Defensively resize giant app icons
563 if (params.appIcon != null) {
564 final ActivityManager am = (ActivityManager) mContext.getSystemService(
565 Context.ACTIVITY_SERVICE);
566 final int iconSize = am.getLauncherLargeIconSize();
567 if ((params.appIcon.getWidth() > iconSize * 2)
568 || (params.appIcon.getHeight() > iconSize * 2)) {
569 params.appIcon = Bitmap.createScaledBitmap(params.appIcon, iconSize, iconSize,
570 true);
571 }
572 }
Jeff Sharkeyab234092015-06-09 21:42:22 -0700573
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000574 switch (params.mode) {
575 case SessionParams.MODE_FULL_INSTALL:
576 case SessionParams.MODE_INHERIT_EXISTING:
577 break;
578 default:
579 throw new IllegalArgumentException("Invalid install mode: " + params.mode);
580 }
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700581
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000582 // If caller requested explicit location, sanity check it, otherwise
583 // resolve the best internal or adopted location.
584 if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
585 if (!PackageHelper.fitsOnInternal(mContext, params)) {
586 throw new IOException("No suitable internal storage available");
587 }
Patrick Baumannff10c9c2018-12-11 15:17:38 -0800588 } else if ((params.installFlags & PackageManager.INSTALL_FORCE_VOLUME_UUID) != 0) {
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000589 // For now, installs to adopted media are treated as internal from
590 // an install flag point-of-view.
Patrick Baumannfc2851e2018-11-13 15:23:22 -0800591 params.installFlags |= PackageManager.INSTALL_INTERNAL;
Patrick Baumannff10c9c2018-12-11 15:17:38 -0800592 } else {
593 params.installFlags |= PackageManager.INSTALL_INTERNAL;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000594
595 // Resolve best location for install, based on combination of
596 // requested install flags, delta size, and manifest settings.
597 final long ident = Binder.clearCallingIdentity();
598 try {
599 params.volumeUuid = PackageHelper.resolveInstallVolume(mContext, params);
600 } finally {
601 Binder.restoreCallingIdentity(ident);
602 }
Robin Leee812d902014-08-21 16:51:18 +0100603 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700604 }
605
606 final int sessionId;
607 final PackageInstallerSession session;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700608 synchronized (mSessions) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700609 // Sanity check that installer isn't going crazy
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700610 final int activeCount = getSessionCount(mSessions, callingUid);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700611 if (activeCount >= MAX_ACTIVE_SESSIONS) {
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700612 throw new IllegalStateException(
613 "Too many active sessions for UID " + callingUid);
614 }
Narayan Kamatha22a7662017-06-12 13:34:29 +0100615 final int historicalCount = mHistoricalSessionsByInstaller.get(callingUid);
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700616 if (historicalCount >= MAX_HISTORICAL_SESSIONS) {
617 throw new IllegalStateException(
618 "Too many historical sessions for UID " + callingUid);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700619 }
620
Jeff Sharkeya1031142014-07-12 18:09:46 -0700621 sessionId = allocateSessionIdLocked();
Todd Kennedy04918fe2016-07-12 14:07:40 -0700622 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700623
Todd Kennedy04918fe2016-07-12 14:07:40 -0700624 final long createdMillis = System.currentTimeMillis();
625 // We're staging to exactly one location
626 File stageDir = null;
627 String stageCid = null;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000628 if (!params.isMultiPackage) {
629 if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
Dario Frenia8f4b132018-12-30 00:36:49 +0000630 stageDir = buildSessionDir(sessionId, params);
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000631 } else {
632 stageCid = buildExternalStageCid(sessionId);
633 }
Todd Kennedy04918fe2016-07-12 14:07:40 -0700634 }
Alan Stokes819fea22019-10-16 16:54:09 +0100635 InstallSource installSource = InstallSource.create(installerPackageName,
Alan Stokes5ed85372019-11-06 09:32:49 +0000636 originatingPackageName, requestedInstallerPackageName, false);
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000637 session = new PackageInstallerSession(mInternalCallback, mContext, mPm, this,
Alan Stokes819fea22019-10-16 16:54:09 +0100638 mInstallThread.getLooper(), mStagingManager, sessionId, userId, callingUid,
639 installSource, params, createdMillis,
Alan Stokes69d2abf2019-10-10 11:02:38 +0100640 stageDir, stageCid, false, false, false, null, SessionInfo.INVALID_ID,
641 false, false, false, SessionInfo.STAGED_SESSION_NO_ERROR, "");
Todd Kennedy04918fe2016-07-12 14:07:40 -0700642
643 synchronized (mSessions) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700644 mSessions.put(sessionId, session);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700645 }
Dario Freniaac4ba42018-12-06 15:47:16 +0000646 if (params.isStaged) {
Dario Frenibe98c3f2018-12-22 15:25:27 +0000647 mStagingManager.createSession(session);
Dario Freniaac4ba42018-12-06 15:47:16 +0000648 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700649
Richard Uhler1c9c5d22019-06-05 13:04:32 +0100650 if ((session.params.installFlags & PackageManager.INSTALL_DRY_RUN) == 0) {
651 mCallbacks.notifySessionCreated(session.sessionId, session.userId);
652 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700653 writeSessionsAsync();
654 return sessionId;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700655 }
656
Nikita Ioffe1962cb12019-03-27 22:59:28 +0000657 private boolean isDowngradeAllowedForCaller(int callingUid) {
658 return callingUid == Process.SYSTEM_UID || callingUid == Process.ROOT_UID
659 || callingUid == Process.SHELL_UID;
660 }
661
Jeff Sharkey381d94b2014-08-24 14:45:56 -0700662 @Override
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700663 public void updateSessionAppIcon(int sessionId, Bitmap appIcon) {
664 synchronized (mSessions) {
665 final PackageInstallerSession session = mSessions.get(sessionId);
666 if (session == null || !isCallingUidOwner(session)) {
667 throw new SecurityException("Caller has no access to session " + sessionId);
668 }
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700669
670 // Defensively resize giant app icons
671 if (appIcon != null) {
672 final ActivityManager am = (ActivityManager) mContext.getSystemService(
673 Context.ACTIVITY_SERVICE);
674 final int iconSize = am.getLauncherLargeIconSize();
675 if ((appIcon.getWidth() > iconSize * 2)
676 || (appIcon.getHeight() > iconSize * 2)) {
677 appIcon = Bitmap.createScaledBitmap(appIcon, iconSize, iconSize, true);
678 }
679 }
680
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700681 session.params.appIcon = appIcon;
Jeff Sharkey02bd7842014-10-06 15:14:27 -0700682 session.params.appIconLastModified = -1;
683
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700684 mInternalCallback.onSessionBadgingChanged(session);
685 }
686 }
687
688 @Override
689 public void updateSessionAppLabel(int sessionId, String appLabel) {
690 synchronized (mSessions) {
691 final PackageInstallerSession session = mSessions.get(sessionId);
692 if (session == null || !isCallingUidOwner(session)) {
693 throw new SecurityException("Caller has no access to session " + sessionId);
694 }
695 session.params.appLabel = appLabel;
696 mInternalCallback.onSessionBadgingChanged(session);
697 }
698 }
699
700 @Override
Jeff Sharkey381d94b2014-08-24 14:45:56 -0700701 public void abandonSession(int sessionId) {
702 synchronized (mSessions) {
703 final PackageInstallerSession session = mSessions.get(sessionId);
704 if (session == null || !isCallingUidOwner(session)) {
705 throw new SecurityException("Caller has no access to session " + sessionId);
706 }
707 session.abandon();
708 }
709 }
710
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700711 @Override
712 public IPackageInstallerSession openSession(int sessionId) {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700713 try {
714 return openSessionInternal(sessionId);
715 } catch (IOException e) {
716 throw ExceptionUtils.wrap(e);
717 }
718 }
719
720 private IPackageInstallerSession openSessionInternal(int sessionId) throws IOException {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700721 synchronized (mSessions) {
722 final PackageInstallerSession session = mSessions.get(sessionId);
Jeff Sharkey381d94b2014-08-24 14:45:56 -0700723 if (session == null || !isCallingUidOwner(session)) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700724 throw new SecurityException("Caller has no access to session " + sessionId);
725 }
Jeff Sharkey742e7902014-08-16 19:09:13 -0700726 session.open();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700727 return session;
728 }
729 }
730
Andreas Gampea36dc622018-02-05 17:19:22 -0800731 @GuardedBy("mSessions")
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700732 private int allocateSessionIdLocked() {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700733 int n = 0;
734 int sessionId;
735 do {
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700736 sessionId = mRandom.nextInt(Integer.MAX_VALUE - 1) + 1;
Todd Kennedy28c4e802016-07-13 13:20:30 -0700737 if (!mAllocatedSessions.get(sessionId, false)) {
738 mAllocatedSessions.put(sessionId, true);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700739 return sessionId;
740 }
741 } while (n++ < 32);
742
743 throw new IllegalStateException("Failed to allocate session ID");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700744 }
745
Dario Frenia8f4b132018-12-30 00:36:49 +0000746 private File getTmpSessionDir(String volumeUuid) {
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700747 return Environment.getDataAppDirectory(volumeUuid);
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700748 }
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700749
Dario Frenia8f4b132018-12-30 00:36:49 +0000750 private File buildTmpSessionDir(int sessionId, String volumeUuid) {
751 final File sessionStagingDir = getTmpSessionDir(volumeUuid);
752 return new File(sessionStagingDir, "vmdl" + sessionId + ".tmp");
753 }
754
755 private File buildSessionDir(int sessionId, SessionParams params) {
756 if (params.isStaged) {
757 final File sessionStagingDir = Environment.getDataStagingDirectory(params.volumeUuid);
758 return new File(sessionStagingDir, "session_" + sessionId);
759 }
760 return buildTmpSessionDir(sessionId, params.volumeUuid);
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700761 }
762
763 static void prepareStageDir(File stageDir) throws IOException {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700764 if (stageDir.exists()) {
765 throw new IOException("Session dir already exists: " + stageDir);
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700766 }
767
768 try {
Dario Frenid8bf22e2018-08-31 14:18:04 +0100769 Os.mkdir(stageDir.getAbsolutePath(), 0775);
770 Os.chmod(stageDir.getAbsolutePath(), 0775);
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700771 } catch (ErrnoException e) {
772 // This purposefully throws if directory already exists
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700773 throw new IOException("Failed to prepare session dir: " + stageDir, e);
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700774 }
775
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700776 if (!SELinux.restorecon(stageDir)) {
777 throw new IOException("Failed to restorecon session dir: " + stageDir);
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700778 }
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700779 }
780
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700781 private String buildExternalStageCid(int sessionId) {
782 return "smdl" + sessionId + ".tmp";
783 }
Jeff Sharkey742e7902014-08-16 19:09:13 -0700784
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700785 @Override
Jeff Sharkeya0907432014-08-15 10:23:11 -0700786 public SessionInfo getSessionInfo(int sessionId) {
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700787 synchronized (mSessions) {
788 final PackageInstallerSession session = mSessions.get(sessionId);
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700789 return session != null ? session.generateInfo() : null;
790 }
791 }
792
793 @Override
Dario Freniaac4ba42018-12-06 15:47:16 +0000794 public ParceledListSlice<SessionInfo> getStagedSessions() {
Dario Frenibe98c3f2018-12-22 15:25:27 +0000795 return mStagingManager.getSessions();
Dario Freniaac4ba42018-12-06 15:47:16 +0000796 }
797
798 @Override
Jeff Sharkey97d47ed2014-10-15 09:19:47 -0700799 public ParceledListSlice<SessionInfo> getAllSessions(int userId) {
Todd Kennedy0eb97382017-10-03 16:57:22 -0700800 mPermissionManager.enforceCrossUserPermission(
801 Binder.getCallingUid(), userId, true, false, "getAllSessions");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700802
Jeff Sharkeya0907432014-08-15 10:23:11 -0700803 final List<SessionInfo> result = new ArrayList<>();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700804 synchronized (mSessions) {
805 for (int i = 0; i < mSessions.size(); i++) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700806 final PackageInstallerSession session = mSessions.valueAt(i);
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000807 if (session.userId == userId && !session.hasParentSessionId()) {
Jeff Sharkeyda1247a2017-06-08 14:13:29 -0600808 result.add(session.generateInfo(false));
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700809 }
810 }
811 }
Jeff Sharkey97d47ed2014-10-15 09:19:47 -0700812 return new ParceledListSlice<>(result);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700813 }
814
815 @Override
Jeff Sharkey97d47ed2014-10-15 09:19:47 -0700816 public ParceledListSlice<SessionInfo> getMySessions(String installerPackageName, int userId) {
Todd Kennedy0eb97382017-10-03 16:57:22 -0700817 mPermissionManager.enforceCrossUserPermission(
818 Binder.getCallingUid(), userId, true, false, "getMySessions");
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700819 mAppOps.checkPackage(Binder.getCallingUid(), installerPackageName);
820
Jeff Sharkeya0907432014-08-15 10:23:11 -0700821 final List<SessionInfo> result = new ArrayList<>();
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700822 synchronized (mSessions) {
823 for (int i = 0; i < mSessions.size(); i++) {
824 final PackageInstallerSession session = mSessions.valueAt(i);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000825
826 SessionInfo info = session.generateInfo(false);
827 if (Objects.equals(info.getInstallerPackageName(), installerPackageName)
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000828 && session.userId == userId && !session.hasParentSessionId()) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000829 result.add(info);
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700830 }
831 }
832 }
Jeff Sharkey97d47ed2014-10-15 09:19:47 -0700833 return new ParceledListSlice<>(result);
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700834 }
835
836 @Override
Svet Ganov67882122016-12-11 16:36:34 -0800837 public void uninstall(VersionedPackage versionedPackage, String callerPackageName, int flags,
Patrick Baumann466ddb52019-04-11 12:43:05 -0700838 IntentSender statusReceiver, int userId) {
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000839 final int callingUid = Binder.getCallingUid();
Todd Kennedy0eb97382017-10-03 16:57:22 -0700840 mPermissionManager.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000841 if ((callingUid != Process.SHELL_UID) && (callingUid != Process.ROOT_UID)) {
842 mAppOps.checkPackage(callingUid, callerPackageName);
843 }
844
Benjamin Franzdabae882017-08-08 12:33:19 +0100845 // Check whether the caller is device owner or affiliated profile owner, in which case we do
846 // it silently.
Benjamin Franzdabae882017-08-08 12:33:19 +0100847 DevicePolicyManagerInternal dpmi =
848 LocalServices.getService(DevicePolicyManagerInternal.class);
Rubin Xufd4a3b42018-12-05 16:03:27 +0000849 final boolean canSilentlyInstallPackage =
850 dpmi != null && dpmi.canSilentlyInstallPackage(callerPackageName, callingUid);
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700851
Jeff Sharkeya0907432014-08-15 10:23:11 -0700852 final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext,
Benjamin Franzdabae882017-08-08 12:33:19 +0100853 statusReceiver, versionedPackage.getPackageName(),
Rubin Xucb924152019-03-28 12:11:17 +0000854 canSilentlyInstallPackage, userId);
Sudheer Shanka72de4dd2016-07-22 15:46:37 -0700855 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES)
856 == PackageManager.PERMISSION_GRANTED) {
Jeff Sharkeyf0600952014-08-07 17:31:53 -0700857 // Sweet, call straight through!
Svet Ganov67882122016-12-11 16:36:34 -0800858 mPm.deletePackageVersioned(versionedPackage, adapter.getBinder(), userId, flags);
Rubin Xufd4a3b42018-12-05 16:03:27 +0000859 } else if (canSilentlyInstallPackage) {
Benjamin Franzdabae882017-08-08 12:33:19 +0100860 // Allow the device owner and affiliated profile owner to silently delete packages
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000861 // Need to clear the calling identity to get DELETE_PACKAGES permission
862 long ident = Binder.clearCallingIdentity();
863 try {
Svet Ganov67882122016-12-11 16:36:34 -0800864 mPm.deletePackageVersioned(versionedPackage, adapter.getBinder(), userId, flags);
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000865 } finally {
866 Binder.restoreCallingIdentity(ident);
867 }
Rubin Xu8b17ad02019-03-07 17:42:37 +0000868 DevicePolicyEventLogger
869 .createEvent(DevicePolicyEnums.UNINSTALL_PACKAGE)
870 .setAdmin(callerPackageName)
871 .write();
Jeff Sharkeyf0600952014-08-07 17:31:53 -0700872 } else {
Philip P. Moltmannd9bb39a2017-09-05 12:41:15 -0700873 ApplicationInfo appInfo = mPm.getApplicationInfo(callerPackageName, 0, userId);
874 if (appInfo.targetSdkVersion >= Build.VERSION_CODES.P) {
875 mContext.enforceCallingOrSelfPermission(Manifest.permission.REQUEST_DELETE_PACKAGES,
876 null);
877 }
878
Jeff Sharkeyf0600952014-08-07 17:31:53 -0700879 // Take a short detour to confirm with user
880 final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
Svet Ganov67882122016-12-11 16:36:34 -0800881 intent.setData(Uri.fromParts("package", versionedPackage.getPackageName(), null));
Jeff Sharkeya0907432014-08-15 10:23:11 -0700882 intent.putExtra(PackageInstaller.EXTRA_CALLBACK, adapter.getBinder().asBinder());
883 adapter.onUserActionRequired(intent);
Jeff Sharkeyf0600952014-08-07 17:31:53 -0700884 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700885 }
886
887 @Override
Chandan Nathe8e463b2019-01-28 15:23:38 +0000888 public void installExistingPackage(String packageName, int installFlags, int installReason,
Philip P. Moltmanna4bd1502019-05-13 17:10:46 -0700889 IntentSender statusReceiver, int userId, List<String> whiteListedPermissions) {
Chandan Nathe8e463b2019-01-28 15:23:38 +0000890 mPm.installExistingPackageAsUser(packageName, userId, installFlags, installReason,
Philip P. Moltmanna4bd1502019-05-13 17:10:46 -0700891 whiteListedPermissions, statusReceiver);
Chandan Nathe8e463b2019-01-28 15:23:38 +0000892 }
893
894 @Override
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700895 public void setPermissionsResult(int sessionId, boolean accepted) {
896 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, TAG);
897
898 synchronized (mSessions) {
Svet Ganov3baa8762016-04-08 09:22:54 -0700899 PackageInstallerSession session = mSessions.get(sessionId);
900 if (session != null) {
901 session.setPermissionsResult(accepted);
902 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700903 }
904 }
905
906 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700907 public void registerCallback(IPackageInstallerCallback callback, int userId) {
Todd Kennedy0eb97382017-10-03 16:57:22 -0700908 mPermissionManager.enforceCrossUserPermission(
909 Binder.getCallingUid(), userId, true, false, "registerCallback");
Jon Miranda2b340a22019-01-25 14:03:49 -0800910 registerCallback(callback, eventUserId -> userId == eventUserId);
911 }
912
913 /**
914 * Assume permissions already checked and caller's identity cleared
915 */
916 public void registerCallback(IPackageInstallerCallback callback, IntPredicate userCheck) {
917 mCallbacks.register(callback, userCheck);
Jeff Sharkeybb580672014-07-10 12:10:25 -0700918 }
919
920 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700921 public void unregisterCallback(IPackageInstallerCallback callback) {
922 mCallbacks.unregister(callback);
Jeff Sharkeya1031142014-07-12 18:09:46 -0700923 }
924
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000925 @Override
926 public PackageInstallerSession getSession(int sessionId) {
927 synchronized (mSessions) {
928 return mSessions.get(sessionId);
929 }
930 }
931
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700932 private static int getSessionCount(SparseArray<PackageInstallerSession> sessions,
933 int installerUid) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700934 int count = 0;
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700935 final int size = sessions.size();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700936 for (int i = 0; i < size; i++) {
Jeff Sharkeyf174c6e2014-08-05 10:42:27 -0700937 final PackageInstallerSession session = sessions.valueAt(i);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000938 if (session.getInstallerUid() == installerUid) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700939 count++;
940 }
941 }
942 return count;
943 }
944
945 private boolean isCallingUidOwner(PackageInstallerSession session) {
946 final int callingUid = Binder.getCallingUid();
947 if (callingUid == Process.ROOT_UID) {
948 return true;
949 } else {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000950 return (session != null) && (callingUid == session.getInstallerUid());
Jeff Sharkeya1031142014-07-12 18:09:46 -0700951 }
952 }
953
Jeff Sharkeya0907432014-08-15 10:23:11 -0700954 static class PackageDeleteObserverAdapter extends PackageDeleteObserver {
955 private final Context mContext;
956 private final IntentSender mTarget;
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700957 private final String mPackageName;
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000958 private final Notification mNotification;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700959
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700960 public PackageDeleteObserverAdapter(Context context, IntentSender target,
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000961 String packageName, boolean showNotification, int userId) {
Jeff Sharkeya0907432014-08-15 10:23:11 -0700962 mContext = context;
963 mTarget = target;
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700964 mPackageName = packageName;
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000965 if (showNotification) {
966 mNotification = buildSuccessNotification(mContext,
967 mContext.getResources().getString(R.string.package_deleted_device_owner),
968 packageName,
969 userId);
970 } else {
971 mNotification = null;
972 }
Jeff Sharkeya0907432014-08-15 10:23:11 -0700973 }
974
975 @Override
976 public void onUserActionRequired(Intent intent) {
Patrick Baumann466ddb52019-04-11 12:43:05 -0700977 if (mTarget == null) {
978 return;
979 }
Jeff Sharkeya0907432014-08-15 10:23:11 -0700980 final Intent fillIn = new Intent();
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700981 fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName);
Jeff Sharkeya0907432014-08-15 10:23:11 -0700982 fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
Jeff Sharkey742e7902014-08-16 19:09:13 -0700983 PackageInstaller.STATUS_PENDING_USER_ACTION);
Jeff Sharkeya0907432014-08-15 10:23:11 -0700984 fillIn.putExtra(Intent.EXTRA_INTENT, intent);
985 try {
986 mTarget.sendIntent(mContext, 0, fillIn, null, null);
987 } catch (SendIntentException ignored) {
988 }
989 }
990
991 @Override
992 public void onPackageDeleted(String basePackageName, int returnCode, String msg) {
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000993 if (PackageManager.DELETE_SUCCEEDED == returnCode && mNotification != null) {
994 NotificationManager notificationManager = (NotificationManager)
995 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
Chris Wren282cfef2017-03-27 15:01:44 -0400996 notificationManager.notify(basePackageName,
997 SystemMessage.NOTE_PACKAGE_STATE,
998 mNotification);
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000999 }
Patrick Baumann466ddb52019-04-11 12:43:05 -07001000 if (mTarget == null) {
1001 return;
1002 }
Jeff Sharkeya0907432014-08-15 10:23:11 -07001003 final Intent fillIn = new Intent();
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -07001004 fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName);
Jeff Sharkeya0907432014-08-15 10:23:11 -07001005 fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
1006 PackageManager.deleteStatusToPublicStatus(returnCode));
1007 fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
1008 PackageManager.deleteStatusToString(returnCode, msg));
1009 fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode);
1010 try {
1011 mTarget.sendIntent(mContext, 0, fillIn, null, null);
1012 } catch (SendIntentException ignored) {
1013 }
1014 }
1015 }
1016
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -08001017 static void sendOnUserActionRequired(Context context, IntentSender target, int sessionId,
1018 Intent intent) {
1019 final Intent fillIn = new Intent();
1020 fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
1021 fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
1022 PackageInstaller.STATUS_PENDING_USER_ACTION);
1023 fillIn.putExtra(Intent.EXTRA_INTENT, intent);
1024 try {
1025 target.sendIntent(context, 0, fillIn, null, null);
1026 } catch (SendIntentException ignored) {
Jeff Sharkeya0907432014-08-15 10:23:11 -07001027 }
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -08001028 }
Jeff Sharkeya0907432014-08-15 10:23:11 -07001029
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -08001030 static void sendOnPackageInstalled(Context context, IntentSender target, int sessionId,
1031 boolean showNotification, int userId, String basePackageName, int returnCode,
1032 String msg, Bundle extras) {
1033 if (PackageManager.INSTALL_SUCCEEDED == returnCode && showNotification) {
1034 boolean update = (extras != null) && extras.getBoolean(Intent.EXTRA_REPLACING);
1035 Notification notification = buildSuccessNotification(context,
1036 context.getResources()
1037 .getString(update ? R.string.package_updated_device_owner :
1038 R.string.package_installed_device_owner),
1039 basePackageName,
1040 userId);
1041 if (notification != null) {
1042 NotificationManager notificationManager = (NotificationManager)
1043 context.getSystemService(Context.NOTIFICATION_SERVICE);
1044 notificationManager.notify(basePackageName,
1045 SystemMessage.NOTE_PACKAGE_STATE,
1046 notification);
Jeff Sharkeya0907432014-08-15 10:23:11 -07001047 }
1048 }
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -08001049 final Intent fillIn = new Intent();
1050 fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, basePackageName);
1051 fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
1052 fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
1053 PackageManager.installStatusToPublicStatus(returnCode));
1054 fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
1055 PackageManager.installStatusToString(returnCode, msg));
1056 fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode);
1057 if (extras != null) {
1058 final String existing = extras.getString(
1059 PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE);
1060 if (!TextUtils.isEmpty(existing)) {
1061 fillIn.putExtra(PackageInstaller.EXTRA_OTHER_PACKAGE_NAME, existing);
Benjamin Franz39fb7fd2015-02-18 16:11:18 +00001062 }
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -08001063 }
1064 try {
1065 target.sendIntent(context, 0, fillIn, null, null);
1066 } catch (SendIntentException ignored) {
Jeff Sharkeya0907432014-08-15 10:23:11 -07001067 }
1068 }
1069
Benjamin Franz39fb7fd2015-02-18 16:11:18 +00001070 /**
1071 * Build a notification for package installation / deletion by device owners that is shown if
1072 * the operation succeeds.
1073 */
1074 private static Notification buildSuccessNotification(Context context, String contentText,
1075 String basePackageName, int userId) {
1076 PackageInfo packageInfo = null;
1077 try {
1078 packageInfo = AppGlobals.getPackageManager().getPackageInfo(
Svet Ganova5c867c2017-05-15 01:17:05 -07001079 basePackageName, PackageManager.MATCH_STATIC_SHARED_LIBRARIES, userId);
Benjamin Franz39fb7fd2015-02-18 16:11:18 +00001080 } catch (RemoteException ignored) {
1081 }
1082 if (packageInfo == null || packageInfo.applicationInfo == null) {
1083 Slog.w(TAG, "Notification not built for package: " + basePackageName);
1084 return null;
1085 }
1086 PackageManager pm = context.getPackageManager();
1087 Bitmap packageIcon = ImageUtils.buildScaledBitmap(
1088 packageInfo.applicationInfo.loadIcon(pm),
1089 context.getResources().getDimensionPixelSize(
1090 android.R.dimen.notification_large_icon_width),
1091 context.getResources().getDimensionPixelSize(
1092 android.R.dimen.notification_large_icon_height));
1093 CharSequence packageLabel = packageInfo.applicationInfo.loadLabel(pm);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05001094 return new Notification.Builder(context, SystemNotificationChannels.DEVICE_ADMIN)
Benjamin Franz39fb7fd2015-02-18 16:11:18 +00001095 .setSmallIcon(R.drawable.ic_check_circle_24px)
1096 .setColor(context.getResources().getColor(
1097 R.color.system_notification_accent_color))
1098 .setContentTitle(packageLabel)
1099 .setContentText(contentText)
Benjamin Franz2e3e9432015-04-17 15:28:17 +01001100 .setStyle(new Notification.BigTextStyle().bigText(contentText))
Benjamin Franz39fb7fd2015-02-18 16:11:18 +00001101 .setLargeIcon(packageIcon)
1102 .build();
1103 }
1104
Jeff Sharkey54d42be2015-07-20 16:36:55 -07001105 public static <E> ArraySet<E> newArraySet(E... elements) {
1106 final ArraySet<E> set = new ArraySet<E>();
1107 if (elements != null) {
1108 set.ensureCapacity(elements.length);
1109 Collections.addAll(set, elements);
1110 }
1111 return set;
1112 }
1113
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001114 private static class Callbacks extends Handler {
1115 private static final int MSG_SESSION_CREATED = 1;
Jeff Sharkeyec9bad22014-09-05 09:45:20 -07001116 private static final int MSG_SESSION_BADGING_CHANGED = 2;
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001117 private static final int MSG_SESSION_ACTIVE_CHANGED = 3;
Jeff Sharkeyec9bad22014-09-05 09:45:20 -07001118 private static final int MSG_SESSION_PROGRESS_CHANGED = 4;
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001119 private static final int MSG_SESSION_FINISHED = 5;
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07001120
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001121 private final RemoteCallbackList<IPackageInstallerCallback>
1122 mCallbacks = new RemoteCallbackList<>();
Jeff Sharkeya1031142014-07-12 18:09:46 -07001123
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001124 public Callbacks(Looper looper) {
1125 super(looper);
1126 }
1127
Jon Miranda2b340a22019-01-25 14:03:49 -08001128 public void register(IPackageInstallerCallback callback, IntPredicate userCheck) {
1129 mCallbacks.register(callback, userCheck);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001130 }
1131
1132 public void unregister(IPackageInstallerCallback callback) {
1133 mCallbacks.unregister(callback);
1134 }
1135
1136 @Override
1137 public void handleMessage(Message msg) {
1138 final int userId = msg.arg2;
1139 final int n = mCallbacks.beginBroadcast();
1140 for (int i = 0; i < n; i++) {
1141 final IPackageInstallerCallback callback = mCallbacks.getBroadcastItem(i);
Jon Miranda2b340a22019-01-25 14:03:49 -08001142 final IntPredicate userCheck = (IntPredicate) mCallbacks.getBroadcastCookie(i);
1143 if (userCheck.test(userId)) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001144 try {
1145 invokeCallback(callback, msg);
1146 } catch (RemoteException ignored) {
1147 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07001148 }
1149 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001150 mCallbacks.finishBroadcast();
Jeff Sharkeya1031142014-07-12 18:09:46 -07001151 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001152
1153 private void invokeCallback(IPackageInstallerCallback callback, Message msg)
1154 throws RemoteException {
1155 final int sessionId = msg.arg1;
1156 switch (msg.what) {
1157 case MSG_SESSION_CREATED:
1158 callback.onSessionCreated(sessionId);
1159 break;
Jeff Sharkeyec9bad22014-09-05 09:45:20 -07001160 case MSG_SESSION_BADGING_CHANGED:
1161 callback.onSessionBadgingChanged(sessionId);
1162 break;
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001163 case MSG_SESSION_ACTIVE_CHANGED:
1164 callback.onSessionActiveChanged(sessionId, (boolean) msg.obj);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001165 break;
1166 case MSG_SESSION_PROGRESS_CHANGED:
1167 callback.onSessionProgressChanged(sessionId, (float) msg.obj);
1168 break;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001169 case MSG_SESSION_FINISHED:
1170 callback.onSessionFinished(sessionId, (boolean) msg.obj);
1171 break;
1172 }
1173 }
1174
1175 private void notifySessionCreated(int sessionId, int userId) {
1176 obtainMessage(MSG_SESSION_CREATED, sessionId, userId).sendToTarget();
1177 }
1178
Jeff Sharkeyec9bad22014-09-05 09:45:20 -07001179 private void notifySessionBadgingChanged(int sessionId, int userId) {
1180 obtainMessage(MSG_SESSION_BADGING_CHANGED, sessionId, userId).sendToTarget();
1181 }
1182
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001183 private void notifySessionActiveChanged(int sessionId, int userId, boolean active) {
1184 obtainMessage(MSG_SESSION_ACTIVE_CHANGED, sessionId, userId, active).sendToTarget();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001185 }
1186
1187 private void notifySessionProgressChanged(int sessionId, int userId, float progress) {
1188 obtainMessage(MSG_SESSION_PROGRESS_CHANGED, sessionId, userId, progress).sendToTarget();
1189 }
1190
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001191 public void notifySessionFinished(int sessionId, int userId, boolean success) {
1192 obtainMessage(MSG_SESSION_FINISHED, sessionId, userId, success).sendToTarget();
1193 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07001194 }
1195
1196 void dump(IndentingPrintWriter pw) {
Jeff Sharkeya1031142014-07-12 18:09:46 -07001197 synchronized (mSessions) {
Jeff Sharkey9a445772014-07-16 11:32:08 -07001198 pw.println("Active install sessions:");
1199 pw.increaseIndent();
Mohammad Samiul Islam52560d52019-08-16 12:07:31 +01001200
1201 List<PackageInstallerSession> finalizedSessions = new ArrayList<>();
Jeff Sharkey9a445772014-07-16 11:32:08 -07001202 int N = mSessions.size();
Jeff Sharkeya1031142014-07-12 18:09:46 -07001203 for (int i = 0; i < N; i++) {
1204 final PackageInstallerSession session = mSessions.valueAt(i);
Mohammad Samiul Islam52560d52019-08-16 12:07:31 +01001205 if (session.isStagedAndInTerminalState()) {
1206 finalizedSessions.add(session);
1207 continue;
1208 }
1209 session.dump(pw);
1210 pw.println();
1211 }
1212 pw.println();
1213 pw.decreaseIndent();
1214
1215 pw.println("Finalized install sessions:");
1216 pw.increaseIndent();
1217 N = finalizedSessions.size();
1218 for (int i = 0; i < N; i++) {
1219 final PackageInstallerSession session = finalizedSessions.get(i);
Jeff Sharkeya1031142014-07-12 18:09:46 -07001220 session.dump(pw);
1221 pw.println();
1222 }
Jeff Sharkey9a445772014-07-16 11:32:08 -07001223 pw.println();
1224 pw.decreaseIndent();
1225
1226 pw.println("Historical install sessions:");
1227 pw.increaseIndent();
1228 N = mHistoricalSessions.size();
1229 for (int i = 0; i < N; i++) {
Narayan Kamatha22a7662017-06-12 13:34:29 +01001230 pw.print(mHistoricalSessions.get(i));
Jeff Sharkey9a445772014-07-16 11:32:08 -07001231 pw.println();
1232 }
1233 pw.println();
1234 pw.decreaseIndent();
Jeff Sharkey742e7902014-08-16 19:09:13 -07001235
1236 pw.println("Legacy install sessions:");
1237 pw.increaseIndent();
1238 pw.println(mLegacySessions.toString());
1239 pw.decreaseIndent();
Jeff Sharkeya1031142014-07-12 18:09:46 -07001240 }
Jeff Sharkeybb580672014-07-10 12:10:25 -07001241 }
1242
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001243 class InternalCallback {
Jeff Sharkeyec9bad22014-09-05 09:45:20 -07001244 public void onSessionBadgingChanged(PackageInstallerSession session) {
Richard Uhler1c9c5d22019-06-05 13:04:32 +01001245 if ((session.params.installFlags & PackageManager.INSTALL_DRY_RUN) == 0) {
1246 mCallbacks.notifySessionBadgingChanged(session.sessionId, session.userId);
1247 }
1248
Jeff Sharkeyec9bad22014-09-05 09:45:20 -07001249 writeSessionsAsync();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001250 }
1251
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001252 public void onSessionActiveChanged(PackageInstallerSession session, boolean active) {
Richard Uhler1c9c5d22019-06-05 13:04:32 +01001253 if ((session.params.installFlags & PackageManager.INSTALL_DRY_RUN) == 0) {
1254 mCallbacks.notifySessionActiveChanged(session.sessionId, session.userId,
1255 active);
1256 }
Jeff Sharkey742e7902014-08-16 19:09:13 -07001257 }
1258
Jeff Sharkeyec9bad22014-09-05 09:45:20 -07001259 public void onSessionProgressChanged(PackageInstallerSession session, float progress) {
Richard Uhler1c9c5d22019-06-05 13:04:32 +01001260 if ((session.params.installFlags & PackageManager.INSTALL_DRY_RUN) == 0) {
1261 mCallbacks.notifySessionProgressChanged(session.sessionId, session.userId,
1262 progress);
1263 }
Jeff Sharkeyec9bad22014-09-05 09:45:20 -07001264 }
1265
Dario Freni0180d0b2019-01-11 21:08:13 +00001266 public void onStagedSessionChanged(PackageInstallerSession session) {
Gavin Corkeryd8311212019-02-22 17:52:30 +00001267 session.markUpdated();
Dario Freni0180d0b2019-01-11 21:08:13 +00001268 writeSessionsAsync();
Dario Freni14f885b2019-02-25 12:48:47 +00001269 if (mOkToSendBroadcasts) {
Dario Freni9694b802019-01-27 23:26:06 +00001270 mPm.sendSessionUpdatedBroadcast(session.generateInfo(false),
1271 session.userId);
1272 }
Dario Freni0180d0b2019-01-11 21:08:13 +00001273 }
1274
Jeff Sharkeycbf47912014-09-12 09:55:32 -07001275 public void onSessionFinished(final PackageInstallerSession session, boolean success) {
Richard Uhler1c9c5d22019-06-05 13:04:32 +01001276 if ((session.params.installFlags & PackageManager.INSTALL_DRY_RUN) == 0) {
1277 mCallbacks.notifySessionFinished(session.sessionId, session.userId, success);
1278 }
Jeff Sharkeycbf47912014-09-12 09:55:32 -07001279
1280 mInstallHandler.post(new Runnable() {
1281 @Override
1282 public void run() {
Dario Freniaac4ba42018-12-06 15:47:16 +00001283 if (session.isStaged()) {
Dario Freniaac4ba42018-12-06 15:47:16 +00001284 if (!success) {
Dario Frenibe98c3f2018-12-22 15:25:27 +00001285 mStagingManager.abortSession(session);
Dario Freniaac4ba42018-12-06 15:47:16 +00001286 }
1287 }
Jeff Sharkeycbf47912014-09-12 09:55:32 -07001288 synchronized (mSessions) {
Dario Freni8e7d0ec2019-01-10 15:21:40 +00001289 if (!session.isStaged() || !success) {
1290 mSessions.remove(session.sessionId);
1291 }
Narayan Kamatha22a7662017-06-12 13:34:29 +01001292 addHistoricalSessionLocked(session);
Jeff Sharkey02bd7842014-10-06 15:14:27 -07001293
1294 final File appIconFile = buildAppIconFile(session.sessionId);
1295 if (appIconFile.exists()) {
1296 appIconFile.delete();
1297 }
1298
Jeff Sharkeycbf47912014-09-12 09:55:32 -07001299 writeSessionsLocked();
1300 }
1301 }
1302 });
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001303 }
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -07001304
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001305 public void onSessionPrepared(PackageInstallerSession session) {
1306 // We prepared the destination to write into; we want to persist
1307 // this, but it's not critical enough to block for.
1308 writeSessionsAsync();
1309 }
1310
Jeff Sharkeycbf47912014-09-12 09:55:32 -07001311 public void onSessionSealedBlocking(PackageInstallerSession session) {
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -07001312 // It's very important that we block until we've recorded the
1313 // session as being sealed, since we never want to allow mutation
1314 // after sealing.
Jeff Sharkeycbf47912014-09-12 09:55:32 -07001315 synchronized (mSessions) {
1316 writeSessionsLocked();
1317 }
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -07001318 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001319 }
1320}