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;
463a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.content.pm.IPackageInstaller;
4716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkeyimport android.content.pm.IPackageInstallerCallback;
483a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.content.pm.IPackageInstallerSession;
4939fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franzimport android.content.pm.PackageInfo;
50f06009542390472872da986486d385001e91a2a7Jeff Sharkeyimport android.content.pm.PackageInstaller;
51a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.content.pm.PackageInstaller.SessionInfo;
52a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.content.pm.PackageInstaller.SessionParams;
53ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkeyimport android.content.pm.PackageManager;
5497d47ed036ff7bd3d7d2ddc1c6df1104ec237559Jeff Sharkeyimport android.content.pm.ParceledListSlice;
551cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.graphics.Bitmap;
5602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkeyimport android.graphics.Bitmap.CompressFormat;
5702bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkeyimport android.graphics.BitmapFactory;
58f06009542390472872da986486d385001e91a2a7Jeff Sharkeyimport android.net.Uri;
593a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.Binder;
60a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.os.Bundle;
611cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.os.Environment;
621cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.os.Handler;
633a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.HandlerThread;
641cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.os.Looper;
651cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.os.Message;
663a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.Process;
67a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkeyimport android.os.RemoteCallbackList;
68a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkeyimport android.os.RemoteException;
69ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport android.os.SELinux;
703a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.UserHandle;
713a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.UserManager;
72b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkeyimport android.os.storage.StorageManager;
73ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport android.system.ErrnoException;
74ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport android.system.Os;
75a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.text.TextUtils;
761cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.text.format.DateUtils;
773a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.util.ArraySet;
781cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.util.AtomicFile;
79a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkeyimport android.util.ExceptionUtils;
803a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.util.Slog;
813a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.util.SparseArray;
82742e790294b3441b79f715fe447069b63c6065dbJeff Sharkeyimport android.util.SparseBooleanArray;
831cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.util.Xml;
843a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
85b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkeyimport libcore.io.IoUtils;
86b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey
8739fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franzimport com.android.internal.R;
883a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport com.android.internal.annotations.GuardedBy;
89742e790294b3441b79f715fe447069b63c6065dbJeff Sharkeyimport com.android.internal.content.PackageHelper;
901cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport com.android.internal.util.FastXmlSerializer;
9139fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franzimport com.android.internal.util.ImageUtils;
92a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkeyimport com.android.internal.util.IndentingPrintWriter;
933a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport com.android.server.IoThread;
943a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
951cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport org.xmlpull.v1.XmlPullParser;
961cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport org.xmlpull.v1.XmlPullParserException;
971cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport org.xmlpull.v1.XmlSerializer;
981cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
993a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport java.io.File;
1001cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport java.io.FileInputStream;
1011cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport java.io.FileNotFoundException;
1021cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport java.io.FileOutputStream;
103ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport java.io.FilenameFilter;
104ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport java.io.IOException;
1059e9e2e73c6ec7bece20268196dc89ad0c8bafad4Wojciech Staszkiewiczimport java.nio.charset.StandardCharsets;
1061cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport java.security.SecureRandom;
107bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkeyimport java.util.ArrayList;
10854d42be6eb149b3e43115e810e4a1b92e9865d05Jeff Sharkeyimport java.util.Collections;
109bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkeyimport java.util.List;
11016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkeyimport java.util.Objects;
1111cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport java.util.Random;
1123a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1133a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeypublic class PackageInstallerService extends IPackageInstaller.Stub {
1143a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private static final String TAG = "PackageInstaller";
115e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey    private static final boolean LOGD = false;
1163a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1173a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    // TODO: remove outstanding sessions when installer package goes away
1186c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey    // TODO: notify listeners in other users when package has been installed there
119742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    // TODO: purge expired sessions periodically in addition to at reboot
1203a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1211cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    /** XML constants used in {@link #mSessionsFile} */
1221cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String TAG_SESSIONS = "sessions";
1231cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String TAG_SESSION = "session";
1247121e18595d4c559044e26bfe6035406a862f466Svet Ganov    private static final String TAG_GRANTED_RUNTIME_PERMISSION = "granted-runtime-permission";
1251cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_SESSION_ID = "sessionId";
1261cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_USER_ID = "userId";
1271cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_INSTALLER_PACKAGE_NAME = "installerPackageName";
128e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey    private static final String ATTR_INSTALLER_UID = "installerUid";
1291cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_CREATED_MILLIS = "createdMillis";
1301cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_SESSION_STAGE_DIR = "sessionStageDir";
131742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    private static final String ATTR_SESSION_STAGE_CID = "sessionStageCid";
13277d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey    private static final String ATTR_PREPARED = "prepared";
1331cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_SEALED = "sealed";
1341cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_MODE = "mode";
1351cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_INSTALL_FLAGS = "installFlags";
1361cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_INSTALL_LOCATION = "installLocation";
1371cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_SIZE_BYTES = "sizeBytes";
1381cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_APP_PACKAGE_NAME = "appPackageName";
13902bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey    @Deprecated
1401cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_APP_ICON = "appIcon";
1411cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_APP_LABEL = "appLabel";
1421cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_ORIGINATING_URI = "originatingUri";
143a1d12cfdb072acb14fa95d5e771e23396e6bd8e1Todd Kennedy    private static final String ATTR_ORIGINATING_UID = "originatingUid";
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";
1477121e18595d4c559044e26bfe6035406a862f466Svet Ganov    private static final String ATTR_NAME = "name";
1481cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
149f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey    /** Automatically destroy sessions older than this */
1501cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final long MAX_AGE_MILLIS = 3 * DateUtils.DAY_IN_MILLIS;
151f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey    /** Upper bound on number of active sessions for a UID */
1521cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final long MAX_ACTIVE_SESSIONS = 1024;
153f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey    /** Upper bound on number of historical sessions for a UID */
154f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey    private static final long MAX_HISTORICAL_SESSIONS = 1048576;
1551cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
1563a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private final Context mContext;
1573a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private final PackageManagerService mPm;
1583a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
159b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey    private AppOpsManager mAppOps;
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
18528c4e806ea6cb12b3b83af8447b6647471a15d38Todd Kennedy    /** All sessions allocated */
18628c4e806ea6cb12b3b83af8447b6647471a15d38Todd Kennedy    @GuardedBy("mSessions")
18728c4e806ea6cb12b3b83af8447b6647471a15d38Todd Kennedy    private final SparseBooleanArray mAllocatedSessions = new SparseBooleanArray();
18828c4e806ea6cb12b3b83af8447b6647471a15d38Todd Kennedy
1893a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    @GuardedBy("mSessions")
1903a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>();
1913a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1929a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey    /** Historical sessions kept around for debugging purposes */
1939a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey    @GuardedBy("mSessions")
1949a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey    private final SparseArray<PackageInstallerSession> mHistoricalSessions = new SparseArray<>();
1959a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey
196742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    /** Sessions allocated to legacy users */
197742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    @GuardedBy("mSessions")
198742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    private final SparseBooleanArray mLegacySessions = new SparseBooleanArray();
199742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
200ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey    private static final FilenameFilter sStageFilter = new FilenameFilter() {
201ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        @Override
202ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        public boolean accept(File dir, String name) {
203742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            return isStageName(name);
204ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        }
205ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey    };
206ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey
207b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey    public PackageInstallerService(Context context, PackageManagerService pm) {
2083a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        mContext = context;
2093a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        mPm = pm;
210ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey
211ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        mInstallThread = new HandlerThread(TAG);
212ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        mInstallThread.start();
2133a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
214cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey        mInstallHandler = new Handler(mInstallThread.getLooper());
215cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey
2161cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        mCallbacks = new Callbacks(mInstallThread.getLooper());
2171cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
2181cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        mSessionsFile = new AtomicFile(
2198212ae0aee1700b9c287ebadf15af8dacdc8eae6Jeff Sharkey                new File(Environment.getDataSystemDirectory(), "install_sessions.xml"));
2208212ae0aee1700b9c287ebadf15af8dacdc8eae6Jeff Sharkey        mSessionsDir = new File(Environment.getDataSystemDirectory(), "install_sessions");
22102bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey        mSessionsDir.mkdirs();
2221cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
2233a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        synchronized (mSessions) {
2243a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            readSessionsLocked();
2253a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
2262699f065558ba78066887210b0c7346105959860Todd Kennedy            reconcileStagesLocked(StorageManager.UUID_PRIVATE_INTERNAL, false /*isEphemeral*/);
2272699f065558ba78066887210b0c7346105959860Todd Kennedy            reconcileStagesLocked(StorageManager.UUID_PRIVATE_INTERNAL, true /*isEphemeral*/);
2286dce4964b4d1a13d276d95730b8fb09d6a5a8d04Jeff Sharkey
22954d42be6eb149b3e43115e810e4a1b92e9865d05Jeff Sharkey            final ArraySet<File> unclaimedIcons = newArraySet(
23002bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                    mSessionsDir.listFiles());
231742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
23202bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            // Ignore stages and icons claimed by active sessions
2333a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            for (int i = 0; i < mSessions.size(); i++) {
234ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey                final PackageInstallerSession session = mSessions.valueAt(i);
23502bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                unclaimedIcons.remove(buildAppIconFile(session.sessionId));
236ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey            }
237742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
23802bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            // Clean up orphaned icons
23902bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            for (File icon : unclaimedIcons) {
24002bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                Slog.w(TAG, "Deleting orphan icon " + icon);
24102bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                icon.delete();
24202bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            }
243ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        }
244ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey    }
245ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey
246b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey    public void systemReady() {
247b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey        mAppOps = mContext.getSystemService(AppOpsManager.class);
248b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey    }
249b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey
2502699f065558ba78066887210b0c7346105959860Todd Kennedy    private void reconcileStagesLocked(String volumeUuid, boolean isEphemeral) {
2512699f065558ba78066887210b0c7346105959860Todd Kennedy        final File stagingDir = buildStagingDir(volumeUuid, isEphemeral);
25254d42be6eb149b3e43115e810e4a1b92e9865d05Jeff Sharkey        final ArraySet<File> unclaimedStages = newArraySet(
2536dce4964b4d1a13d276d95730b8fb09d6a5a8d04Jeff Sharkey                stagingDir.listFiles(sStageFilter));
2546dce4964b4d1a13d276d95730b8fb09d6a5a8d04Jeff Sharkey
2556dce4964b4d1a13d276d95730b8fb09d6a5a8d04Jeff Sharkey        // Ignore stages claimed by active sessions
2566dce4964b4d1a13d276d95730b8fb09d6a5a8d04Jeff Sharkey        for (int i = 0; i < mSessions.size(); i++) {
2576dce4964b4d1a13d276d95730b8fb09d6a5a8d04Jeff Sharkey            final PackageInstallerSession session = mSessions.valueAt(i);
2586dce4964b4d1a13d276d95730b8fb09d6a5a8d04Jeff Sharkey            unclaimedStages.remove(session.stageDir);
2596dce4964b4d1a13d276d95730b8fb09d6a5a8d04Jeff Sharkey        }
2606dce4964b4d1a13d276d95730b8fb09d6a5a8d04Jeff Sharkey
2616dce4964b4d1a13d276d95730b8fb09d6a5a8d04Jeff Sharkey        // Clean up orphaned staging directories
2626dce4964b4d1a13d276d95730b8fb09d6a5a8d04Jeff Sharkey        for (File stage : unclaimedStages) {
2636dce4964b4d1a13d276d95730b8fb09d6a5a8d04Jeff Sharkey            Slog.w(TAG, "Deleting orphan stage " + stage);
2646dce4964b4d1a13d276d95730b8fb09d6a5a8d04Jeff Sharkey            synchronized (mPm.mInstallLock) {
265fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkey                mPm.removeCodePathLI(stage);
2666dce4964b4d1a13d276d95730b8fb09d6a5a8d04Jeff Sharkey            }
2676dce4964b4d1a13d276d95730b8fb09d6a5a8d04Jeff Sharkey        }
2686dce4964b4d1a13d276d95730b8fb09d6a5a8d04Jeff Sharkey    }
2696dce4964b4d1a13d276d95730b8fb09d6a5a8d04Jeff Sharkey
2706dce4964b4d1a13d276d95730b8fb09d6a5a8d04Jeff Sharkey    public void onPrivateVolumeMounted(String volumeUuid) {
2716dce4964b4d1a13d276d95730b8fb09d6a5a8d04Jeff Sharkey        synchronized (mSessions) {
2722699f065558ba78066887210b0c7346105959860Todd Kennedy            reconcileStagesLocked(volumeUuid, false /*isEphemeral*/);
2736dce4964b4d1a13d276d95730b8fb09d6a5a8d04Jeff Sharkey        }
2746dce4964b4d1a13d276d95730b8fb09d6a5a8d04Jeff Sharkey    }
2756dce4964b4d1a13d276d95730b8fb09d6a5a8d04Jeff Sharkey
276742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    public void onSecureContainersAvailable() {
277742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        synchronized (mSessions) {
278742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            final ArraySet<String> unclaimed = new ArraySet<>();
279742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            for (String cid : PackageHelper.getSecureContainerList()) {
280742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                if (isStageName(cid)) {
281742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                    unclaimed.add(cid);
282742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                }
283742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            }
284742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
285742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            // Ignore stages claimed by active sessions
286742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            for (int i = 0; i < mSessions.size(); i++) {
287742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                final PackageInstallerSession session = mSessions.valueAt(i);
288941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                final String cid = session.stageCid;
289742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
290742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                if (unclaimed.remove(cid)) {
291742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                    // Claimed by active session, mount it
292742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                    PackageHelper.mountSdDir(cid, PackageManagerService.getEncryptKey(),
293742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                            Process.SYSTEM_UID);
294742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                }
295742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            }
296742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
297742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            // Clean up orphaned staging containers
298742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            for (String cid : unclaimed) {
299742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                Slog.w(TAG, "Deleting orphan container " + cid);
300742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                PackageHelper.destroySdDir(cid);
301742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            }
302742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        }
303742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    }
304742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
305742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    public static boolean isStageName(String name) {
306742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        final boolean isFile = name.startsWith("vmdl") && name.endsWith(".tmp");
307742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        final boolean isContainer = name.startsWith("smdl") && name.endsWith(".tmp");
308742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        final boolean isLegacyContainer = name.startsWith("smdl2tmp");
309742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        return isFile || isContainer || isLegacyContainer;
3107328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey    }
3117328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey
312ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey    @Deprecated
3132699f065558ba78066887210b0c7346105959860Todd Kennedy    public File allocateStageDirLegacy(String volumeUuid, boolean isEphemeral) throws IOException {
314ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        synchronized (mSessions) {
315ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey            try {
316ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey                final int sessionId = allocateSessionIdLocked();
317742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                mLegacySessions.put(sessionId, true);
3182699f065558ba78066887210b0c7346105959860Todd Kennedy                final File stageDir = buildStageDir(volumeUuid, sessionId, isEphemeral);
319b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey                prepareStageDir(stageDir);
32077d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey                return stageDir;
321ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey            } catch (IllegalStateException e) {
322ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey                throw new IOException(e);
3233a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
3243a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
3253a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
3263a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
327742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    @Deprecated
328742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    public String allocateExternalStageCidLegacy() {
329742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        synchronized (mSessions) {
330742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            final int sessionId = allocateSessionIdLocked();
331742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            mLegacySessions.put(sessionId, true);
332742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            return "smdl" + sessionId + ".tmp";
333742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        }
334742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    }
335742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
3363a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private void readSessionsLocked() {
3371cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        if (LOGD) Slog.v(TAG, "readSessionsLocked()");
3381cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
3393a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        mSessions.clear();
3401cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
3411cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        FileInputStream fis = null;
3421cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        try {
3431cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            fis = mSessionsFile.openRead();
3441cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            final XmlPullParser in = Xml.newPullParser();
3459e9e2e73c6ec7bece20268196dc89ad0c8bafad4Wojciech Staszkiewicz            in.setInput(fis, StandardCharsets.UTF_8.name());
3461cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
3471cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            int type;
3481cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            while ((type = in.next()) != END_DOCUMENT) {
3491cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                if (type == START_TAG) {
3501cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    final String tag = in.getName();
3511cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    if (TAG_SESSION.equals(tag)) {
3521cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                        final PackageInstallerSession session = readSessionLocked(in);
3531cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                        final long age = System.currentTimeMillis() - session.createdMillis;
3541cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
3551cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                        final boolean valid;
3561cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                        if (age >= MAX_AGE_MILLIS) {
3571cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                            Slog.w(TAG, "Abandoning old session first created at "
3581cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                                    + session.createdMillis);
3591cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                            valid = false;
3601cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                        } else {
3611cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                            valid = true;
3621cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                        }
3631cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
3641cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                        if (valid) {
3651cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                            mSessions.put(session.sessionId, session);
3661cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                        } else {
3671cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                            // Since this is early during boot we don't send
3681cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                            // any observer events about the session, but we
3691cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                            // keep details around for dumpsys.
3701cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                            mHistoricalSessions.put(session.sessionId, session);
3711cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                        }
37228c4e806ea6cb12b3b83af8447b6647471a15d38Todd Kennedy                        mAllocatedSessions.put(session.sessionId, true);
3731cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    }
3741cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                }
3751cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            }
3761cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        } catch (FileNotFoundException e) {
3771cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            // Missing sessions are okay, probably first boot
3787121e18595d4c559044e26bfe6035406a862f466Svet Ganov        } catch (IOException | XmlPullParserException e) {
3798d05172112436a81bed6e4a0810f8914509d8a4dDianne Hackborn            Slog.wtf(TAG, "Failed reading install sessions", e);
3801cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        } finally {
3811cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            IoUtils.closeQuietly(fis);
3821cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        }
3831cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    }
3841cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
3857121e18595d4c559044e26bfe6035406a862f466Svet Ganov    private PackageInstallerSession readSessionLocked(XmlPullParser in) throws IOException,
3867121e18595d4c559044e26bfe6035406a862f466Svet Ganov            XmlPullParserException {
3871cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        final int sessionId = readIntAttribute(in, ATTR_SESSION_ID);
3881cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        final int userId = readIntAttribute(in, ATTR_USER_ID);
3891cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        final String installerPackageName = readStringAttribute(in, ATTR_INSTALLER_PACKAGE_NAME);
390cd65448ccd13c4c2d0fe9e9623fec3a898ab9372Jeff Sharkey        final int installerUid = readIntAttribute(in, ATTR_INSTALLER_UID, mPm.getPackageUid(
391cd65448ccd13c4c2d0fe9e9623fec3a898ab9372Jeff Sharkey                installerPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, userId));
3921cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        final long createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS);
393742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        final String stageDirRaw = readStringAttribute(in, ATTR_SESSION_STAGE_DIR);
394742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        final File stageDir = (stageDirRaw != null) ? new File(stageDirRaw) : null;
395742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        final String stageCid = readStringAttribute(in, ATTR_SESSION_STAGE_CID);
39677d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        final boolean prepared = readBooleanAttribute(in, ATTR_PREPARED, true);
3971cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        final boolean sealed = readBooleanAttribute(in, ATTR_SEALED);
3981cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
399a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        final SessionParams params = new SessionParams(
400a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                SessionParams.MODE_INVALID);
4011cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        params.mode = readIntAttribute(in, ATTR_MODE);
4021cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        params.installFlags = readIntAttribute(in, ATTR_INSTALL_FLAGS);
4031cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        params.installLocation = readIntAttribute(in, ATTR_INSTALL_LOCATION);
4041cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        params.sizeBytes = readLongAttribute(in, ATTR_SIZE_BYTES);
4051cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        params.appPackageName = readStringAttribute(in, ATTR_APP_PACKAGE_NAME);
4061cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        params.appIcon = readBitmapAttribute(in, ATTR_APP_ICON);
4071cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        params.appLabel = readStringAttribute(in, ATTR_APP_LABEL);
4081cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        params.originatingUri = readUriAttribute(in, ATTR_ORIGINATING_URI);
409a1d12cfdb072acb14fa95d5e771e23396e6bd8e1Todd Kennedy        params.originatingUid =
410a1d12cfdb072acb14fa95d5e771e23396e6bd8e1Todd Kennedy                readIntAttribute(in, ATTR_ORIGINATING_UID, SessionParams.UID_UNKNOWN);
4111cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        params.referrerUri = readUriAttribute(in, ATTR_REFERRER_URI);
4121cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        params.abiOverride = readStringAttribute(in, ATTR_ABI_OVERRIDE);
413b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey        params.volumeUuid = readStringAttribute(in, ATTR_VOLUME_UUID);
4147121e18595d4c559044e26bfe6035406a862f466Svet Ganov        params.grantedRuntimePermissions = readGrantedRuntimePermissions(in);
4151cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
41602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey        final File appIconFile = buildAppIconFile(sessionId);
41702bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey        if (appIconFile.exists()) {
41802bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            params.appIcon = BitmapFactory.decodeFile(appIconFile.getAbsolutePath());
41902bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            params.appIconLastModified = appIconFile.lastModified();
42002bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey        }
42102bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey
422a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        return new PackageInstallerSession(mInternalCallback, mContext, mPm,
423e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey                mInstallThread.getLooper(), sessionId, userId, installerPackageName, installerUid,
424e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey                params, createdMillis, stageDir, stageCid, prepared, sealed);
4253a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
4263a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
4273a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private void writeSessionsLocked() {
4281cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        if (LOGD) Slog.v(TAG, "writeSessionsLocked()");
4291cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
4301cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        FileOutputStream fos = null;
4311cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        try {
4321cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            fos = mSessionsFile.startWrite();
4331cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
4341cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            XmlSerializer out = new FastXmlSerializer();
4359e9e2e73c6ec7bece20268196dc89ad0c8bafad4Wojciech Staszkiewicz            out.setOutput(fos, StandardCharsets.UTF_8.name());
4361cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            out.startDocument(null, true);
4371cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            out.startTag(null, TAG_SESSIONS);
4381cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            final int size = mSessions.size();
4391cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            for (int i = 0; i < size; i++) {
4401cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                final PackageInstallerSession session = mSessions.valueAt(i);
4411cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                writeSessionLocked(out, session);
4421cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            }
4431cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            out.endTag(null, TAG_SESSIONS);
4441cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            out.endDocument();
4451cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
4461cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            mSessionsFile.finishWrite(fos);
4471cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        } catch (IOException e) {
4481cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            if (fos != null) {
4491cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                mSessionsFile.failWrite(fos);
4501cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            }
4511cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        }
4521cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    }
4531cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
4541cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private void writeSessionLocked(XmlSerializer out, PackageInstallerSession session)
4551cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            throws IOException {
456a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        final SessionParams params = session.params;
4571cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
4581cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        out.startTag(null, TAG_SESSION);
4591cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
4601cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        writeIntAttribute(out, ATTR_SESSION_ID, session.sessionId);
4611cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        writeIntAttribute(out, ATTR_USER_ID, session.userId);
4621cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        writeStringAttribute(out, ATTR_INSTALLER_PACKAGE_NAME,
4631cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                session.installerPackageName);
464e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey        writeIntAttribute(out, ATTR_INSTALLER_UID, session.installerUid);
4651cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        writeLongAttribute(out, ATTR_CREATED_MILLIS, session.createdMillis);
466941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        if (session.stageDir != null) {
467742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            writeStringAttribute(out, ATTR_SESSION_STAGE_DIR,
468941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                    session.stageDir.getAbsolutePath());
469742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        }
470941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        if (session.stageCid != null) {
471941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            writeStringAttribute(out, ATTR_SESSION_STAGE_CID, session.stageCid);
472742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        }
47377d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        writeBooleanAttribute(out, ATTR_PREPARED, session.isPrepared());
474742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        writeBooleanAttribute(out, ATTR_SEALED, session.isSealed());
4751cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
4761cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        writeIntAttribute(out, ATTR_MODE, params.mode);
4771cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        writeIntAttribute(out, ATTR_INSTALL_FLAGS, params.installFlags);
4781cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        writeIntAttribute(out, ATTR_INSTALL_LOCATION, params.installLocation);
4791cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        writeLongAttribute(out, ATTR_SIZE_BYTES, params.sizeBytes);
4801cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        writeStringAttribute(out, ATTR_APP_PACKAGE_NAME, params.appPackageName);
4811cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        writeStringAttribute(out, ATTR_APP_LABEL, params.appLabel);
4821cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        writeUriAttribute(out, ATTR_ORIGINATING_URI, params.originatingUri);
483a1d12cfdb072acb14fa95d5e771e23396e6bd8e1Todd Kennedy        writeIntAttribute(out, ATTR_ORIGINATING_UID, params.originatingUid);
4841cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        writeUriAttribute(out, ATTR_REFERRER_URI, params.referrerUri);
4851cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        writeStringAttribute(out, ATTR_ABI_OVERRIDE, params.abiOverride);
486b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey        writeStringAttribute(out, ATTR_VOLUME_UUID, params.volumeUuid);
4871cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
48802bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey        // Persist app icon if changed since last written
48902bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey        final File appIconFile = buildAppIconFile(session.sessionId);
49002bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey        if (params.appIcon == null && appIconFile.exists()) {
49102bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            appIconFile.delete();
49202bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey        } else if (params.appIcon != null
49302bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                && appIconFile.lastModified() != params.appIconLastModified) {
49402bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            if (LOGD) Slog.w(TAG, "Writing changed icon " + appIconFile);
49502bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            FileOutputStream os = null;
49602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            try {
49702bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                os = new FileOutputStream(appIconFile);
49802bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                params.appIcon.compress(CompressFormat.PNG, 90, os);
49902bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            } catch (IOException e) {
50002bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                Slog.w(TAG, "Failed to write icon " + appIconFile + ": " + e.getMessage());
50102bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            } finally {
50202bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                IoUtils.closeQuietly(os);
50302bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            }
50402bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey
50502bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            params.appIconLastModified = appIconFile.lastModified();
50602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey        }
50702bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey
5087121e18595d4c559044e26bfe6035406a862f466Svet Ganov        writeGrantedRuntimePermissions(out, params.grantedRuntimePermissions);
5097121e18595d4c559044e26bfe6035406a862f466Svet Ganov
5101cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        out.endTag(null, TAG_SESSION);
5113a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
5123a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
5137121e18595d4c559044e26bfe6035406a862f466Svet Ganov    private static void writeGrantedRuntimePermissions(XmlSerializer out,
5147121e18595d4c559044e26bfe6035406a862f466Svet Ganov            String[] grantedRuntimePermissions) throws IOException {
5157121e18595d4c559044e26bfe6035406a862f466Svet Ganov        if (grantedRuntimePermissions != null) {
5167121e18595d4c559044e26bfe6035406a862f466Svet Ganov            for (String permission : grantedRuntimePermissions) {
5177121e18595d4c559044e26bfe6035406a862f466Svet Ganov                out.startTag(null, TAG_GRANTED_RUNTIME_PERMISSION);
5187121e18595d4c559044e26bfe6035406a862f466Svet Ganov                writeStringAttribute(out, ATTR_NAME, permission);
5197121e18595d4c559044e26bfe6035406a862f466Svet Ganov                out.endTag(null, TAG_GRANTED_RUNTIME_PERMISSION);
5207121e18595d4c559044e26bfe6035406a862f466Svet Ganov            }
5217121e18595d4c559044e26bfe6035406a862f466Svet Ganov        }
5227121e18595d4c559044e26bfe6035406a862f466Svet Ganov    }
5237121e18595d4c559044e26bfe6035406a862f466Svet Ganov
5247121e18595d4c559044e26bfe6035406a862f466Svet Ganov    private static String[] readGrantedRuntimePermissions(XmlPullParser in)
5257121e18595d4c559044e26bfe6035406a862f466Svet Ganov            throws IOException, XmlPullParserException {
5267121e18595d4c559044e26bfe6035406a862f466Svet Ganov        List<String> permissions = null;
5277121e18595d4c559044e26bfe6035406a862f466Svet Ganov
5287121e18595d4c559044e26bfe6035406a862f466Svet Ganov        final int outerDepth = in.getDepth();
5297121e18595d4c559044e26bfe6035406a862f466Svet Ganov        int type;
5307121e18595d4c559044e26bfe6035406a862f466Svet Ganov        while ((type = in.next()) != XmlPullParser.END_DOCUMENT
5317121e18595d4c559044e26bfe6035406a862f466Svet Ganov                && (type != XmlPullParser.END_TAG || in.getDepth() > outerDepth)) {
5327121e18595d4c559044e26bfe6035406a862f466Svet Ganov            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
5337121e18595d4c559044e26bfe6035406a862f466Svet Ganov                continue;
5347121e18595d4c559044e26bfe6035406a862f466Svet Ganov            }
5357121e18595d4c559044e26bfe6035406a862f466Svet Ganov            if (TAG_GRANTED_RUNTIME_PERMISSION.equals(in.getName())) {
5367121e18595d4c559044e26bfe6035406a862f466Svet Ganov                String permission = readStringAttribute(in, ATTR_NAME);
5377121e18595d4c559044e26bfe6035406a862f466Svet Ganov                if (permissions == null) {
5387121e18595d4c559044e26bfe6035406a862f466Svet Ganov                    permissions = new ArrayList<>();
5397121e18595d4c559044e26bfe6035406a862f466Svet Ganov                }
5407121e18595d4c559044e26bfe6035406a862f466Svet Ganov                permissions.add(permission);
5417121e18595d4c559044e26bfe6035406a862f466Svet Ganov            }
5427121e18595d4c559044e26bfe6035406a862f466Svet Ganov        }
5437121e18595d4c559044e26bfe6035406a862f466Svet Ganov
5447121e18595d4c559044e26bfe6035406a862f466Svet Ganov        if (permissions == null) {
5457121e18595d4c559044e26bfe6035406a862f466Svet Ganov            return null;
5467121e18595d4c559044e26bfe6035406a862f466Svet Ganov        }
5477121e18595d4c559044e26bfe6035406a862f466Svet Ganov
5487121e18595d4c559044e26bfe6035406a862f466Svet Ganov        String[] permissionsArray = new String[permissions.size()];
5497121e18595d4c559044e26bfe6035406a862f466Svet Ganov        permissions.toArray(permissionsArray);
5507121e18595d4c559044e26bfe6035406a862f466Svet Ganov        return permissionsArray;
5517121e18595d4c559044e26bfe6035406a862f466Svet Ganov    }
5527121e18595d4c559044e26bfe6035406a862f466Svet Ganov
55302bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey    private File buildAppIconFile(int sessionId) {
55402bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey        return new File(mSessionsDir, "app_icon." + sessionId + ".png");
55502bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey    }
55602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey
5573a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private void writeSessionsAsync() {
5583a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        IoThread.getHandler().post(new Runnable() {
5593a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            @Override
5603a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            public void run() {
5613a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                synchronized (mSessions) {
5623a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                    writeSessionsLocked();
5633a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                }
5643a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
5653a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        });
5663a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
5673a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
5683a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    @Override
569a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey    public int createSession(SessionParams params, String installerPackageName, int userId) {
570742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        try {
571742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            return createSessionInternal(params, installerPackageName, userId);
572742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        } catch (IOException e) {
573742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            throw ExceptionUtils.wrap(e);
574742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        }
575742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    }
576742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
577742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    private int createSessionInternal(SessionParams params, String installerPackageName, int userId)
578742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            throws IOException {
5793a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        final int callingUid = Binder.getCallingUid();
580e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey        mPm.enforceCrossUserPermission(callingUid, userId, true, true, "createSession");
5813a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
582e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey        if (mPm.isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
5833a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            throw new SecurityException("User restriction prevents installing");
5843a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
5853a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
5861cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {
587e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey            params.installFlags |= PackageManager.INSTALL_FROM_ADB;
5881cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
5893a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        } else {
590ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey            mAppOps.checkPackage(callingUid, installerPackageName);
591ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey
592e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey            params.installFlags &= ~PackageManager.INSTALL_FROM_ADB;
593e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey            params.installFlags &= ~PackageManager.INSTALL_ALL_USERS;
594e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey            params.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
5953a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
5963a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
597805b63e253c139625f5a86d72ef7b31d6ec9f8e9Svetoslav        // Only system components can circumvent runtime permissions when installing.
598805b63e253c139625f5a86d72ef7b31d6ec9f8e9Svetoslav        if ((params.installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0
599805b63e253c139625f5a86d72ef7b31d6ec9f8e9Svetoslav                && mContext.checkCallingOrSelfPermission(Manifest.permission
600805b63e253c139625f5a86d72ef7b31d6ec9f8e9Svetoslav                .INSTALL_GRANT_RUNTIME_PERMISSIONS) == PackageManager.PERMISSION_DENIED) {
601805b63e253c139625f5a86d72ef7b31d6ec9f8e9Svetoslav            throw new SecurityException("You need the "
602805b63e253c139625f5a86d72ef7b31d6ec9f8e9Svetoslav                    + "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS permission "
603805b63e253c139625f5a86d72ef7b31d6ec9f8e9Svetoslav                    + "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag");
604805b63e253c139625f5a86d72ef7b31d6ec9f8e9Svetoslav        }
605805b63e253c139625f5a86d72ef7b31d6ec9f8e9Svetoslav
6061cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        // Defensively resize giant app icons
6071cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        if (params.appIcon != null) {
6081cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            final ActivityManager am = (ActivityManager) mContext.getSystemService(
6091cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    Context.ACTIVITY_SERVICE);
6101cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            final int iconSize = am.getLauncherLargeIconSize();
6111cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            if ((params.appIcon.getWidth() > iconSize * 2)
6121cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    || (params.appIcon.getHeight() > iconSize * 2)) {
6131cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                params.appIcon = Bitmap.createScaledBitmap(params.appIcon, iconSize, iconSize,
6141cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                        true);
6151cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            }
6161cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        }
6171cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
618b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey        switch (params.mode) {
619b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey            case SessionParams.MODE_FULL_INSTALL:
620b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey            case SessionParams.MODE_INHERIT_EXISTING:
621b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey                break;
622b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey            default:
623b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey                throw new IllegalArgumentException("Invalid install mode: " + params.mode);
624b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey        }
625b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey
626b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey        // If caller requested explicit location, sanity check it, otherwise
627b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey        // resolve the best internal or adopted location.
628b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey        if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
629b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey            if (!PackageHelper.fitsOnInternal(mContext, params.sizeBytes)) {
630b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey                throw new IOException("No suitable internal storage available");
631b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey            }
632b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey
633b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey        } else if ((params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
634b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey            if (!PackageHelper.fitsOnExternal(mContext, params.sizeBytes)) {
635b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey                throw new IOException("No suitable external storage available");
636b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey            }
637b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey
638ab2340996a515ea0c437ad5bb1ea1fa88ab9edffJeff Sharkey        } else if ((params.installFlags & PackageManager.INSTALL_FORCE_VOLUME_UUID) != 0) {
639ab2340996a515ea0c437ad5bb1ea1fa88ab9edffJeff Sharkey            // For now, installs to adopted media are treated as internal from
640ab2340996a515ea0c437ad5bb1ea1fa88ab9edffJeff Sharkey            // an install flag point-of-view.
641ab2340996a515ea0c437ad5bb1ea1fa88ab9edffJeff Sharkey            params.setInstallFlagsInternal();
642ab2340996a515ea0c437ad5bb1ea1fa88ab9edffJeff Sharkey
643b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey        } else {
644b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey            // For now, installs to adopted media are treated as internal from
645b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey            // an install flag point-of-view.
646b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey            params.setInstallFlagsInternal();
647b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey
64877d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            // Resolve best location for install, based on combination of
64977d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            // requested install flags, delta size, and manifest settings.
650e812d9096915ad165de125520ed7371009587d1fRobin Lee            final long ident = Binder.clearCallingIdentity();
651e812d9096915ad165de125520ed7371009587d1fRobin Lee            try {
652b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey                params.volumeUuid = PackageHelper.resolveInstallVolume(mContext,
653b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey                        params.appPackageName, params.installLocation, params.sizeBytes);
654e812d9096915ad165de125520ed7371009587d1fRobin Lee            } finally {
655e812d9096915ad165de125520ed7371009587d1fRobin Lee                Binder.restoreCallingIdentity(ident);
656a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            }
657a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        }
658a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
659a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        final int sessionId;
660a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        final PackageInstallerSession session;
6613a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        synchronized (mSessions) {
6621cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            // Sanity check that installer isn't going crazy
663f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey            final int activeCount = getSessionCount(mSessions, callingUid);
6641cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            if (activeCount >= MAX_ACTIVE_SESSIONS) {
665f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey                throw new IllegalStateException(
666f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey                        "Too many active sessions for UID " + callingUid);
667f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey            }
668f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey            final int historicalCount = getSessionCount(mHistoricalSessions, callingUid);
669f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey            if (historicalCount >= MAX_HISTORICAL_SESSIONS) {
670f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey                throw new IllegalStateException(
671f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey                        "Too many historical sessions for UID " + callingUid);
6721cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            }
6731cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
674a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            sessionId = allocateSessionIdLocked();
67504918fe02715d330cbefa16d055d5766264273c3Todd Kennedy        }
676a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
67704918fe02715d330cbefa16d055d5766264273c3Todd Kennedy        final long createdMillis = System.currentTimeMillis();
67804918fe02715d330cbefa16d055d5766264273c3Todd Kennedy        // We're staging to exactly one location
67904918fe02715d330cbefa16d055d5766264273c3Todd Kennedy        File stageDir = null;
68004918fe02715d330cbefa16d055d5766264273c3Todd Kennedy        String stageCid = null;
68104918fe02715d330cbefa16d055d5766264273c3Todd Kennedy        if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
68204918fe02715d330cbefa16d055d5766264273c3Todd Kennedy            final boolean isEphemeral =
68304918fe02715d330cbefa16d055d5766264273c3Todd Kennedy                    (params.installFlags & PackageManager.INSTALL_EPHEMERAL) != 0;
68404918fe02715d330cbefa16d055d5766264273c3Todd Kennedy            stageDir = buildStageDir(params.volumeUuid, sessionId, isEphemeral);
68504918fe02715d330cbefa16d055d5766264273c3Todd Kennedy        } else {
68604918fe02715d330cbefa16d055d5766264273c3Todd Kennedy            stageCid = buildExternalStageCid(sessionId);
68704918fe02715d330cbefa16d055d5766264273c3Todd Kennedy        }
68804918fe02715d330cbefa16d055d5766264273c3Todd Kennedy
68904918fe02715d330cbefa16d055d5766264273c3Todd Kennedy        session = new PackageInstallerSession(mInternalCallback, mContext, mPm,
69004918fe02715d330cbefa16d055d5766264273c3Todd Kennedy                mInstallThread.getLooper(), sessionId, userId, installerPackageName, callingUid,
69104918fe02715d330cbefa16d055d5766264273c3Todd Kennedy                params, createdMillis, stageDir, stageCid, false, false);
6923a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
69304918fe02715d330cbefa16d055d5766264273c3Todd Kennedy        synchronized (mSessions) {
6943a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            mSessions.put(sessionId, session);
6953a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
696a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
6971cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        mCallbacks.notifySessionCreated(session.sessionId, session.userId);
698a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        writeSessionsAsync();
699a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        return sessionId;
7003a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
7013a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
702381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey    @Override
703ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey    public void updateSessionAppIcon(int sessionId, Bitmap appIcon) {
704ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey        synchronized (mSessions) {
705ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            final PackageInstallerSession session = mSessions.get(sessionId);
706ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            if (session == null || !isCallingUidOwner(session)) {
707ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey                throw new SecurityException("Caller has no access to session " + sessionId);
708ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            }
70902bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey
71002bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            // Defensively resize giant app icons
71102bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            if (appIcon != null) {
71202bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                final ActivityManager am = (ActivityManager) mContext.getSystemService(
71302bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                        Context.ACTIVITY_SERVICE);
71402bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                final int iconSize = am.getLauncherLargeIconSize();
71502bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                if ((appIcon.getWidth() > iconSize * 2)
71602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                        || (appIcon.getHeight() > iconSize * 2)) {
71702bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                    appIcon = Bitmap.createScaledBitmap(appIcon, iconSize, iconSize, true);
71802bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                }
71902bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            }
72002bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey
721ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            session.params.appIcon = appIcon;
72202bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            session.params.appIconLastModified = -1;
72302bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey
724ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            mInternalCallback.onSessionBadgingChanged(session);
725ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey        }
726ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey    }
727ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey
728ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey    @Override
729ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey    public void updateSessionAppLabel(int sessionId, String appLabel) {
730ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey        synchronized (mSessions) {
731ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            final PackageInstallerSession session = mSessions.get(sessionId);
732ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            if (session == null || !isCallingUidOwner(session)) {
733ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey                throw new SecurityException("Caller has no access to session " + sessionId);
734ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            }
735ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            session.params.appLabel = appLabel;
736ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            mInternalCallback.onSessionBadgingChanged(session);
737ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey        }
738ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey    }
739ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey
740ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey    @Override
741381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey    public void abandonSession(int sessionId) {
742381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey        synchronized (mSessions) {
743381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey            final PackageInstallerSession session = mSessions.get(sessionId);
744381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey            if (session == null || !isCallingUidOwner(session)) {
745381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey                throw new SecurityException("Caller has no access to session " + sessionId);
746381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey            }
747381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey            session.abandon();
748381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey        }
749381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey    }
750381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey
75177d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey    @Override
75277d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey    public IPackageInstallerSession openSession(int sessionId) {
75377d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        try {
75477d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            return openSessionInternal(sessionId);
75577d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        } catch (IOException e) {
75677d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            throw ExceptionUtils.wrap(e);
757742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        }
758742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    }
759742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
76077d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey    private IPackageInstallerSession openSessionInternal(int sessionId) throws IOException {
7613a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        synchronized (mSessions) {
7623a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            final PackageInstallerSession session = mSessions.get(sessionId);
763381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey            if (session == null || !isCallingUidOwner(session)) {
7643a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                throw new SecurityException("Caller has no access to session " + sessionId);
7653a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
766742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            session.open();
7673a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            return session;
7683a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
7693a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
7703a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
7713a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private int allocateSessionIdLocked() {
7721cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        int n = 0;
7731cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        int sessionId;
7741cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        do {
775f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey            sessionId = mRandom.nextInt(Integer.MAX_VALUE - 1) + 1;
77628c4e806ea6cb12b3b83af8447b6647471a15d38Todd Kennedy            if (!mAllocatedSessions.get(sessionId, false)) {
77728c4e806ea6cb12b3b83af8447b6647471a15d38Todd Kennedy                mAllocatedSessions.put(sessionId, true);
7781cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                return sessionId;
7791cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            }
7801cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        } while (n++ < 32);
7811cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
7821cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        throw new IllegalStateException("Failed to allocate session ID");
7833a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
7843a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
7852699f065558ba78066887210b0c7346105959860Todd Kennedy    private File buildStagingDir(String volumeUuid, boolean isEphemeral) {
7862699f065558ba78066887210b0c7346105959860Todd Kennedy        if (isEphemeral) {
7872699f065558ba78066887210b0c7346105959860Todd Kennedy            return Environment.getDataAppEphemeralDirectory(volumeUuid);
7882699f065558ba78066887210b0c7346105959860Todd Kennedy        }
7896dce4964b4d1a13d276d95730b8fb09d6a5a8d04Jeff Sharkey        return Environment.getDataAppDirectory(volumeUuid);
790b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey    }
791b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey
7922699f065558ba78066887210b0c7346105959860Todd Kennedy    private File buildStageDir(String volumeUuid, int sessionId, boolean isEphemeral) {
7932699f065558ba78066887210b0c7346105959860Todd Kennedy        final File stagingDir = buildStagingDir(volumeUuid, isEphemeral);
794b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey        return new File(stagingDir, "vmdl" + sessionId + ".tmp");
79577d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey    }
796ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey
797b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey    static void prepareStageDir(File stageDir) throws IOException {
79877d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        if (stageDir.exists()) {
79977d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            throw new IOException("Session dir already exists: " + stageDir);
800ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        }
801ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey
802ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        try {
80377d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            Os.mkdir(stageDir.getAbsolutePath(), 0755);
80477d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            Os.chmod(stageDir.getAbsolutePath(), 0755);
805ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        } catch (ErrnoException e) {
806ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey            // This purposefully throws if directory already exists
80777d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            throw new IOException("Failed to prepare session dir: " + stageDir, e);
808ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        }
809ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey
81077d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        if (!SELinux.restorecon(stageDir)) {
81177d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            throw new IOException("Failed to restorecon session dir: " + stageDir);
812ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        }
813ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey    }
814ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey
81577d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey    private String buildExternalStageCid(int sessionId) {
81677d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        return "smdl" + sessionId + ".tmp";
81777d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey    }
818742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
81977d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey    static void prepareExternalStageCid(String stageCid, long sizeBytes) throws IOException {
82077d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        if (PackageHelper.createSdDir(sizeBytes, stageCid, PackageManagerService.getEncryptKey(),
821742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                Process.SYSTEM_UID, true) == null) {
82277d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            throw new IOException("Failed to create session cid: " + stageCid);
823742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        }
824742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    }
825742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
8263a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    @Override
827a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey    public SessionInfo getSessionInfo(int sessionId) {
82816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey        synchronized (mSessions) {
82916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey            final PackageInstallerSession session = mSessions.get(sessionId);
83016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey            return session != null ? session.generateInfo() : null;
83116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey        }
83216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey    }
83316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey
83416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey    @Override
83597d47ed036ff7bd3d7d2ddc1c6df1104ec237559Jeff Sharkey    public ParceledListSlice<SessionInfo> getAllSessions(int userId) {
8368cd28b57ed732656d002d97879e15c5695b54fffAmith Yamasani        mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, "getAllSessions");
8373a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
838a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        final List<SessionInfo> result = new ArrayList<>();
8393a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        synchronized (mSessions) {
8403a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            for (int i = 0; i < mSessions.size(); i++) {
8413a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                final PackageInstallerSession session = mSessions.valueAt(i);
842bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey                if (session.userId == userId) {
843bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey                    result.add(session.generateInfo());
8443a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                }
8453a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
8463a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
84797d47ed036ff7bd3d7d2ddc1c6df1104ec237559Jeff Sharkey        return new ParceledListSlice<>(result);
8483a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
8493a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
8503a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    @Override
85197d47ed036ff7bd3d7d2ddc1c6df1104ec237559Jeff Sharkey    public ParceledListSlice<SessionInfo> getMySessions(String installerPackageName, int userId) {
8528cd28b57ed732656d002d97879e15c5695b54fffAmith Yamasani        mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, "getMySessions");
85316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey        mAppOps.checkPackage(Binder.getCallingUid(), installerPackageName);
85416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey
855a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        final List<SessionInfo> result = new ArrayList<>();
85616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey        synchronized (mSessions) {
85716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey            for (int i = 0; i < mSessions.size(); i++) {
85816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey                final PackageInstallerSession session = mSessions.valueAt(i);
85916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey                if (Objects.equals(session.installerPackageName, installerPackageName)
86016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey                        && session.userId == userId) {
86116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey                    result.add(session.generateInfo());
86216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey                }
86316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey            }
86416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey        }
86597d47ed036ff7bd3d7d2ddc1c6df1104ec237559Jeff Sharkey        return new ParceledListSlice<>(result);
86616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey    }
86716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey
86816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey    @Override
86939fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz    public void uninstall(String packageName, String callerPackageName, int flags,
87039fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                IntentSender statusReceiver, int userId) {
87139fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        final int callingUid = Binder.getCallingUid();
87239fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        mPm.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
87339fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        if ((callingUid != Process.SHELL_UID) && (callingUid != Process.ROOT_UID)) {
87439fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz            mAppOps.checkPackage(callingUid, callerPackageName);
87539fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        }
87639fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz
877c8a5a555f1482d0f45b538eb898d6ee7e26552a6Makoto Onuki        // Check whether the caller is device owner, in which case we do it silently.
87839fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(
87939fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                Context.DEVICE_POLICY_SERVICE);
880c8a5a555f1482d0f45b538eb898d6ee7e26552a6Makoto Onuki        boolean isDeviceOwner = (dpm != null) && dpm.isDeviceOwnerAppOnCallingUser(
881c8a5a555f1482d0f45b538eb898d6ee7e26552a6Makoto Onuki                callerPackageName);
88216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey
883a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext,
88439fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                statusReceiver, packageName, isDeviceOwner, userId);
88572de4ddb461e132f381aad7386f815581fd2aad5Sudheer Shanka        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES)
88672de4ddb461e132f381aad7386f815581fd2aad5Sudheer Shanka                    == PackageManager.PERMISSION_GRANTED) {
887f06009542390472872da986486d385001e91a2a7Jeff Sharkey            // Sweet, call straight through!
888a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            mPm.deletePackage(packageName, adapter.getBinder(), userId, flags);
88939fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        } else if (isDeviceOwner) {
89039fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz            // Allow the DeviceOwner to silently delete packages
89139fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz            // Need to clear the calling identity to get DELETE_PACKAGES permission
89239fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz            long ident = Binder.clearCallingIdentity();
89339fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz            try {
89439fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                mPm.deletePackage(packageName, adapter.getBinder(), userId, flags);
89539fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz            } finally {
89639fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                Binder.restoreCallingIdentity(ident);
89739fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz            }
898f06009542390472872da986486d385001e91a2a7Jeff Sharkey        } else {
899f06009542390472872da986486d385001e91a2a7Jeff Sharkey            // Take a short detour to confirm with user
900f06009542390472872da986486d385001e91a2a7Jeff Sharkey            final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
901f06009542390472872da986486d385001e91a2a7Jeff Sharkey            intent.setData(Uri.fromParts("package", packageName, null));
902a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            intent.putExtra(PackageInstaller.EXTRA_CALLBACK, adapter.getBinder().asBinder());
903a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            adapter.onUserActionRequired(intent);
904f06009542390472872da986486d385001e91a2a7Jeff Sharkey        }
9053a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
9063a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
9073a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    @Override
9087328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey    public void setPermissionsResult(int sessionId, boolean accepted) {
9097328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, TAG);
9107328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey
9117328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey        synchronized (mSessions) {
9123baa87653ead8982fcb114274a3778161763a894Svet Ganov            PackageInstallerSession session = mSessions.get(sessionId);
9133baa87653ead8982fcb114274a3778161763a894Svet Ganov            if (session != null) {
9143baa87653ead8982fcb114274a3778161763a894Svet Ganov                session.setPermissionsResult(accepted);
9153baa87653ead8982fcb114274a3778161763a894Svet Ganov            }
9167328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey        }
9177328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey    }
9187328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey
9197328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey    @Override
92016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey    public void registerCallback(IPackageInstallerCallback callback, int userId) {
9218cd28b57ed732656d002d97879e15c5695b54fffAmith Yamasani        mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, "registerCallback");
9221cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        mCallbacks.register(callback, userId);
923bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey    }
924bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey
925bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey    @Override
92616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey    public void unregisterCallback(IPackageInstallerCallback callback) {
92716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey        mCallbacks.unregister(callback);
928a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey    }
929a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
930f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey    private static int getSessionCount(SparseArray<PackageInstallerSession> sessions,
931f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey            int installerUid) {
9321cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        int count = 0;
933f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey        final int size = sessions.size();
9341cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        for (int i = 0; i < size; i++) {
935f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey            final PackageInstallerSession session = sessions.valueAt(i);
9361cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            if (session.installerUid == installerUid) {
9371cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                count++;
9381cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            }
9391cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        }
9401cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        return count;
9411cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    }
9421cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
9431cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private boolean isCallingUidOwner(PackageInstallerSession session) {
9441cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        final int callingUid = Binder.getCallingUid();
9451cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        if (callingUid == Process.ROOT_UID) {
9461cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            return true;
9471cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        } else {
9481cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            return (session != null) && (callingUid == session.installerUid);
949a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        }
950a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey    }
951a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
952a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey    static class PackageDeleteObserverAdapter extends PackageDeleteObserver {
953a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        private final Context mContext;
954a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        private final IntentSender mTarget;
955bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey        private final String mPackageName;
95639fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        private final Notification mNotification;
957a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey
958bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey        public PackageDeleteObserverAdapter(Context context, IntentSender target,
95939fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                String packageName, boolean showNotification, int userId) {
960a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            mContext = context;
961a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            mTarget = target;
962bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            mPackageName = packageName;
96339fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz            if (showNotification) {
96439fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                mNotification = buildSuccessNotification(mContext,
96539fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                        mContext.getResources().getString(R.string.package_deleted_device_owner),
96639fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                        packageName,
96739fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                        userId);
96839fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz            } else {
96939fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                mNotification = null;
97039fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz            }
971a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        }
972a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey
973a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        @Override
974a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        public void onUserActionRequired(Intent intent) {
975a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            final Intent fillIn = new Intent();
976bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName);
977a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
978742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                    PackageInstaller.STATUS_PENDING_USER_ACTION);
979a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            fillIn.putExtra(Intent.EXTRA_INTENT, intent);
980a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            try {
981a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                mTarget.sendIntent(mContext, 0, fillIn, null, null);
982a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            } catch (SendIntentException ignored) {
983a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            }
984a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        }
985a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey
986a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        @Override
987a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        public void onPackageDeleted(String basePackageName, int returnCode, String msg) {
98839fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz            if (PackageManager.DELETE_SUCCEEDED == returnCode && mNotification != null) {
98939fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                NotificationManager notificationManager = (NotificationManager)
99039fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                        mContext.getSystemService(Context.NOTIFICATION_SERVICE);
99139fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                notificationManager.notify(basePackageName, 0, mNotification);
99239fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz            }
993a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            final Intent fillIn = new Intent();
994bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName);
995a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
996a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                    PackageManager.deleteStatusToPublicStatus(returnCode));
997a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
998a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                    PackageManager.deleteStatusToString(returnCode, msg));
999a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode);
1000a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            try {
1001a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                mTarget.sendIntent(mContext, 0, fillIn, null, null);
1002a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            } catch (SendIntentException ignored) {
1003a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            }
1004a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        }
1005a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey    }
1006a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey
1007a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey    static class PackageInstallObserverAdapter extends PackageInstallObserver {
1008a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        private final Context mContext;
1009a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        private final IntentSender mTarget;
1010bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey        private final int mSessionId;
101139fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        private final boolean mShowNotification;
101239fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        private final int mUserId;
1013a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey
101439fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        public PackageInstallObserverAdapter(Context context, IntentSender target, int sessionId,
101539fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                boolean showNotification, int userId) {
1016a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            mContext = context;
1017a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            mTarget = target;
1018bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            mSessionId = sessionId;
101939fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz            mShowNotification = showNotification;
102039fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz            mUserId = userId;
1021a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        }
1022a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey
1023a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        @Override
1024a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        public void onUserActionRequired(Intent intent) {
1025a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            final Intent fillIn = new Intent();
1026bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId);
1027a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
1028742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                    PackageInstaller.STATUS_PENDING_USER_ACTION);
1029a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            fillIn.putExtra(Intent.EXTRA_INTENT, intent);
1030a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            try {
1031a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                mTarget.sendIntent(mContext, 0, fillIn, null, null);
1032a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            } catch (SendIntentException ignored) {
1033a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            }
1034a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        }
1035a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey
1036a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        @Override
1037a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        public void onPackageInstalled(String basePackageName, int returnCode, String msg,
1038a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                Bundle extras) {
103939fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz            if (PackageManager.INSTALL_SUCCEEDED == returnCode && mShowNotification) {
10402e3e943ccd419dd10d3e4df5ae7640e8b020cc76Benjamin Franz                boolean update = (extras != null) && extras.getBoolean(Intent.EXTRA_REPLACING);
104139fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                Notification notification = buildSuccessNotification(mContext,
10422e3e943ccd419dd10d3e4df5ae7640e8b020cc76Benjamin Franz                        mContext.getResources()
10432e3e943ccd419dd10d3e4df5ae7640e8b020cc76Benjamin Franz                                .getString(update ? R.string.package_updated_device_owner :
10442e3e943ccd419dd10d3e4df5ae7640e8b020cc76Benjamin Franz                                        R.string.package_installed_device_owner),
104539fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                        basePackageName,
104639fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                        mUserId);
104739fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                if (notification != null) {
104839fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                    NotificationManager notificationManager = (NotificationManager)
104939fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                            mContext.getSystemService(Context.NOTIFICATION_SERVICE);
105039fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                    notificationManager.notify(basePackageName, 0, notification);
105139fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                }
105239fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz            }
1053a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            final Intent fillIn = new Intent();
10542e3e943ccd419dd10d3e4df5ae7640e8b020cc76Benjamin Franz            fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, basePackageName);
1055bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId);
1056a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
1057a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                    PackageManager.installStatusToPublicStatus(returnCode));
1058a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
1059a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                    PackageManager.installStatusToString(returnCode, msg));
1060a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode);
1061a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            if (extras != null) {
1062a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                final String existing = extras.getString(
1063a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                        PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE);
1064a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                if (!TextUtils.isEmpty(existing)) {
1065941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                    fillIn.putExtra(PackageInstaller.EXTRA_OTHER_PACKAGE_NAME, existing);
1066a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                }
1067a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            }
1068a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            try {
1069a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                mTarget.sendIntent(mContext, 0, fillIn, null, null);
1070a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            } catch (SendIntentException ignored) {
1071a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            }
1072a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        }
1073a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey    }
1074a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey
107539fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz    /**
107639fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz     * Build a notification for package installation / deletion by device owners that is shown if
107739fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz     * the operation succeeds.
107839fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz     */
107939fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz    private static Notification buildSuccessNotification(Context context, String contentText,
108039fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz            String basePackageName, int userId) {
108139fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        PackageInfo packageInfo = null;
108239fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        try {
108339fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz            packageInfo = AppGlobals.getPackageManager().getPackageInfo(
108439fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                    basePackageName, 0, userId);
108539fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        } catch (RemoteException ignored) {
108639fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        }
108739fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        if (packageInfo == null || packageInfo.applicationInfo == null) {
108839fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz            Slog.w(TAG, "Notification not built for package: " + basePackageName);
108939fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz            return null;
109039fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        }
109139fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        PackageManager pm = context.getPackageManager();
109239fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        Bitmap packageIcon = ImageUtils.buildScaledBitmap(
109339fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                packageInfo.applicationInfo.loadIcon(pm),
109439fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                context.getResources().getDimensionPixelSize(
109539fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                        android.R.dimen.notification_large_icon_width),
109639fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                context.getResources().getDimensionPixelSize(
109739fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                        android.R.dimen.notification_large_icon_height));
109839fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        CharSequence packageLabel = packageInfo.applicationInfo.loadLabel(pm);
109939fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz        return new Notification.Builder(context)
110039fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                .setSmallIcon(R.drawable.ic_check_circle_24px)
110139fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                .setColor(context.getResources().getColor(
110239fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                        R.color.system_notification_accent_color))
110339fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                .setContentTitle(packageLabel)
110439fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                .setContentText(contentText)
11052e3e943ccd419dd10d3e4df5ae7640e8b020cc76Benjamin Franz                .setStyle(new Notification.BigTextStyle().bigText(contentText))
110639fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                .setLargeIcon(packageIcon)
110739fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz                .build();
110839fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz    }
110939fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz
111054d42be6eb149b3e43115e810e4a1b92e9865d05Jeff Sharkey    public static <E> ArraySet<E> newArraySet(E... elements) {
111154d42be6eb149b3e43115e810e4a1b92e9865d05Jeff Sharkey        final ArraySet<E> set = new ArraySet<E>();
111254d42be6eb149b3e43115e810e4a1b92e9865d05Jeff Sharkey        if (elements != null) {
111354d42be6eb149b3e43115e810e4a1b92e9865d05Jeff Sharkey            set.ensureCapacity(elements.length);
111454d42be6eb149b3e43115e810e4a1b92e9865d05Jeff Sharkey            Collections.addAll(set, elements);
111554d42be6eb149b3e43115e810e4a1b92e9865d05Jeff Sharkey        }
111654d42be6eb149b3e43115e810e4a1b92e9865d05Jeff Sharkey        return set;
111754d42be6eb149b3e43115e810e4a1b92e9865d05Jeff Sharkey    }
111854d42be6eb149b3e43115e810e4a1b92e9865d05Jeff Sharkey
11191cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static class Callbacks extends Handler {
11201cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        private static final int MSG_SESSION_CREATED = 1;
1121ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey        private static final int MSG_SESSION_BADGING_CHANGED = 2;
1122bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey        private static final int MSG_SESSION_ACTIVE_CHANGED = 3;
1123ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey        private static final int MSG_SESSION_PROGRESS_CHANGED = 4;
1124bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey        private static final int MSG_SESSION_FINISHED = 5;
11251cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
11261cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        private final RemoteCallbackList<IPackageInstallerCallback>
11271cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                mCallbacks = new RemoteCallbackList<>();
11281cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
11291cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        public Callbacks(Looper looper) {
11301cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            super(looper);
1131a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        }
1132a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
11331cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        public void register(IPackageInstallerCallback callback, int userId) {
11341cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            mCallbacks.register(callback, new UserHandle(userId));
11351cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        }
11361cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
11371cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        public void unregister(IPackageInstallerCallback callback) {
11381cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            mCallbacks.unregister(callback);
11391cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        }
11401cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
11411cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        @Override
11421cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        public void handleMessage(Message msg) {
11431cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            final int userId = msg.arg2;
11441cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            final int n = mCallbacks.beginBroadcast();
11451cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            for (int i = 0; i < n; i++) {
11461cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                final IPackageInstallerCallback callback = mCallbacks.getBroadcastItem(i);
11471cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                final UserHandle user = (UserHandle) mCallbacks.getBroadcastCookie(i);
11481cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                // TODO: dispatch notifications for slave profiles
11491cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                if (userId == user.getIdentifier()) {
11501cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    try {
11511cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                        invokeCallback(callback, msg);
11521cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    } catch (RemoteException ignored) {
11531cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    }
1154a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey                }
1155a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            }
11561cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            mCallbacks.finishBroadcast();
1157a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        }
1158a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
11591cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        private void invokeCallback(IPackageInstallerCallback callback, Message msg)
11601cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                throws RemoteException {
11611cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            final int sessionId = msg.arg1;
11621cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            switch (msg.what) {
11631cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                case MSG_SESSION_CREATED:
11641cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    callback.onSessionCreated(sessionId);
11651cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    break;
1166ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey                case MSG_SESSION_BADGING_CHANGED:
1167ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey                    callback.onSessionBadgingChanged(sessionId);
1168ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey                    break;
1169bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey                case MSG_SESSION_ACTIVE_CHANGED:
1170bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey                    callback.onSessionActiveChanged(sessionId, (boolean) msg.obj);
11711cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    break;
11721cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                case MSG_SESSION_PROGRESS_CHANGED:
11731cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    callback.onSessionProgressChanged(sessionId, (float) msg.obj);
11741cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    break;
11751cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                case MSG_SESSION_FINISHED:
11761cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    callback.onSessionFinished(sessionId, (boolean) msg.obj);
11771cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    break;
1178a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            }
1179a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        }
11801cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
11811cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        private void notifySessionCreated(int sessionId, int userId) {
11821cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            obtainMessage(MSG_SESSION_CREATED, sessionId, userId).sendToTarget();
11831cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        }
11841cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
1185ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey        private void notifySessionBadgingChanged(int sessionId, int userId) {
1186ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            obtainMessage(MSG_SESSION_BADGING_CHANGED, sessionId, userId).sendToTarget();
1187ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey        }
1188ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey
1189bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey        private void notifySessionActiveChanged(int sessionId, int userId, boolean active) {
1190bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey            obtainMessage(MSG_SESSION_ACTIVE_CHANGED, sessionId, userId, active).sendToTarget();
11911cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        }
11921cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
11931cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        private void notifySessionProgressChanged(int sessionId, int userId, float progress) {
11941cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            obtainMessage(MSG_SESSION_PROGRESS_CHANGED, sessionId, userId, progress).sendToTarget();
11951cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        }
11961cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
11971cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        public void notifySessionFinished(int sessionId, int userId, boolean success) {
11981cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            obtainMessage(MSG_SESSION_FINISHED, sessionId, userId, success).sendToTarget();
11991cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        }
1200a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey    }
1201a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
1202a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey    void dump(IndentingPrintWriter pw) {
1203a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        synchronized (mSessions) {
12049a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey            pw.println("Active install sessions:");
12059a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey            pw.increaseIndent();
12069a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey            int N = mSessions.size();
1207a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            for (int i = 0; i < N; i++) {
1208a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey                final PackageInstallerSession session = mSessions.valueAt(i);
1209a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey                session.dump(pw);
1210a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey                pw.println();
1211a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            }
12129a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey            pw.println();
12139a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey            pw.decreaseIndent();
12149a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey
12159a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey            pw.println("Historical install sessions:");
12169a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey            pw.increaseIndent();
12179a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey            N = mHistoricalSessions.size();
12189a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey            for (int i = 0; i < N; i++) {
12199a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey                final PackageInstallerSession session = mHistoricalSessions.valueAt(i);
12209a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey                session.dump(pw);
12219a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey                pw.println();
12229a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey            }
12239a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey            pw.println();
12249a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey            pw.decreaseIndent();
1225742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
1226742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            pw.println("Legacy install sessions:");
1227742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            pw.increaseIndent();
1228742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            pw.println(mLegacySessions.toString());
1229742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            pw.decreaseIndent();
1230a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        }
1231bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey    }
1232bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey
12331cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    class InternalCallback {
1234ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey        public void onSessionBadgingChanged(PackageInstallerSession session) {
1235ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            mCallbacks.notifySessionBadgingChanged(session.sessionId, session.userId);
1236ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            writeSessionsAsync();
12371cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        }
12381cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
1239bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey        public void onSessionActiveChanged(PackageInstallerSession session, boolean active) {
1240bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey            mCallbacks.notifySessionActiveChanged(session.sessionId, session.userId, active);
1241742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        }
1242742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
1243ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey        public void onSessionProgressChanged(PackageInstallerSession session, float progress) {
1244ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            mCallbacks.notifySessionProgressChanged(session.sessionId, session.userId, progress);
1245ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey        }
1246ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey
1247cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey        public void onSessionFinished(final PackageInstallerSession session, boolean success) {
12481cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            mCallbacks.notifySessionFinished(session.sessionId, session.userId, success);
1249cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey
1250cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey            mInstallHandler.post(new Runnable() {
1251cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey                @Override
1252cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey                public void run() {
1253cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey                    synchronized (mSessions) {
1254cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey                        mSessions.remove(session.sessionId);
1255cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey                        mHistoricalSessions.put(session.sessionId, session);
125602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey
125702bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                        final File appIconFile = buildAppIconFile(session.sessionId);
125802bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                        if (appIconFile.exists()) {
125902bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                            appIconFile.delete();
126002bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                        }
126102bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey
1262cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey                        writeSessionsLocked();
1263cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey                    }
1264cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey                }
1265cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey            });
12663a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
1267bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey
126877d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        public void onSessionPrepared(PackageInstallerSession session) {
126977d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            // We prepared the destination to write into; we want to persist
127077d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            // this, but it's not critical enough to block for.
127177d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            writeSessionsAsync();
127277d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        }
127377d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey
1274cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey        public void onSessionSealedBlocking(PackageInstallerSession session) {
1275bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            // It's very important that we block until we've recorded the
1276bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            // session as being sealed, since we never want to allow mutation
1277bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            // after sealing.
1278cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey            synchronized (mSessions) {
1279cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey                writeSessionsLocked();
1280cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey            }
1281bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey        }
12823a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
12833a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey}
1284