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