PackageInstallerService.java revision 9e9e2e73c6ec7bece20268196dc89ad0c8bafad4
13a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey/*
23a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * Copyright (C) 2014 The Android Open Source Project
33a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey *
43a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License");
53a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * you may not use this file except in compliance with the License.
63a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * You may obtain a copy of the License at
73a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey *
83a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey *      http://www.apache.org/licenses/LICENSE-2.0
93a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey *
103a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * Unless required by applicable law or agreed to in writing, software
113a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS,
123a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * See the License for the specific language governing permissions and
143a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * limitations under the License.
153a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey */
163a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
173a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeypackage com.android.server.pm;
183a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
191cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.readBitmapAttribute;
201cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.readBooleanAttribute;
211cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.readIntAttribute;
221cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.readLongAttribute;
231cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.readStringAttribute;
241cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.readUriAttribute;
251cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.writeBooleanAttribute;
261cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.writeIntAttribute;
271cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.writeLongAttribute;
281cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.writeStringAttribute;
291cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.writeUriAttribute;
301cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
311cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static org.xmlpull.v1.XmlPullParser.START_TAG;
321cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
33805b63e253c139625f5a86d72ef7b31d6ec9f8e9Svetoslavimport android.Manifest;
341cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.app.ActivityManager;
3539fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franzimport android.app.AppGlobals;
363a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.app.AppOpsManager;
3739fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franzimport android.app.Notification;
3839fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franzimport android.app.NotificationManager;
39a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.app.PackageDeleteObserver;
40a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.app.PackageInstallObserver;
4139fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franzimport android.app.admin.DevicePolicyManager;
423a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.content.Context;
43f06009542390472872da986486d385001e91a2a7Jeff Sharkeyimport android.content.Intent;
44a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.content.IntentSender;
45a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.content.IntentSender.SendIntentException;
4639fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franzimport android.content.pm.ApplicationInfo;
473a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.content.pm.IPackageInstaller;
4816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkeyimport android.content.pm.IPackageInstallerCallback;
493a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.content.pm.IPackageInstallerSession;
5039fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franzimport android.content.pm.PackageInfo;
51f06009542390472872da986486d385001e91a2a7Jeff Sharkeyimport android.content.pm.PackageInstaller;
52a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.content.pm.PackageInstaller.SessionInfo;
53a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.content.pm.PackageInstaller.SessionParams;
54ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkeyimport android.content.pm.PackageManager;
5597d47ed036ff7bd3d7d2ddc1c6df1104ec237559Jeff Sharkeyimport android.content.pm.ParceledListSlice;
561cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.graphics.Bitmap;
5702bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkeyimport android.graphics.Bitmap.CompressFormat;
5802bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkeyimport android.graphics.BitmapFactory;
59f06009542390472872da986486d385001e91a2a7Jeff Sharkeyimport android.net.Uri;
603a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.Binder;
61a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.os.Bundle;
621cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.os.Environment;
631cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.os.Handler;
643a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.HandlerThread;
651cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.os.Looper;
661cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.os.Message;
673a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.Process;
68a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkeyimport android.os.RemoteCallbackList;
69a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkeyimport android.os.RemoteException;
70ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport android.os.SELinux;
713a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.UserHandle;
723a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.UserManager;
73b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkeyimport android.os.storage.StorageManager;
74b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkeyimport android.os.storage.VolumeInfo;
75ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport android.system.ErrnoException;
76ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport android.system.Os;
77a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.text.TextUtils;
781cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.text.format.DateUtils;
793a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.util.ArraySet;
801cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.util.AtomicFile;
81a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkeyimport android.util.ExceptionUtils;
823a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.util.Slog;
833a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.util.SparseArray;
84742e790294b3441b79f715fe447069b63c6065dbJeff Sharkeyimport android.util.SparseBooleanArray;
851cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.util.Xml;
863a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
87b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkeyimport libcore.io.IoUtils;
88b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey
8939fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franzimport com.android.internal.R;
903a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport com.android.internal.annotations.GuardedBy;
91742e790294b3441b79f715fe447069b63c6065dbJeff Sharkeyimport com.android.internal.content.PackageHelper;
921cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport com.android.internal.util.FastXmlSerializer;
9339fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franzimport com.android.internal.util.ImageUtils;
94a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkeyimport com.android.internal.util.IndentingPrintWriter;
953a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport com.android.server.IoThread;
963a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport com.google.android.collect.Sets;
973a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
981cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport org.xmlpull.v1.XmlPullParser;
991cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport org.xmlpull.v1.XmlPullParserException;
1001cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport org.xmlpull.v1.XmlSerializer;
1011cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
1023a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport java.io.File;
1031cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport java.io.FileInputStream;
1041cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport java.io.FileNotFoundException;
1051cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport java.io.FileOutputStream;
106ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport java.io.FilenameFilter;
107ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport java.io.IOException;
1089e9e2e73c6ec7bece20268196dc89ad0c8bafad4Wojciech Staszkiewiczimport java.nio.charset.StandardCharsets;
1091cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport java.security.SecureRandom;
110bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkeyimport java.util.ArrayList;
111bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkeyimport java.util.List;
11216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkeyimport java.util.Objects;
1131cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport java.util.Random;
1143a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1153a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeypublic class PackageInstallerService extends IPackageInstaller.Stub {
1163a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private static final String TAG = "PackageInstaller";
117e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey    private static final boolean LOGD = false;
1183a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1193a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    // TODO: remove outstanding sessions when installer package goes away
1206c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey    // TODO: notify listeners in other users when package has been installed there
121742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    // TODO: purge expired sessions periodically in addition to at reboot
1223a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1231cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    /** XML constants used in {@link #mSessionsFile} */
1241cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String TAG_SESSIONS = "sessions";
1251cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String TAG_SESSION = "session";
1261cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_SESSION_ID = "sessionId";
1271cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_USER_ID = "userId";
1281cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_INSTALLER_PACKAGE_NAME = "installerPackageName";
129e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey    private static final String ATTR_INSTALLER_UID = "installerUid";
1301cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_CREATED_MILLIS = "createdMillis";
1311cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_SESSION_STAGE_DIR = "sessionStageDir";
132742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    private static final String ATTR_SESSION_STAGE_CID = "sessionStageCid";
13377d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey    private static final String ATTR_PREPARED = "prepared";
1341cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_SEALED = "sealed";
1351cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_MODE = "mode";
1361cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_INSTALL_FLAGS = "installFlags";
1371cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_INSTALL_LOCATION = "installLocation";
1381cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_SIZE_BYTES = "sizeBytes";
1391cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_APP_PACKAGE_NAME = "appPackageName";
14002bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey    @Deprecated
1411cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_APP_ICON = "appIcon";
1421cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_APP_LABEL = "appLabel";
1431cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_ORIGINATING_URI = "originatingUri";
1441cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_REFERRER_URI = "referrerUri";
1451cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_ABI_OVERRIDE = "abiOverride";
146b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey    private static final String ATTR_VOLUME_UUID = "volumeUuid";
1471cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
148f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey    /** Automatically destroy sessions older than this */
1491cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final long MAX_AGE_MILLIS = 3 * DateUtils.DAY_IN_MILLIS;
150f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey    /** Upper bound on number of active sessions for a UID */
1511cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final long MAX_ACTIVE_SESSIONS = 1024;
152f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey    /** Upper bound on number of historical sessions for a UID */
153f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey    private static final long MAX_HISTORICAL_SESSIONS = 1048576;
1541cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
1553a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private final Context mContext;
1563a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private final PackageManagerService mPm;
1573a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
158b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey    private AppOpsManager mAppOps;
159b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey    private StorageManager mStorage;
160b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey
161ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey    private final HandlerThread mInstallThread;
162cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey    private final Handler mInstallHandler;
1633a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1641cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private final Callbacks mCallbacks;
1651cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
1661cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    /**
16702bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey     * File storing persisted {@link #mSessions} metadata.
1681cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey     */
1691cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private final AtomicFile mSessionsFile;
1701cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
17102bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey    /**
17202bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey     * Directory storing persisted {@link #mSessions} metadata which is too
17302bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey     * heavy to store directly in {@link #mSessionsFile}.
17402bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey     */
17502bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey    private final File mSessionsDir;
17602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey
1771cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private final InternalCallback mInternalCallback = new InternalCallback();
1781cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
1791cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    /**
1801cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey     * Used for generating session IDs. Since this is created at boot time,
1811cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey     * normal random might be predictable.
1821cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey     */
1831cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private final Random mRandom = new SecureRandom();
1843a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1853a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    @GuardedBy("mSessions")
1863a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>();
1873a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1889a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey    /** Historical sessions kept around for debugging purposes */
1899a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey    @GuardedBy("mSessions")
1909a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey    private final SparseArray<PackageInstallerSession> mHistoricalSessions = new SparseArray<>();
1919a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey
192742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    /** Sessions allocated to legacy users */
193742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    @GuardedBy("mSessions")
194742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    private final SparseBooleanArray mLegacySessions = new SparseBooleanArray();
195742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
196ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey    private static final FilenameFilter sStageFilter = new FilenameFilter() {
197ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        @Override
198ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        public boolean accept(File dir, String name) {
199742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            return isStageName(name);
200ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        }
201ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey    };
202ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey
203b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey    public PackageInstallerService(Context context, PackageManagerService pm) {
2043a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        mContext = context;
2053a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        mPm = pm;
206ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey
207ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        mInstallThread = new HandlerThread(TAG);
208ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        mInstallThread.start();
2093a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
210cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey        mInstallHandler = new Handler(mInstallThread.getLooper());
211cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey
2121cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        mCallbacks = new Callbacks(mInstallThread.getLooper());
2131cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
2141cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        mSessionsFile = new AtomicFile(
2151cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                new File(Environment.getSystemSecureDirectory(), "install_sessions.xml"));
21602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey        mSessionsDir = new File(Environment.getSystemSecureDirectory(), "install_sessions");
21702bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey        mSessionsDir.mkdirs();
2181cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
2193a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        synchronized (mSessions) {
2203a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            readSessionsLocked();
2213a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
222b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey            final File internalStagingDir = buildInternalStagingDir();
22302bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            final ArraySet<File> unclaimedStages = Sets.newArraySet(
224b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey                    internalStagingDir.listFiles(sStageFilter));
22502bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            final ArraySet<File> unclaimedIcons = Sets.newArraySet(
22602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                    mSessionsDir.listFiles());
227742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
22802bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            // Ignore stages and icons claimed by active sessions
2293a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            for (int i = 0; i < mSessions.size(); i++) {
230ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey                final PackageInstallerSession session = mSessions.valueAt(i);
23102bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                unclaimedStages.remove(session.stageDir);
23202bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                unclaimedIcons.remove(buildAppIconFile(session.sessionId));
233ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey            }
234742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
235742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            // Clean up orphaned staging directories
23602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            for (File stage : unclaimedStages) {
237ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey                Slog.w(TAG, "Deleting orphan stage " + stage);
238ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey                if (stage.isDirectory()) {
239b94c1657eb0140f7b91f5372a9f76de5a3d87e36Fyodor Kupolov                    mPm.mInstaller.rmPackageDir(stage.getAbsolutePath());
240b94c1657eb0140f7b91f5372a9f76de5a3d87e36Fyodor Kupolov                } else {
241b94c1657eb0140f7b91f5372a9f76de5a3d87e36Fyodor Kupolov                    stage.delete();
242ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey                }
2433a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
24402bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey
24502bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            // Clean up orphaned icons
24602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            for (File icon : unclaimedIcons) {
24702bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                Slog.w(TAG, "Deleting orphan icon " + icon);
24802bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                icon.delete();
24902bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            }
250ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        }
251ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey    }
252ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey
253b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey    public void systemReady() {
254b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey        mAppOps = mContext.getSystemService(AppOpsManager.class);
255b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey        mStorage = mContext.getSystemService(StorageManager.class);
256b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey    }
257b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey
258742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    public void onSecureContainersAvailable() {
259742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        synchronized (mSessions) {
260742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            final ArraySet<String> unclaimed = new ArraySet<>();
261742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            for (String cid : PackageHelper.getSecureContainerList()) {
262742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                if (isStageName(cid)) {
263742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                    unclaimed.add(cid);
264742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                }
265742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            }
266742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
267742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            // Ignore stages claimed by active sessions
268742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            for (int i = 0; i < mSessions.size(); i++) {
269742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                final PackageInstallerSession session = mSessions.valueAt(i);
270941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                final String cid = session.stageCid;
271742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
272742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                if (unclaimed.remove(cid)) {
273742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                    // Claimed by active session, mount it
274742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                    PackageHelper.mountSdDir(cid, PackageManagerService.getEncryptKey(),
275742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                            Process.SYSTEM_UID);
276742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                }
277742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            }
278742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
279742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            // Clean up orphaned staging containers
280742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            for (String cid : unclaimed) {
281742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                Slog.w(TAG, "Deleting orphan container " + cid);
282742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                PackageHelper.destroySdDir(cid);
283742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            }
284742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        }
285742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    }
286742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
287742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    public static boolean isStageName(String name) {
288742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        final boolean isFile = name.startsWith("vmdl") && name.endsWith(".tmp");
289742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        final boolean isContainer = name.startsWith("smdl") && name.endsWith(".tmp");
290742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        final boolean isLegacyContainer = name.startsWith("smdl2tmp");
291742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        return isFile || isContainer || isLegacyContainer;
2927328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey    }
2937328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey
294ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey    @Deprecated
295b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey    public File allocateStageDirLegacy(String volumeUuid) throws IOException {
296ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        synchronized (mSessions) {
297ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey            try {
298ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey                final int sessionId = allocateSessionIdLocked();
299742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                mLegacySessions.put(sessionId, true);
300b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey                final File stageDir = buildStageDir(volumeUuid, sessionId);
301b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey                prepareStageDir(stageDir);
30277d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey                return stageDir;
303ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey            } catch (IllegalStateException e) {
304ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey                throw new IOException(e);
3053a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
3063a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
3073a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
3083a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
309742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    @Deprecated
310742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    public String allocateExternalStageCidLegacy() {
311742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        synchronized (mSessions) {
312742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            final int sessionId = allocateSessionIdLocked();
313742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            mLegacySessions.put(sessionId, true);
314742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            return "smdl" + sessionId + ".tmp";
315742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        }
316742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    }
317742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
3183a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private void readSessionsLocked() {
3191cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        if (LOGD) Slog.v(TAG, "readSessionsLocked()");
3201cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
3213a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        mSessions.clear();
3221cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
3231cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        FileInputStream fis = null;
3241cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        try {
3251cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            fis = mSessionsFile.openRead();
3261cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            final XmlPullParser in = Xml.newPullParser();
3279e9e2e73c6ec7bece20268196dc89ad0c8bafad4Wojciech Staszkiewicz            in.setInput(fis, StandardCharsets.UTF_8.name());
3281cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
3291cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            int type;
3301cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            while ((type = in.next()) != END_DOCUMENT) {
3311cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                if (type == START_TAG) {
3321cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    final String tag = in.getName();
3331cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    if (TAG_SESSION.equals(tag)) {
3341cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                        final PackageInstallerSession session = readSessionLocked(in);
3351cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                        final long age = System.currentTimeMillis() - session.createdMillis;
3361cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
3371cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                        final boolean valid;
3381cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                        if (age >= MAX_AGE_MILLIS) {
3391cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                            Slog.w(TAG, "Abandoning old session first created at "
3401cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                                    + session.createdMillis);
3411cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                            valid = false;
3421cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                        } else {
3431cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                            valid = true;
3441cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                        }
3451cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
3461cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                        if (valid) {
3471cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                            mSessions.put(session.sessionId, session);
3481cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                        } else {
3491cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                            // Since this is early during boot we don't send
3501cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                            // any observer events about the session, but we
3511cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                            // keep details around for dumpsys.
3521cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                            mHistoricalSessions.put(session.sessionId, session);
3531cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                        }
3541cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    }
3551cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                }
3561cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            }
3571cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        } catch (FileNotFoundException e) {
3581cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            // Missing sessions are okay, probably first boot
3591cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        } catch (IOException e) {
3608d05172112436a81bed6e4a0810f8914509d8a4dDianne Hackborn            Slog.wtf(TAG, "Failed reading install sessions", e);
3611cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        } catch (XmlPullParserException e) {
3628d05172112436a81bed6e4a0810f8914509d8a4dDianne Hackborn            Slog.wtf(TAG, "Failed reading install sessions", e);
3631cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        } finally {
3641cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            IoUtils.closeQuietly(fis);
3651cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        }
3661cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    }
3671cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
3681cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private PackageInstallerSession readSessionLocked(XmlPullParser in) throws IOException {
3691cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        final int sessionId = readIntAttribute(in, ATTR_SESSION_ID);
3701cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        final int userId = readIntAttribute(in, ATTR_USER_ID);
3711cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        final String installerPackageName = readStringAttribute(in, ATTR_INSTALLER_PACKAGE_NAME);
372e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey        final int installerUid = readIntAttribute(in, ATTR_INSTALLER_UID,
373e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey                mPm.getPackageUid(installerPackageName, userId));
3741cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        final long createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS);
375742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        final String stageDirRaw = readStringAttribute(in, ATTR_SESSION_STAGE_DIR);
376742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        final File stageDir = (stageDirRaw != null) ? new File(stageDirRaw) : null;
377742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        final String stageCid = readStringAttribute(in, ATTR_SESSION_STAGE_CID);
37877d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        final boolean prepared = readBooleanAttribute(in, ATTR_PREPARED, true);
3791cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        final boolean sealed = readBooleanAttribute(in, ATTR_SEALED);
3801cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
381a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        final SessionParams params = new SessionParams(
382a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                SessionParams.MODE_INVALID);
3831cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        params.mode = readIntAttribute(in, ATTR_MODE);
3841cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        params.installFlags = readIntAttribute(in, ATTR_INSTALL_FLAGS);
3851cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        params.installLocation = readIntAttribute(in, ATTR_INSTALL_LOCATION);
3861cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        params.sizeBytes = readLongAttribute(in, ATTR_SIZE_BYTES);
3871cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        params.appPackageName = readStringAttribute(in, ATTR_APP_PACKAGE_NAME);
3881cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        params.appIcon = readBitmapAttribute(in, ATTR_APP_ICON);
3891cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        params.appLabel = readStringAttribute(in, ATTR_APP_LABEL);
3901cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        params.originatingUri = readUriAttribute(in, ATTR_ORIGINATING_URI);
3911cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        params.referrerUri = readUriAttribute(in, ATTR_REFERRER_URI);
3921cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        params.abiOverride = readStringAttribute(in, ATTR_ABI_OVERRIDE);
393b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey        params.volumeUuid = readStringAttribute(in, ATTR_VOLUME_UUID);
3941cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
39502bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey        final File appIconFile = buildAppIconFile(sessionId);
39602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey        if (appIconFile.exists()) {
39702bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            params.appIcon = BitmapFactory.decodeFile(appIconFile.getAbsolutePath());
39802bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            params.appIconLastModified = appIconFile.lastModified();
39902bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey        }
40002bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey
401a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        return new PackageInstallerSession(mInternalCallback, mContext, mPm,
402e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey                mInstallThread.getLooper(), sessionId, userId, installerPackageName, installerUid,
403e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey                params, createdMillis, stageDir, stageCid, prepared, sealed);
4043a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
4053a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
4063a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private void writeSessionsLocked() {
4071cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        if (LOGD) Slog.v(TAG, "writeSessionsLocked()");
4081cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
4091cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        FileOutputStream fos = null;
4101cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        try {
4111cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            fos = mSessionsFile.startWrite();
4121cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
4131cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            XmlSerializer out = new FastXmlSerializer();
4149e9e2e73c6ec7bece20268196dc89ad0c8bafad4Wojciech Staszkiewicz            out.setOutput(fos, StandardCharsets.UTF_8.name());
4151cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            out.startDocument(null, true);
4161cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            out.startTag(null, TAG_SESSIONS);
4171cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            final int size = mSessions.size();
4181cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            for (int i = 0; i < size; i++) {
4191cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                final PackageInstallerSession session = mSessions.valueAt(i);
4201cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                writeSessionLocked(out, session);
4211cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            }
4221cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            out.endTag(null, TAG_SESSIONS);
4231cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            out.endDocument();
4241cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
4251cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            mSessionsFile.finishWrite(fos);
4261cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        } catch (IOException e) {
4271cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            if (fos != null) {
4281cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                mSessionsFile.failWrite(fos);
4291cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            }
4301cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        }
4311cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    }
4321cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
4331cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private void writeSessionLocked(XmlSerializer out, PackageInstallerSession session)
4341cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            throws IOException {
435a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        final SessionParams params = session.params;
4361cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
4371cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        out.startTag(null, TAG_SESSION);
4381cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
4391cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        writeIntAttribute(out, ATTR_SESSION_ID, session.sessionId);
4401cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        writeIntAttribute(out, ATTR_USER_ID, session.userId);
4411cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        writeStringAttribute(out, ATTR_INSTALLER_PACKAGE_NAME,
4421cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                session.installerPackageName);
443e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey        writeIntAttribute(out, ATTR_INSTALLER_UID, session.installerUid);
4441cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        writeLongAttribute(out, ATTR_CREATED_MILLIS, session.createdMillis);
445941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        if (session.stageDir != null) {
446742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            writeStringAttribute(out, ATTR_SESSION_STAGE_DIR,
447941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                    session.stageDir.getAbsolutePath());
448742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        }
449941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        if (session.stageCid != null) {
450941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            writeStringAttribute(out, ATTR_SESSION_STAGE_CID, session.stageCid);
451742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        }
45277d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        writeBooleanAttribute(out, ATTR_PREPARED, session.isPrepared());
453742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        writeBooleanAttribute(out, ATTR_SEALED, session.isSealed());
4541cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
4551cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        writeIntAttribute(out, ATTR_MODE, params.mode);
4561cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        writeIntAttribute(out, ATTR_INSTALL_FLAGS, params.installFlags);
4571cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        writeIntAttribute(out, ATTR_INSTALL_LOCATION, params.installLocation);
4581cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        writeLongAttribute(out, ATTR_SIZE_BYTES, params.sizeBytes);
4591cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        writeStringAttribute(out, ATTR_APP_PACKAGE_NAME, params.appPackageName);
4601cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        writeStringAttribute(out, ATTR_APP_LABEL, params.appLabel);
4611cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        writeUriAttribute(out, ATTR_ORIGINATING_URI, params.originatingUri);
4621cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        writeUriAttribute(out, ATTR_REFERRER_URI, params.referrerUri);
4631cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        writeStringAttribute(out, ATTR_ABI_OVERRIDE, params.abiOverride);
464b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey        writeStringAttribute(out, ATTR_VOLUME_UUID, params.volumeUuid);
4651cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
46602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey        // Persist app icon if changed since last written
46702bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey        final File appIconFile = buildAppIconFile(session.sessionId);
46802bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey        if (params.appIcon == null && appIconFile.exists()) {
46902bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            appIconFile.delete();
47002bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey        } else if (params.appIcon != null
47102bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                && appIconFile.lastModified() != params.appIconLastModified) {
47202bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            if (LOGD) Slog.w(TAG, "Writing changed icon " + appIconFile);
47302bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            FileOutputStream os = null;
47402bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            try {
47502bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                os = new FileOutputStream(appIconFile);
47602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                params.appIcon.compress(CompressFormat.PNG, 90, os);
47702bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            } catch (IOException e) {
47802bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                Slog.w(TAG, "Failed to write icon " + appIconFile + ": " + e.getMessage());
47902bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            } finally {
48002bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                IoUtils.closeQuietly(os);
48102bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            }
48202bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey
48302bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            params.appIconLastModified = appIconFile.lastModified();
48402bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey        }
48502bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey
4861cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        out.endTag(null, TAG_SESSION);
4873a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
4883a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
48902bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey    private File buildAppIconFile(int sessionId) {
49002bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey        return new File(mSessionsDir, "app_icon." + sessionId + ".png");
49102bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey    }
49202bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey
4933a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private void writeSessionsAsync() {
4943a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        IoThread.getHandler().post(new Runnable() {
4953a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            @Override
4963a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            public void run() {
4973a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                synchronized (mSessions) {
4983a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                    writeSessionsLocked();
4993a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                }
5003a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
5013a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        });
5023a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
5033a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
5043a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    @Override
505a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey    public int createSession(SessionParams params, String installerPackageName, int userId) {
506742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        try {
507742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            return createSessionInternal(params, installerPackageName, userId);
508742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        } catch (IOException e) {
509742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            throw ExceptionUtils.wrap(e);
510742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        }
511742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    }
512742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
513742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    private int createSessionInternal(SessionParams params, String installerPackageName, int userId)
514742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            throws IOException {
5153a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        final int callingUid = Binder.getCallingUid();
516e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey        mPm.enforceCrossUserPermission(callingUid, userId, true, true, "createSession");
5173a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
518e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey        if (mPm.isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
5193a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            throw new SecurityException("User restriction prevents installing");
5203a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
5213a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
5221cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {
523e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey            params.installFlags |= PackageManager.INSTALL_FROM_ADB;
5241cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
5253a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        } else {
526ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey            mAppOps.checkPackage(callingUid, installerPackageName);
527ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey
528e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey            params.installFlags &= ~PackageManager.INSTALL_FROM_ADB;
529e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey            params.installFlags &= ~PackageManager.INSTALL_ALL_USERS;
530e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey            params.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
5313a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
5323a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
533805b63e253c139625f5a86d72ef7b31d6ec9f8e9Svetoslav        // Only system components can circumvent runtime permissions when installing.
534805b63e253c139625f5a86d72ef7b31d6ec9f8e9Svetoslav        if ((params.installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0
535805b63e253c139625f5a86d72ef7b31d6ec9f8e9Svetoslav                && mContext.checkCallingOrSelfPermission(Manifest.permission
536805b63e253c139625f5a86d72ef7b31d6ec9f8e9Svetoslav                .INSTALL_GRANT_RUNTIME_PERMISSIONS) == PackageManager.PERMISSION_DENIED) {
537805b63e253c139625f5a86d72ef7b31d6ec9f8e9Svetoslav            throw new SecurityException("You need the "
538805b63e253c139625f5a86d72ef7b31d6ec9f8e9Svetoslav                    + "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS permission "
539805b63e253c139625f5a86d72ef7b31d6ec9f8e9Svetoslav                    + "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag");
540805b63e253c139625f5a86d72ef7b31d6ec9f8e9Svetoslav        }
541805b63e253c139625f5a86d72ef7b31d6ec9f8e9Svetoslav
5421cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        // Defensively resize giant app icons
5431cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        if (params.appIcon != null) {
5441cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            final ActivityManager am = (ActivityManager) mContext.getSystemService(
5451cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    Context.ACTIVITY_SERVICE);
5461cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            final int iconSize = am.getLauncherLargeIconSize();
5471cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            if ((params.appIcon.getWidth() > iconSize * 2)
5481cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    || (params.appIcon.getHeight() > iconSize * 2)) {
5491cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                params.appIcon = Bitmap.createScaledBitmap(params.appIcon, iconSize, iconSize,
5501cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                        true);
5511cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            }
5521cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        }
5531cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
554b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey        switch (params.mode) {
555b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey            case SessionParams.MODE_FULL_INSTALL:
556b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey            case SessionParams.MODE_INHERIT_EXISTING:
557b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey                break;
558b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey            default:
559b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey                throw new IllegalArgumentException("Invalid install mode: " + params.mode);
560b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey        }
561b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey
562b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey        // If caller requested explicit location, sanity check it, otherwise
563b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey        // resolve the best internal or adopted location.
564b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey        if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
565b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey            if (!PackageHelper.fitsOnInternal(mContext, params.sizeBytes)) {
566b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey                throw new IOException("No suitable internal storage available");
567b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey            }
568b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey
569b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey        } else if ((params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
570b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey            if (!PackageHelper.fitsOnExternal(mContext, params.sizeBytes)) {
571b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey                throw new IOException("No suitable external storage available");
572b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey            }
573b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey
574b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey        } else {
575b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey            // For now, installs to adopted media are treated as internal from
576b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey            // an install flag point-of-view.
577b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey            params.setInstallFlagsInternal();
578b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey
57977d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            // Resolve best location for install, based on combination of
58077d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            // requested install flags, delta size, and manifest settings.
581e812d9096915ad165de125520ed7371009587d1fRobin Lee            final long ident = Binder.clearCallingIdentity();
582e812d9096915ad165de125520ed7371009587d1fRobin Lee            try {
583b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey                params.volumeUuid = PackageHelper.resolveInstallVolume(mContext,
584b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey                        params.appPackageName, params.installLocation, params.sizeBytes);
585e812d9096915ad165de125520ed7371009587d1fRobin Lee            } finally {
586e812d9096915ad165de125520ed7371009587d1fRobin Lee                Binder.restoreCallingIdentity(ident);
587a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            }
588a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        }
589a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
590a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        final int sessionId;
591a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        final PackageInstallerSession session;
5923a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        synchronized (mSessions) {
5931cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            // Sanity check that installer isn't going crazy
594f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey            final int activeCount = getSessionCount(mSessions, callingUid);
5951cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            if (activeCount >= MAX_ACTIVE_SESSIONS) {
596f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey                throw new IllegalStateException(
597f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey                        "Too many active sessions for UID " + callingUid);
598f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey            }
599f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey            final int historicalCount = getSessionCount(mHistoricalSessions, callingUid);
600f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey            if (historicalCount >= MAX_HISTORICAL_SESSIONS) {
601f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey                throw new IllegalStateException(
602f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey                        "Too many historical sessions for UID " + callingUid);
6031cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            }
6041cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
605742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            final long createdMillis = System.currentTimeMillis();
606a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            sessionId = allocateSessionIdLocked();
607a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
608742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            // We're staging to exactly one location
609742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            File stageDir = null;
610742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            String stageCid = null;
61177d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
612b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey                stageDir = buildStageDir(params.volumeUuid, sessionId);
613742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            } else {
61477d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey                stageCid = buildExternalStageCid(sessionId);
615742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            }
6163a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
617a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            session = new PackageInstallerSession(mInternalCallback, mContext, mPm,
618e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey                    mInstallThread.getLooper(), sessionId, userId, installerPackageName, callingUid,
619e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey                    params, createdMillis, stageDir, stageCid, false, false);
6203a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            mSessions.put(sessionId, session);
6213a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
622a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
6231cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        mCallbacks.notifySessionCreated(session.sessionId, session.userId);
624a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        writeSessionsAsync();
625a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        return sessionId;
6263a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
6273a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
628381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey    @Override
629ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey    public void updateSessionAppIcon(int sessionId, Bitmap appIcon) {
630ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey        synchronized (mSessions) {
631ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            final PackageInstallerSession session = mSessions.get(sessionId);
632ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            if (session == null || !isCallingUidOwner(session)) {
633ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey                throw new SecurityException("Caller has no access to session " + sessionId);
634ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            }
63502bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey
63602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            // Defensively resize giant app icons
63702bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            if (appIcon != null) {
63802bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                final ActivityManager am = (ActivityManager) mContext.getSystemService(
63902bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                        Context.ACTIVITY_SERVICE);
64002bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                final int iconSize = am.getLauncherLargeIconSize();
64102bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                if ((appIcon.getWidth() > iconSize * 2)
64202bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                        || (appIcon.getHeight() > iconSize * 2)) {
64302bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                    appIcon = Bitmap.createScaledBitmap(appIcon, iconSize, iconSize, true);
64402bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                }
64502bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            }
64602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey
647ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            session.params.appIcon = appIcon;
64802bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            session.params.appIconLastModified = -1;
64902bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey
650ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            mInternalCallback.onSessionBadgingChanged(session);
651ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey        }
652ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey    }
653ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey
654ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey    @Override
655ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey    public void updateSessionAppLabel(int sessionId, String appLabel) {
656ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey        synchronized (mSessions) {
657ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            final PackageInstallerSession session = mSessions.get(sessionId);
658ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            if (session == null || !isCallingUidOwner(session)) {
659ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey                throw new SecurityException("Caller has no access to session " + sessionId);
660ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            }
661ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            session.params.appLabel = appLabel;
662ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            mInternalCallback.onSessionBadgingChanged(session);
663ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey        }
664ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey    }
665ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey
666ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey    @Override
667381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey    public void abandonSession(int sessionId) {
668381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey        synchronized (mSessions) {
669381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey            final PackageInstallerSession session = mSessions.get(sessionId);
670381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey            if (session == null || !isCallingUidOwner(session)) {
671381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey                throw new SecurityException("Caller has no access to session " + sessionId);
672381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey            }
673381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey            session.abandon();
674381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey        }
675381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey    }
676381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey
67777d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey    @Override
67877d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey    public IPackageInstallerSession openSession(int sessionId) {
67977d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        try {
68077d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            return openSessionInternal(sessionId);
68177d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        } catch (IOException e) {
68277d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            throw ExceptionUtils.wrap(e);
683742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        }
684742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    }
685742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
68677d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey    private IPackageInstallerSession openSessionInternal(int sessionId) throws IOException {
6873a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        synchronized (mSessions) {
6883a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            final PackageInstallerSession session = mSessions.get(sessionId);
689381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey            if (session == null || !isCallingUidOwner(session)) {
6903a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                throw new SecurityException("Caller has no access to session " + sessionId);
6913a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
692742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            session.open();
6933a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            return session;
6943a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
6953a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
6963a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
6973a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private int allocateSessionIdLocked() {
6981cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        int n = 0;
6991cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        int sessionId;
7001cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        do {
701f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey            sessionId = mRandom.nextInt(Integer.MAX_VALUE - 1) + 1;
702742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            if (mSessions.get(sessionId) == null && mHistoricalSessions.get(sessionId) == null
703742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                    && !mLegacySessions.get(sessionId, false)) {
7041cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                return sessionId;
7051cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            }
7061cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        } while (n++ < 32);
7071cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
7081cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        throw new IllegalStateException("Failed to allocate session ID");
7093a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
7103a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
711b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey    private File buildInternalStagingDir() {
712b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey        return new File(Environment.getDataDirectory(), "app");
713b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey    }
714b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey
715b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey    private File buildStagingDir(String volumeUuid) throws FileNotFoundException {
716b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey        if (volumeUuid == null) {
717b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey            return buildInternalStagingDir();
718b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey        } else {
719b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey            final VolumeInfo vol = mStorage.findVolumeByUuid(volumeUuid);
720b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey            if (vol != null && vol.type == VolumeInfo.TYPE_PRIVATE
721620b32b316fd4f1bab4eef55ec8802d14a55e7ddJeff Sharkey                    && vol.isMountedWritable()) {
722b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey                return new File(vol.path, "app");
723b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey            } else {
724b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey                throw new FileNotFoundException("Failed to find volume for UUID " + volumeUuid);
725b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey            }
726b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey        }
727b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey    }
728b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey
729b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey    private File buildStageDir(String volumeUuid, int sessionId) throws FileNotFoundException {
730b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey        final File stagingDir = buildStagingDir(volumeUuid);
731b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey        return new File(stagingDir, "vmdl" + sessionId + ".tmp");
73277d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey    }
733ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey
734b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey    static void prepareStageDir(File stageDir) throws IOException {
73577d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        if (stageDir.exists()) {
73677d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            throw new IOException("Session dir already exists: " + stageDir);
737ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        }
738ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey
739ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        try {
74077d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            Os.mkdir(stageDir.getAbsolutePath(), 0755);
74177d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            Os.chmod(stageDir.getAbsolutePath(), 0755);
742ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        } catch (ErrnoException e) {
743ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey            // This purposefully throws if directory already exists
74477d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            throw new IOException("Failed to prepare session dir: " + stageDir, e);
745ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        }
746ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey
74777d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        if (!SELinux.restorecon(stageDir)) {
74877d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            throw new IOException("Failed to restorecon session dir: " + stageDir);
749ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        }
750ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey    }
751ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey
75277d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey    private String buildExternalStageCid(int sessionId) {
75377d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        return "smdl" + sessionId + ".tmp";
75477d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey    }
755742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
75677d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey    static void prepareExternalStageCid(String stageCid, long sizeBytes) throws IOException {
75777d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        if (PackageHelper.createSdDir(sizeBytes, stageCid, PackageManagerService.getEncryptKey(),
758742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                Process.SYSTEM_UID, true) == null) {
75977d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            throw new IOException("Failed to create session cid: " + stageCid);
760742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        }
761742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    }
762742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
7633a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    @Override
764a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey    public SessionInfo getSessionInfo(int sessionId) {
76516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey        synchronized (mSessions) {
76616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey            final PackageInstallerSession session = mSessions.get(sessionId);
76716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey            return session != null ? session.generateInfo() : null;
76816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey        }
76916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey    }
77016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey
77116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey    @Override
77297d47ed036ff7bd3d7d2ddc1c6df1104ec237559Jeff Sharkey    public ParceledListSlice<SessionInfo> getAllSessions(int userId) {
7738cd28b57ed732656d002d97879e15c5695b54fffAmith Yamasani        mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, "getAllSessions");
7743a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
775a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        final List<SessionInfo> result = new ArrayList<>();
7763a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        synchronized (mSessions) {
7773a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            for (int i = 0; i < mSessions.size(); i++) {
7783a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                final PackageInstallerSession session = mSessions.valueAt(i);
779bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey                if (session.userId == userId) {
780bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey                    result.add(session.generateInfo());
7813a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                }
7823a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
7833a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
78497d47ed036ff7bd3d7d2ddc1c6df1104ec237559Jeff Sharkey        return new ParceledListSlice<>(result);
7853a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
7863a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
7873a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    @Override
78897d47ed036ff7bd3d7d2ddc1c6df1104ec237559Jeff Sharkey    public ParceledListSlice<SessionInfo> getMySessions(String installerPackageName, int userId) {
7898cd28b57ed732656d002d97879e15c5695b54fffAmith Yamasani        mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, "getMySessions");
79016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey        mAppOps.checkPackage(Binder.getCallingUid(), installerPackageName);
79116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey
792a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        final List<SessionInfo> result = new ArrayList<>();
79316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey        synchronized (mSessions) {
79416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey            for (int i = 0; i < mSessions.size(); i++) {
79516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey                final PackageInstallerSession session = mSessions.valueAt(i);
79616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey                if (Objects.equals(session.installerPackageName, installerPackageName)
79716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey                        && session.userId == userId) {
79816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey                    result.add(session.generateInfo());
79916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey                }
80016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey            }
80116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey        }
80297d47ed036ff7bd3d7d2ddc1c6df1104ec237559Jeff Sharkey        return new ParceledListSlice<>(result);
80316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey    }
80416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey
80516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey    @Override
80639fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz    public void uninstall(String packageName, String callerPackageName, int flags,
80739fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                IntentSender statusReceiver, int userId) {
80839fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        final int callingUid = Binder.getCallingUid();
80939fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        mPm.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
81039fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        if ((callingUid != Process.SHELL_UID) && (callingUid != Process.ROOT_UID)) {
81139fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz            mAppOps.checkPackage(callingUid, callerPackageName);
81239fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        }
81339fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz
81439fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        // Check whether the caller is device owner
81539fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(
81639fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                Context.DEVICE_POLICY_SERVICE);
81739fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        boolean isDeviceOwner = (dpm != null) && dpm.isDeviceOwnerApp(callerPackageName);
81816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey
819a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext,
82039fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                statusReceiver, packageName, isDeviceOwner, userId);
821f06009542390472872da986486d385001e91a2a7Jeff Sharkey        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES)
822f06009542390472872da986486d385001e91a2a7Jeff Sharkey                == PackageManager.PERMISSION_GRANTED) {
823f06009542390472872da986486d385001e91a2a7Jeff Sharkey            // Sweet, call straight through!
824a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            mPm.deletePackage(packageName, adapter.getBinder(), userId, flags);
82539fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        } else if (isDeviceOwner) {
82639fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz            // Allow the DeviceOwner to silently delete packages
82739fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz            // Need to clear the calling identity to get DELETE_PACKAGES permission
82839fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz            long ident = Binder.clearCallingIdentity();
82939fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz            try {
83039fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                mPm.deletePackage(packageName, adapter.getBinder(), userId, flags);
83139fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz            } finally {
83239fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                Binder.restoreCallingIdentity(ident);
83339fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz            }
834f06009542390472872da986486d385001e91a2a7Jeff Sharkey        } else {
835f06009542390472872da986486d385001e91a2a7Jeff Sharkey            // Take a short detour to confirm with user
836f06009542390472872da986486d385001e91a2a7Jeff Sharkey            final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
837f06009542390472872da986486d385001e91a2a7Jeff Sharkey            intent.setData(Uri.fromParts("package", packageName, null));
838a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            intent.putExtra(PackageInstaller.EXTRA_CALLBACK, adapter.getBinder().asBinder());
839a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            adapter.onUserActionRequired(intent);
840f06009542390472872da986486d385001e91a2a7Jeff Sharkey        }
8413a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
8423a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
8433a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    @Override
8447328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey    public void setPermissionsResult(int sessionId, boolean accepted) {
8457328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, TAG);
8467328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey
8477328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey        synchronized (mSessions) {
8487328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey            mSessions.get(sessionId).setPermissionsResult(accepted);
8497328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey        }
8507328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey    }
8517328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey
8527328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey    @Override
85316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey    public void registerCallback(IPackageInstallerCallback callback, int userId) {
8548cd28b57ed732656d002d97879e15c5695b54fffAmith Yamasani        mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, "registerCallback");
8551cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        mCallbacks.register(callback, userId);
856bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey    }
857bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey
858bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey    @Override
85916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey    public void unregisterCallback(IPackageInstallerCallback callback) {
86016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey        mCallbacks.unregister(callback);
861a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey    }
862a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
863f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey    private static int getSessionCount(SparseArray<PackageInstallerSession> sessions,
864f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey            int installerUid) {
8651cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        int count = 0;
866f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey        final int size = sessions.size();
8671cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        for (int i = 0; i < size; i++) {
868f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey            final PackageInstallerSession session = sessions.valueAt(i);
8691cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            if (session.installerUid == installerUid) {
8701cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                count++;
8711cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            }
8721cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        }
8731cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        return count;
8741cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    }
8751cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
8761cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private boolean isCallingUidOwner(PackageInstallerSession session) {
8771cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        final int callingUid = Binder.getCallingUid();
8781cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        if (callingUid == Process.ROOT_UID) {
8791cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            return true;
8801cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        } else {
8811cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            return (session != null) && (callingUid == session.installerUid);
882a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        }
883a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey    }
884a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
885a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey    static class PackageDeleteObserverAdapter extends PackageDeleteObserver {
886a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        private final Context mContext;
887a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        private final IntentSender mTarget;
888bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey        private final String mPackageName;
88939fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        private final Notification mNotification;
890a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey
891bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey        public PackageDeleteObserverAdapter(Context context, IntentSender target,
89239fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                String packageName, boolean showNotification, int userId) {
893a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            mContext = context;
894a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            mTarget = target;
895bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            mPackageName = packageName;
89639fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz            if (showNotification) {
89739fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                mNotification = buildSuccessNotification(mContext,
89839fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                        mContext.getResources().getString(R.string.package_deleted_device_owner),
89939fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                        packageName,
90039fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                        userId);
90139fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz            } else {
90239fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                mNotification = null;
90339fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz            }
904a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        }
905a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey
906a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        @Override
907a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        public void onUserActionRequired(Intent intent) {
908a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            final Intent fillIn = new Intent();
909bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName);
910a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
911742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                    PackageInstaller.STATUS_PENDING_USER_ACTION);
912a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            fillIn.putExtra(Intent.EXTRA_INTENT, intent);
913a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            try {
914a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                mTarget.sendIntent(mContext, 0, fillIn, null, null);
915a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            } catch (SendIntentException ignored) {
916a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            }
917a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        }
918a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey
919a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        @Override
920a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        public void onPackageDeleted(String basePackageName, int returnCode, String msg) {
92139fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz            if (PackageManager.DELETE_SUCCEEDED == returnCode && mNotification != null) {
92239fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                NotificationManager notificationManager = (NotificationManager)
92339fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                        mContext.getSystemService(Context.NOTIFICATION_SERVICE);
92439fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                notificationManager.notify(basePackageName, 0, mNotification);
92539fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz            }
926a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            final Intent fillIn = new Intent();
927bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName);
928a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
929a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                    PackageManager.deleteStatusToPublicStatus(returnCode));
930a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
931a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                    PackageManager.deleteStatusToString(returnCode, msg));
932a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode);
933a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            try {
934a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                mTarget.sendIntent(mContext, 0, fillIn, null, null);
935a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            } catch (SendIntentException ignored) {
936a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            }
937a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        }
938a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey    }
939a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey
940a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey    static class PackageInstallObserverAdapter extends PackageInstallObserver {
941a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        private final Context mContext;
942a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        private final IntentSender mTarget;
943bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey        private final int mSessionId;
94439fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        private final boolean mShowNotification;
94539fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        private final int mUserId;
946a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey
94739fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        public PackageInstallObserverAdapter(Context context, IntentSender target, int sessionId,
94839fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                boolean showNotification, int userId) {
949a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            mContext = context;
950a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            mTarget = target;
951bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            mSessionId = sessionId;
95239fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz            mShowNotification = showNotification;
95339fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz            mUserId = userId;
954a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        }
955a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey
956a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        @Override
957a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        public void onUserActionRequired(Intent intent) {
958a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            final Intent fillIn = new Intent();
959bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId);
960a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
961742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                    PackageInstaller.STATUS_PENDING_USER_ACTION);
962a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            fillIn.putExtra(Intent.EXTRA_INTENT, intent);
963a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            try {
964a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                mTarget.sendIntent(mContext, 0, fillIn, null, null);
965a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            } catch (SendIntentException ignored) {
966a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            }
967a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        }
968a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey
969a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        @Override
970a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        public void onPackageInstalled(String basePackageName, int returnCode, String msg,
971a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                Bundle extras) {
97239fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz            if (PackageManager.INSTALL_SUCCEEDED == returnCode && mShowNotification) {
9732e3e943ccd419dd10d3e4df5ae7640e8b020cc76Benjamin Franz                boolean update = (extras != null) && extras.getBoolean(Intent.EXTRA_REPLACING);
97439fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                Notification notification = buildSuccessNotification(mContext,
9752e3e943ccd419dd10d3e4df5ae7640e8b020cc76Benjamin Franz                        mContext.getResources()
9762e3e943ccd419dd10d3e4df5ae7640e8b020cc76Benjamin Franz                                .getString(update ? R.string.package_updated_device_owner :
9772e3e943ccd419dd10d3e4df5ae7640e8b020cc76Benjamin Franz                                        R.string.package_installed_device_owner),
97839fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                        basePackageName,
97939fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                        mUserId);
98039fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                if (notification != null) {
98139fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                    NotificationManager notificationManager = (NotificationManager)
98239fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                            mContext.getSystemService(Context.NOTIFICATION_SERVICE);
98339fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                    notificationManager.notify(basePackageName, 0, notification);
98439fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                }
98539fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz            }
986a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            final Intent fillIn = new Intent();
9872e3e943ccd419dd10d3e4df5ae7640e8b020cc76Benjamin Franz            fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, basePackageName);
988bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId);
989a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
990a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                    PackageManager.installStatusToPublicStatus(returnCode));
991a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
992a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                    PackageManager.installStatusToString(returnCode, msg));
993a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode);
994a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            if (extras != null) {
995a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                final String existing = extras.getString(
996a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                        PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE);
997a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                if (!TextUtils.isEmpty(existing)) {
998941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                    fillIn.putExtra(PackageInstaller.EXTRA_OTHER_PACKAGE_NAME, existing);
999a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                }
1000a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            }
1001a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            try {
1002a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                mTarget.sendIntent(mContext, 0, fillIn, null, null);
1003a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            } catch (SendIntentException ignored) {
1004a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            }
1005a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        }
1006a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey    }
1007a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey
100839fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz    /**
100939fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz     * Build a notification for package installation / deletion by device owners that is shown if
101039fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz     * the operation succeeds.
101139fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz     */
101239fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz    private static Notification buildSuccessNotification(Context context, String contentText,
101339fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz            String basePackageName, int userId) {
101439fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        PackageInfo packageInfo = null;
101539fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        try {
101639fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz            packageInfo = AppGlobals.getPackageManager().getPackageInfo(
101739fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                    basePackageName, 0, userId);
101839fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        } catch (RemoteException ignored) {
101939fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        }
102039fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        if (packageInfo == null || packageInfo.applicationInfo == null) {
102139fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz            Slog.w(TAG, "Notification not built for package: " + basePackageName);
102239fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz            return null;
102339fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        }
102439fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        PackageManager pm = context.getPackageManager();
102539fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        Bitmap packageIcon = ImageUtils.buildScaledBitmap(
102639fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                packageInfo.applicationInfo.loadIcon(pm),
102739fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                context.getResources().getDimensionPixelSize(
102839fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                        android.R.dimen.notification_large_icon_width),
102939fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                context.getResources().getDimensionPixelSize(
103039fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                        android.R.dimen.notification_large_icon_height));
103139fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        CharSequence packageLabel = packageInfo.applicationInfo.loadLabel(pm);
103239fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        return new Notification.Builder(context)
103339fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                .setSmallIcon(R.drawable.ic_check_circle_24px)
103439fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                .setColor(context.getResources().getColor(
103539fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                        R.color.system_notification_accent_color))
103639fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                .setContentTitle(packageLabel)
103739fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                .setContentText(contentText)
10382e3e943ccd419dd10d3e4df5ae7640e8b020cc76Benjamin Franz                .setStyle(new Notification.BigTextStyle().bigText(contentText))
103939fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                .setLargeIcon(packageIcon)
104039fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                .build();
104139fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz    }
104239fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz
10431cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static class Callbacks extends Handler {
10441cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        private static final int MSG_SESSION_CREATED = 1;
1045ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey        private static final int MSG_SESSION_BADGING_CHANGED = 2;
1046bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey        private static final int MSG_SESSION_ACTIVE_CHANGED = 3;
1047ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey        private static final int MSG_SESSION_PROGRESS_CHANGED = 4;
1048bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey        private static final int MSG_SESSION_FINISHED = 5;
10491cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
10501cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        private final RemoteCallbackList<IPackageInstallerCallback>
10511cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                mCallbacks = new RemoteCallbackList<>();
10521cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
10531cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        public Callbacks(Looper looper) {
10541cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            super(looper);
1055a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        }
1056a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
10571cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        public void register(IPackageInstallerCallback callback, int userId) {
10581cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            mCallbacks.register(callback, new UserHandle(userId));
10591cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        }
10601cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
10611cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        public void unregister(IPackageInstallerCallback callback) {
10621cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            mCallbacks.unregister(callback);
10631cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        }
10641cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
10651cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        @Override
10661cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        public void handleMessage(Message msg) {
10671cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            final int userId = msg.arg2;
10681cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            final int n = mCallbacks.beginBroadcast();
10691cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            for (int i = 0; i < n; i++) {
10701cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                final IPackageInstallerCallback callback = mCallbacks.getBroadcastItem(i);
10711cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                final UserHandle user = (UserHandle) mCallbacks.getBroadcastCookie(i);
10721cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                // TODO: dispatch notifications for slave profiles
10731cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                if (userId == user.getIdentifier()) {
10741cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    try {
10751cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                        invokeCallback(callback, msg);
10761cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    } catch (RemoteException ignored) {
10771cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    }
1078a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey                }
1079a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            }
10801cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            mCallbacks.finishBroadcast();
1081a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        }
1082a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
10831cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        private void invokeCallback(IPackageInstallerCallback callback, Message msg)
10841cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                throws RemoteException {
10851cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            final int sessionId = msg.arg1;
10861cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            switch (msg.what) {
10871cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                case MSG_SESSION_CREATED:
10881cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    callback.onSessionCreated(sessionId);
10891cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    break;
1090ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey                case MSG_SESSION_BADGING_CHANGED:
1091ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey                    callback.onSessionBadgingChanged(sessionId);
1092ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey                    break;
1093bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey                case MSG_SESSION_ACTIVE_CHANGED:
1094bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey                    callback.onSessionActiveChanged(sessionId, (boolean) msg.obj);
10951cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    break;
10961cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                case MSG_SESSION_PROGRESS_CHANGED:
10971cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    callback.onSessionProgressChanged(sessionId, (float) msg.obj);
10981cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    break;
10991cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                case MSG_SESSION_FINISHED:
11001cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    callback.onSessionFinished(sessionId, (boolean) msg.obj);
11011cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    break;
1102a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            }
1103a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        }
11041cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
11051cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        private void notifySessionCreated(int sessionId, int userId) {
11061cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            obtainMessage(MSG_SESSION_CREATED, sessionId, userId).sendToTarget();
11071cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        }
11081cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
1109ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey        private void notifySessionBadgingChanged(int sessionId, int userId) {
1110ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            obtainMessage(MSG_SESSION_BADGING_CHANGED, sessionId, userId).sendToTarget();
1111ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey        }
1112ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey
1113bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey        private void notifySessionActiveChanged(int sessionId, int userId, boolean active) {
1114bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey            obtainMessage(MSG_SESSION_ACTIVE_CHANGED, sessionId, userId, active).sendToTarget();
11151cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        }
11161cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
11171cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        private void notifySessionProgressChanged(int sessionId, int userId, float progress) {
11181cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            obtainMessage(MSG_SESSION_PROGRESS_CHANGED, sessionId, userId, progress).sendToTarget();
11191cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        }
11201cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
11211cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        public void notifySessionFinished(int sessionId, int userId, boolean success) {
11221cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            obtainMessage(MSG_SESSION_FINISHED, sessionId, userId, success).sendToTarget();
11231cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        }
1124a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey    }
1125a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
1126a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey    void dump(IndentingPrintWriter pw) {
1127a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        synchronized (mSessions) {
11289a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey            pw.println("Active install sessions:");
11299a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey            pw.increaseIndent();
11309a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey            int N = mSessions.size();
1131a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            for (int i = 0; i < N; i++) {
1132a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey                final PackageInstallerSession session = mSessions.valueAt(i);
1133a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey                session.dump(pw);
1134a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey                pw.println();
1135a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            }
11369a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey            pw.println();
11379a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey            pw.decreaseIndent();
11389a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey
11399a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey            pw.println("Historical install sessions:");
11409a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey            pw.increaseIndent();
11419a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey            N = mHistoricalSessions.size();
11429a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey            for (int i = 0; i < N; i++) {
11439a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey                final PackageInstallerSession session = mHistoricalSessions.valueAt(i);
11449a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey                session.dump(pw);
11459a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey                pw.println();
11469a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey            }
11479a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey            pw.println();
11489a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey            pw.decreaseIndent();
1149742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
1150742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            pw.println("Legacy install sessions:");
1151742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            pw.increaseIndent();
1152742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            pw.println(mLegacySessions.toString());
1153742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            pw.decreaseIndent();
1154a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        }
1155bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey    }
1156bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey
11571cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    class InternalCallback {
1158ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey        public void onSessionBadgingChanged(PackageInstallerSession session) {
1159ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            mCallbacks.notifySessionBadgingChanged(session.sessionId, session.userId);
1160ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            writeSessionsAsync();
11611cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        }
11621cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
1163bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey        public void onSessionActiveChanged(PackageInstallerSession session, boolean active) {
1164bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey            mCallbacks.notifySessionActiveChanged(session.sessionId, session.userId, active);
1165742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        }
1166742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
1167ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey        public void onSessionProgressChanged(PackageInstallerSession session, float progress) {
1168ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            mCallbacks.notifySessionProgressChanged(session.sessionId, session.userId, progress);
1169ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey        }
1170ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey
1171cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey        public void onSessionFinished(final PackageInstallerSession session, boolean success) {
11721cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            mCallbacks.notifySessionFinished(session.sessionId, session.userId, success);
1173cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey
1174cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey            mInstallHandler.post(new Runnable() {
1175cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey                @Override
1176cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey                public void run() {
1177cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey                    synchronized (mSessions) {
1178cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey                        mSessions.remove(session.sessionId);
1179cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey                        mHistoricalSessions.put(session.sessionId, session);
118002bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey
118102bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                        final File appIconFile = buildAppIconFile(session.sessionId);
118202bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                        if (appIconFile.exists()) {
118302bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                            appIconFile.delete();
118402bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                        }
118502bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey
1186cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey                        writeSessionsLocked();
1187cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey                    }
1188cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey                }
1189cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey            });
11903a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
1191bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey
119277d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        public void onSessionPrepared(PackageInstallerSession session) {
119377d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            // We prepared the destination to write into; we want to persist
119477d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            // this, but it's not critical enough to block for.
119577d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            writeSessionsAsync();
119677d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        }
119777d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey
1198cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey        public void onSessionSealedBlocking(PackageInstallerSession session) {
1199bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            // It's very important that we block until we've recorded the
1200bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            // session as being sealed, since we never want to allow mutation
1201bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            // after sealing.
1202cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey            synchronized (mSessions) {
1203cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey                writeSessionsLocked();
1204cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey            }
1205bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey        }
12063a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
12073a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey}
1208