PackageInstallerService.java revision 39fb7fd730dc2113ced7e663d7a35e48a4c6b1ae
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 331cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.app.ActivityManager; 3439fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franzimport android.app.AppGlobals; 353a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.app.AppOpsManager; 3639fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franzimport android.app.Notification; 3739fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franzimport android.app.NotificationManager; 38a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.app.PackageDeleteObserver; 39a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.app.PackageInstallObserver; 4039fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franzimport android.app.admin.DevicePolicyManager; 413a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.content.Context; 42f06009542390472872da986486d385001e91a2a7Jeff Sharkeyimport android.content.Intent; 43a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.content.IntentSender; 44a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.content.IntentSender.SendIntentException; 4539fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franzimport android.content.pm.ApplicationInfo; 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; 73b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkeyimport android.os.storage.VolumeInfo; 74ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport android.system.ErrnoException; 75ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport android.system.Os; 76a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.text.TextUtils; 771cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.text.format.DateUtils; 783a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.util.ArraySet; 791cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.util.AtomicFile; 80a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkeyimport android.util.ExceptionUtils; 813a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.util.Slog; 823a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.util.SparseArray; 83742e790294b3441b79f715fe447069b63c6065dbJeff Sharkeyimport android.util.SparseBooleanArray; 841cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.util.Xml; 853a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 86b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkeyimport libcore.io.IoUtils; 87b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey 8839fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franzimport com.android.internal.R; 893a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport com.android.internal.annotations.GuardedBy; 90742e790294b3441b79f715fe447069b63c6065dbJeff Sharkeyimport com.android.internal.content.PackageHelper; 911cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport com.android.internal.util.FastXmlSerializer; 9239fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franzimport com.android.internal.util.ImageUtils; 93a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkeyimport com.android.internal.util.IndentingPrintWriter; 943a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport com.android.server.IoThread; 953a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport com.google.android.collect.Sets; 963a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 971cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport org.xmlpull.v1.XmlPullParser; 981cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport org.xmlpull.v1.XmlPullParserException; 991cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport org.xmlpull.v1.XmlSerializer; 1001cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 1013a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport java.io.File; 1021cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport java.io.FileInputStream; 1031cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport java.io.FileNotFoundException; 1041cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport java.io.FileOutputStream; 105ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport java.io.FilenameFilter; 106ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport java.io.IOException; 1071cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport java.security.SecureRandom; 108bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkeyimport java.util.ArrayList; 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"; 1241cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_SESSION_ID = "sessionId"; 1251cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_USER_ID = "userId"; 1261cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_INSTALLER_PACKAGE_NAME = "installerPackageName"; 127e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey private static final String ATTR_INSTALLER_UID = "installerUid"; 1281cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_CREATED_MILLIS = "createdMillis"; 1291cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_SESSION_STAGE_DIR = "sessionStageDir"; 130742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey private static final String ATTR_SESSION_STAGE_CID = "sessionStageCid"; 13177d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey private static final String ATTR_PREPARED = "prepared"; 1321cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_SEALED = "sealed"; 1331cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_MODE = "mode"; 1341cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_INSTALL_FLAGS = "installFlags"; 1351cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_INSTALL_LOCATION = "installLocation"; 1361cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_SIZE_BYTES = "sizeBytes"; 1371cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_APP_PACKAGE_NAME = "appPackageName"; 13802bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey @Deprecated 1391cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_APP_ICON = "appIcon"; 1401cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_APP_LABEL = "appLabel"; 1411cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_ORIGINATING_URI = "originatingUri"; 1421cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_REFERRER_URI = "referrerUri"; 1431cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_ABI_OVERRIDE = "abiOverride"; 144b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey private static final String ATTR_VOLUME_UUID = "volumeUuid"; 1451cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 146f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey /** Automatically destroy sessions older than this */ 1471cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final long MAX_AGE_MILLIS = 3 * DateUtils.DAY_IN_MILLIS; 148f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey /** Upper bound on number of active sessions for a UID */ 1491cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final long MAX_ACTIVE_SESSIONS = 1024; 150f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey /** Upper bound on number of historical sessions for a UID */ 151f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey private static final long MAX_HISTORICAL_SESSIONS = 1048576; 1521cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 1533a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private final Context mContext; 1543a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private final PackageManagerService mPm; 1553a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 156b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey private AppOpsManager mAppOps; 157b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey private StorageManager mStorage; 158b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey 159ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey private final HandlerThread mInstallThread; 160cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey private final Handler mInstallHandler; 1613a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1621cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private final Callbacks mCallbacks; 1631cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 1641cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey /** 16502bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey * File storing persisted {@link #mSessions} metadata. 1661cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey */ 1671cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private final AtomicFile mSessionsFile; 1681cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 16902bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey /** 17002bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey * Directory storing persisted {@link #mSessions} metadata which is too 17102bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey * heavy to store directly in {@link #mSessionsFile}. 17202bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey */ 17302bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey private final File mSessionsDir; 17402bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey 1751cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private final InternalCallback mInternalCallback = new InternalCallback(); 1761cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 1771cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey /** 1781cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * Used for generating session IDs. Since this is created at boot time, 1791cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * normal random might be predictable. 1801cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey */ 1811cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private final Random mRandom = new SecureRandom(); 1823a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1833a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey @GuardedBy("mSessions") 1843a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>(); 1853a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1869a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey /** Historical sessions kept around for debugging purposes */ 1879a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey @GuardedBy("mSessions") 1889a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey private final SparseArray<PackageInstallerSession> mHistoricalSessions = new SparseArray<>(); 1899a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey 190742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey /** Sessions allocated to legacy users */ 191742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey @GuardedBy("mSessions") 192742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey private final SparseBooleanArray mLegacySessions = new SparseBooleanArray(); 193742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 194ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey private static final FilenameFilter sStageFilter = new FilenameFilter() { 195ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey @Override 196ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey public boolean accept(File dir, String name) { 197742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey return isStageName(name); 198ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 199ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey }; 200ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 201b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey public PackageInstallerService(Context context, PackageManagerService pm) { 2023a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey mContext = context; 2033a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey mPm = pm; 204ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 205ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey mInstallThread = new HandlerThread(TAG); 206ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey mInstallThread.start(); 2073a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 208cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey mInstallHandler = new Handler(mInstallThread.getLooper()); 209cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey 2101cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mCallbacks = new Callbacks(mInstallThread.getLooper()); 2111cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 2121cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mSessionsFile = new AtomicFile( 2131cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey new File(Environment.getSystemSecureDirectory(), "install_sessions.xml")); 21402bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey mSessionsDir = new File(Environment.getSystemSecureDirectory(), "install_sessions"); 21502bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey mSessionsDir.mkdirs(); 2161cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 2173a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey synchronized (mSessions) { 2183a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey readSessionsLocked(); 2193a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 220b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey final File internalStagingDir = buildInternalStagingDir(); 22102bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey final ArraySet<File> unclaimedStages = Sets.newArraySet( 222b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey internalStagingDir.listFiles(sStageFilter)); 22302bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey final ArraySet<File> unclaimedIcons = Sets.newArraySet( 22402bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey mSessionsDir.listFiles()); 225742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 22602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey // Ignore stages and icons claimed by active sessions 2273a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey for (int i = 0; i < mSessions.size(); i++) { 228ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey final PackageInstallerSession session = mSessions.valueAt(i); 22902bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey unclaimedStages.remove(session.stageDir); 23002bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey unclaimedIcons.remove(buildAppIconFile(session.sessionId)); 231ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 232742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 233742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey // Clean up orphaned staging directories 23402bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey for (File stage : unclaimedStages) { 235ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey Slog.w(TAG, "Deleting orphan stage " + stage); 236ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey if (stage.isDirectory()) { 237b94c1657eb0140f7b91f5372a9f76de5a3d87e36Fyodor Kupolov mPm.mInstaller.rmPackageDir(stage.getAbsolutePath()); 238b94c1657eb0140f7b91f5372a9f76de5a3d87e36Fyodor Kupolov } else { 239b94c1657eb0140f7b91f5372a9f76de5a3d87e36Fyodor Kupolov stage.delete(); 240ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 2413a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 24202bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey 24302bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey // Clean up orphaned icons 24402bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey for (File icon : unclaimedIcons) { 24502bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey Slog.w(TAG, "Deleting orphan icon " + icon); 24602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey icon.delete(); 24702bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey } 248ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 249ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 250ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 251b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey public void systemReady() { 252b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey mAppOps = mContext.getSystemService(AppOpsManager.class); 253b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey mStorage = mContext.getSystemService(StorageManager.class); 254b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey } 255b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey 256742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey public void onSecureContainersAvailable() { 257742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey synchronized (mSessions) { 258742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final ArraySet<String> unclaimed = new ArraySet<>(); 259742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey for (String cid : PackageHelper.getSecureContainerList()) { 260742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey if (isStageName(cid)) { 261742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey unclaimed.add(cid); 262742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 263742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 264742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 265742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey // Ignore stages claimed by active sessions 266742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey for (int i = 0; i < mSessions.size(); i++) { 267742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final PackageInstallerSession session = mSessions.valueAt(i); 268941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey final String cid = session.stageCid; 269742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 270742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey if (unclaimed.remove(cid)) { 271742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey // Claimed by active session, mount it 272742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey PackageHelper.mountSdDir(cid, PackageManagerService.getEncryptKey(), 273742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey Process.SYSTEM_UID); 274742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 275742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 276742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 277742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey // Clean up orphaned staging containers 278742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey for (String cid : unclaimed) { 279742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey Slog.w(TAG, "Deleting orphan container " + cid); 280742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey PackageHelper.destroySdDir(cid); 281742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 282742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 283742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 284742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 285742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey public static boolean isStageName(String name) { 286742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final boolean isFile = name.startsWith("vmdl") && name.endsWith(".tmp"); 287742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final boolean isContainer = name.startsWith("smdl") && name.endsWith(".tmp"); 288742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final boolean isLegacyContainer = name.startsWith("smdl2tmp"); 289742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey return isFile || isContainer || isLegacyContainer; 2907328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey } 2917328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey 292ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey @Deprecated 293b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey public File allocateStageDirLegacy(String volumeUuid) throws IOException { 294ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey synchronized (mSessions) { 295ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey try { 296ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey final int sessionId = allocateSessionIdLocked(); 297742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey mLegacySessions.put(sessionId, true); 298b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey final File stageDir = buildStageDir(volumeUuid, sessionId); 299b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey prepareStageDir(stageDir); 30077d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey return stageDir; 301ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } catch (IllegalStateException e) { 302ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey throw new IOException(e); 3033a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 3043a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 3053a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 3063a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 307742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey @Deprecated 308742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey public String allocateExternalStageCidLegacy() { 309742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey synchronized (mSessions) { 310742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final int sessionId = allocateSessionIdLocked(); 311742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey mLegacySessions.put(sessionId, true); 312742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey return "smdl" + sessionId + ".tmp"; 313742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 314742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 315742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 3163a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private void readSessionsLocked() { 3171cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (LOGD) Slog.v(TAG, "readSessionsLocked()"); 3181cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 3193a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey mSessions.clear(); 3201cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 3211cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey FileInputStream fis = null; 3221cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey try { 3231cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey fis = mSessionsFile.openRead(); 3241cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final XmlPullParser in = Xml.newPullParser(); 3251cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey in.setInput(fis, null); 3261cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 3271cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey int type; 3281cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey while ((type = in.next()) != END_DOCUMENT) { 3291cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (type == START_TAG) { 3301cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final String tag = in.getName(); 3311cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (TAG_SESSION.equals(tag)) { 3321cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final PackageInstallerSession session = readSessionLocked(in); 3331cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final long age = System.currentTimeMillis() - session.createdMillis; 3341cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 3351cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final boolean valid; 3361cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (age >= MAX_AGE_MILLIS) { 3371cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey Slog.w(TAG, "Abandoning old session first created at " 3381cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey + session.createdMillis); 3391cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey valid = false; 3401cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } else { 3411cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey valid = true; 3421cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 3431cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 3441cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (valid) { 3451cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mSessions.put(session.sessionId, session); 3461cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } else { 3471cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey // Since this is early during boot we don't send 3481cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey // any observer events about the session, but we 3491cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey // keep details around for dumpsys. 3501cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mHistoricalSessions.put(session.sessionId, session); 3511cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 3521cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 3531cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 3541cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 3551cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } catch (FileNotFoundException e) { 3561cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey // Missing sessions are okay, probably first boot 3571cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } catch (IOException e) { 3588d05172112436a81bed6e4a0810f8914509d8a4dDianne Hackborn Slog.wtf(TAG, "Failed reading install sessions", e); 3591cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } catch (XmlPullParserException e) { 3608d05172112436a81bed6e4a0810f8914509d8a4dDianne Hackborn Slog.wtf(TAG, "Failed reading install sessions", e); 3611cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } finally { 3621cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey IoUtils.closeQuietly(fis); 3631cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 3641cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 3651cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 3661cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private PackageInstallerSession readSessionLocked(XmlPullParser in) throws IOException { 3671cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final int sessionId = readIntAttribute(in, ATTR_SESSION_ID); 3681cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final int userId = readIntAttribute(in, ATTR_USER_ID); 3691cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final String installerPackageName = readStringAttribute(in, ATTR_INSTALLER_PACKAGE_NAME); 370e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey final int installerUid = readIntAttribute(in, ATTR_INSTALLER_UID, 371e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey mPm.getPackageUid(installerPackageName, userId)); 3721cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final long createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS); 373742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final String stageDirRaw = readStringAttribute(in, ATTR_SESSION_STAGE_DIR); 374742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final File stageDir = (stageDirRaw != null) ? new File(stageDirRaw) : null; 375742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final String stageCid = readStringAttribute(in, ATTR_SESSION_STAGE_CID); 37677d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey final boolean prepared = readBooleanAttribute(in, ATTR_PREPARED, true); 3771cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final boolean sealed = readBooleanAttribute(in, ATTR_SEALED); 3781cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 379a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey final SessionParams params = new SessionParams( 380a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey SessionParams.MODE_INVALID); 3811cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.mode = readIntAttribute(in, ATTR_MODE); 3821cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.installFlags = readIntAttribute(in, ATTR_INSTALL_FLAGS); 3831cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.installLocation = readIntAttribute(in, ATTR_INSTALL_LOCATION); 3841cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.sizeBytes = readLongAttribute(in, ATTR_SIZE_BYTES); 3851cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.appPackageName = readStringAttribute(in, ATTR_APP_PACKAGE_NAME); 3861cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.appIcon = readBitmapAttribute(in, ATTR_APP_ICON); 3871cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.appLabel = readStringAttribute(in, ATTR_APP_LABEL); 3881cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.originatingUri = readUriAttribute(in, ATTR_ORIGINATING_URI); 3891cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.referrerUri = readUriAttribute(in, ATTR_REFERRER_URI); 3901cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.abiOverride = readStringAttribute(in, ATTR_ABI_OVERRIDE); 391b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey params.volumeUuid = readStringAttribute(in, ATTR_VOLUME_UUID); 3921cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 39302bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey final File appIconFile = buildAppIconFile(sessionId); 39402bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey if (appIconFile.exists()) { 39502bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey params.appIcon = BitmapFactory.decodeFile(appIconFile.getAbsolutePath()); 39602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey params.appIconLastModified = appIconFile.lastModified(); 39702bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey } 39802bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey 399a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey return new PackageInstallerSession(mInternalCallback, mContext, mPm, 400e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey mInstallThread.getLooper(), sessionId, userId, installerPackageName, installerUid, 401e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey params, createdMillis, stageDir, stageCid, prepared, sealed); 4023a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 4033a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 4043a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private void writeSessionsLocked() { 4051cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (LOGD) Slog.v(TAG, "writeSessionsLocked()"); 4061cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 4071cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey FileOutputStream fos = null; 4081cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey try { 4091cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey fos = mSessionsFile.startWrite(); 4101cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 4111cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey XmlSerializer out = new FastXmlSerializer(); 4121cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey out.setOutput(fos, "utf-8"); 4131cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey out.startDocument(null, true); 4141cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey out.startTag(null, TAG_SESSIONS); 4151cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final int size = mSessions.size(); 4161cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey for (int i = 0; i < size; i++) { 4171cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final PackageInstallerSession session = mSessions.valueAt(i); 4181cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeSessionLocked(out, session); 4191cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 4201cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey out.endTag(null, TAG_SESSIONS); 4211cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey out.endDocument(); 4221cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 4231cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mSessionsFile.finishWrite(fos); 4241cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } catch (IOException e) { 4251cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (fos != null) { 4261cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mSessionsFile.failWrite(fos); 4271cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 4281cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 4291cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 4301cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 4311cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private void writeSessionLocked(XmlSerializer out, PackageInstallerSession session) 4321cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey throws IOException { 433a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey final SessionParams params = session.params; 4341cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 4351cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey out.startTag(null, TAG_SESSION); 4361cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 4371cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeIntAttribute(out, ATTR_SESSION_ID, session.sessionId); 4381cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeIntAttribute(out, ATTR_USER_ID, session.userId); 4391cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeStringAttribute(out, ATTR_INSTALLER_PACKAGE_NAME, 4401cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey session.installerPackageName); 441e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey writeIntAttribute(out, ATTR_INSTALLER_UID, session.installerUid); 4421cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeLongAttribute(out, ATTR_CREATED_MILLIS, session.createdMillis); 443941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey if (session.stageDir != null) { 444742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey writeStringAttribute(out, ATTR_SESSION_STAGE_DIR, 445941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey session.stageDir.getAbsolutePath()); 446742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 447941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey if (session.stageCid != null) { 448941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey writeStringAttribute(out, ATTR_SESSION_STAGE_CID, session.stageCid); 449742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 45077d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey writeBooleanAttribute(out, ATTR_PREPARED, session.isPrepared()); 451742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey writeBooleanAttribute(out, ATTR_SEALED, session.isSealed()); 4521cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 4531cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeIntAttribute(out, ATTR_MODE, params.mode); 4541cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeIntAttribute(out, ATTR_INSTALL_FLAGS, params.installFlags); 4551cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeIntAttribute(out, ATTR_INSTALL_LOCATION, params.installLocation); 4561cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeLongAttribute(out, ATTR_SIZE_BYTES, params.sizeBytes); 4571cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeStringAttribute(out, ATTR_APP_PACKAGE_NAME, params.appPackageName); 4581cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeStringAttribute(out, ATTR_APP_LABEL, params.appLabel); 4591cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeUriAttribute(out, ATTR_ORIGINATING_URI, params.originatingUri); 4601cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeUriAttribute(out, ATTR_REFERRER_URI, params.referrerUri); 4611cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeStringAttribute(out, ATTR_ABI_OVERRIDE, params.abiOverride); 462b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey writeStringAttribute(out, ATTR_VOLUME_UUID, params.volumeUuid); 4631cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 46402bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey // Persist app icon if changed since last written 46502bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey final File appIconFile = buildAppIconFile(session.sessionId); 46602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey if (params.appIcon == null && appIconFile.exists()) { 46702bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey appIconFile.delete(); 46802bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey } else if (params.appIcon != null 46902bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey && appIconFile.lastModified() != params.appIconLastModified) { 47002bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey if (LOGD) Slog.w(TAG, "Writing changed icon " + appIconFile); 47102bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey FileOutputStream os = null; 47202bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey try { 47302bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey os = new FileOutputStream(appIconFile); 47402bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey params.appIcon.compress(CompressFormat.PNG, 90, os); 47502bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey } catch (IOException e) { 47602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey Slog.w(TAG, "Failed to write icon " + appIconFile + ": " + e.getMessage()); 47702bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey } finally { 47802bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey IoUtils.closeQuietly(os); 47902bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey } 48002bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey 48102bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey params.appIconLastModified = appIconFile.lastModified(); 48202bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey } 48302bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey 4841cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey out.endTag(null, TAG_SESSION); 4853a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 4863a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 48702bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey private File buildAppIconFile(int sessionId) { 48802bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey return new File(mSessionsDir, "app_icon." + sessionId + ".png"); 48902bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey } 49002bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey 4913a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private void writeSessionsAsync() { 4923a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey IoThread.getHandler().post(new Runnable() { 4933a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey @Override 4943a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey public void run() { 4953a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey synchronized (mSessions) { 4963a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey writeSessionsLocked(); 4973a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 4983a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 4993a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey }); 5003a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 5013a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 5023a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey @Override 503a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey public int createSession(SessionParams params, String installerPackageName, int userId) { 504742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey try { 505742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey return createSessionInternal(params, installerPackageName, userId); 506742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } catch (IOException e) { 507742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey throw ExceptionUtils.wrap(e); 508742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 509742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 510742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 511742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey private int createSessionInternal(SessionParams params, String installerPackageName, int userId) 512742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey throws IOException { 5133a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey final int callingUid = Binder.getCallingUid(); 514e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey mPm.enforceCrossUserPermission(callingUid, userId, true, true, "createSession"); 5153a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 516e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey if (mPm.isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) { 5173a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey throw new SecurityException("User restriction prevents installing"); 5183a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 5193a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 5201cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) { 521e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey params.installFlags |= PackageManager.INSTALL_FROM_ADB; 5221cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 5233a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } else { 524ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey mAppOps.checkPackage(callingUid, installerPackageName); 525ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 526e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey params.installFlags &= ~PackageManager.INSTALL_FROM_ADB; 527e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey params.installFlags &= ~PackageManager.INSTALL_ALL_USERS; 528e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey params.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING; 5293a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 5303a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 5311cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey // Defensively resize giant app icons 5321cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (params.appIcon != null) { 5331cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final ActivityManager am = (ActivityManager) mContext.getSystemService( 5341cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey Context.ACTIVITY_SERVICE); 5351cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final int iconSize = am.getLauncherLargeIconSize(); 5361cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if ((params.appIcon.getWidth() > iconSize * 2) 5371cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey || (params.appIcon.getHeight() > iconSize * 2)) { 5381cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.appIcon = Bitmap.createScaledBitmap(params.appIcon, iconSize, iconSize, 5391cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey true); 5401cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 5411cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 5421cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 543b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey switch (params.mode) { 544b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey case SessionParams.MODE_FULL_INSTALL: 545b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey case SessionParams.MODE_INHERIT_EXISTING: 546b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey break; 547b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey default: 548b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey throw new IllegalArgumentException("Invalid install mode: " + params.mode); 549b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey } 550b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey 551b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey // If caller requested explicit location, sanity check it, otherwise 552b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey // resolve the best internal or adopted location. 553b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) { 554b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey if (!PackageHelper.fitsOnInternal(mContext, params.sizeBytes)) { 555b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey throw new IOException("No suitable internal storage available"); 556b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey } 557b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey 558b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey } else if ((params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) { 559b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey if (!PackageHelper.fitsOnExternal(mContext, params.sizeBytes)) { 560b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey throw new IOException("No suitable external storage available"); 561b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey } 562b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey 563b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey } else { 564b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey // For now, installs to adopted media are treated as internal from 565b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey // an install flag point-of-view. 566b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey params.setInstallFlagsInternal(); 567b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey 56877d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey // Resolve best location for install, based on combination of 56977d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey // requested install flags, delta size, and manifest settings. 570e812d9096915ad165de125520ed7371009587d1fRobin Lee final long ident = Binder.clearCallingIdentity(); 571e812d9096915ad165de125520ed7371009587d1fRobin Lee try { 572b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey params.volumeUuid = PackageHelper.resolveInstallVolume(mContext, 573b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey params.appPackageName, params.installLocation, params.sizeBytes); 574e812d9096915ad165de125520ed7371009587d1fRobin Lee } finally { 575e812d9096915ad165de125520ed7371009587d1fRobin Lee Binder.restoreCallingIdentity(ident); 576a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 577a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 578a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 579a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey final int sessionId; 580a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey final PackageInstallerSession session; 5813a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey synchronized (mSessions) { 5821cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey // Sanity check that installer isn't going crazy 583f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey final int activeCount = getSessionCount(mSessions, callingUid); 5841cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (activeCount >= MAX_ACTIVE_SESSIONS) { 585f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey throw new IllegalStateException( 586f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey "Too many active sessions for UID " + callingUid); 587f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey } 588f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey final int historicalCount = getSessionCount(mHistoricalSessions, callingUid); 589f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey if (historicalCount >= MAX_HISTORICAL_SESSIONS) { 590f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey throw new IllegalStateException( 591f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey "Too many historical sessions for UID " + callingUid); 5921cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 5931cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 594742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final long createdMillis = System.currentTimeMillis(); 595a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey sessionId = allocateSessionIdLocked(); 596a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 597742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey // We're staging to exactly one location 598742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey File stageDir = null; 599742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey String stageCid = null; 60077d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) { 601b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey stageDir = buildStageDir(params.volumeUuid, sessionId); 602742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } else { 60377d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey stageCid = buildExternalStageCid(sessionId); 604742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 6053a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 606a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey session = new PackageInstallerSession(mInternalCallback, mContext, mPm, 607e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey mInstallThread.getLooper(), sessionId, userId, installerPackageName, callingUid, 608e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey params, createdMillis, stageDir, stageCid, false, false); 6093a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey mSessions.put(sessionId, session); 6103a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 611a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 6121cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mCallbacks.notifySessionCreated(session.sessionId, session.userId); 613a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey writeSessionsAsync(); 614a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey return sessionId; 6153a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 6163a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 617381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey @Override 618ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey public void updateSessionAppIcon(int sessionId, Bitmap appIcon) { 619ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey synchronized (mSessions) { 620ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey final PackageInstallerSession session = mSessions.get(sessionId); 621ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey if (session == null || !isCallingUidOwner(session)) { 622ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey throw new SecurityException("Caller has no access to session " + sessionId); 623ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey } 62402bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey 62502bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey // Defensively resize giant app icons 62602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey if (appIcon != null) { 62702bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey final ActivityManager am = (ActivityManager) mContext.getSystemService( 62802bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey Context.ACTIVITY_SERVICE); 62902bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey final int iconSize = am.getLauncherLargeIconSize(); 63002bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey if ((appIcon.getWidth() > iconSize * 2) 63102bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey || (appIcon.getHeight() > iconSize * 2)) { 63202bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey appIcon = Bitmap.createScaledBitmap(appIcon, iconSize, iconSize, true); 63302bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey } 63402bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey } 63502bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey 636ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey session.params.appIcon = appIcon; 63702bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey session.params.appIconLastModified = -1; 63802bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey 639ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey mInternalCallback.onSessionBadgingChanged(session); 640ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey } 641ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey } 642ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey 643ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey @Override 644ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey public void updateSessionAppLabel(int sessionId, String appLabel) { 645ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey synchronized (mSessions) { 646ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey final PackageInstallerSession session = mSessions.get(sessionId); 647ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey if (session == null || !isCallingUidOwner(session)) { 648ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey throw new SecurityException("Caller has no access to session " + sessionId); 649ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey } 650ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey session.params.appLabel = appLabel; 651ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey mInternalCallback.onSessionBadgingChanged(session); 652ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey } 653ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey } 654ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey 655ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey @Override 656381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey public void abandonSession(int sessionId) { 657381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey synchronized (mSessions) { 658381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey final PackageInstallerSession session = mSessions.get(sessionId); 659381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey if (session == null || !isCallingUidOwner(session)) { 660381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey throw new SecurityException("Caller has no access to session " + sessionId); 661381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey } 662381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey session.abandon(); 663381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey } 664381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey } 665381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey 66677d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey @Override 66777d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey public IPackageInstallerSession openSession(int sessionId) { 66877d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey try { 66977d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey return openSessionInternal(sessionId); 67077d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey } catch (IOException e) { 67177d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey throw ExceptionUtils.wrap(e); 672742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 673742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 674742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 67577d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey private IPackageInstallerSession openSessionInternal(int sessionId) throws IOException { 6763a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey synchronized (mSessions) { 6773a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey final PackageInstallerSession session = mSessions.get(sessionId); 678381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey if (session == null || !isCallingUidOwner(session)) { 6793a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey throw new SecurityException("Caller has no access to session " + sessionId); 6803a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 681742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey session.open(); 6823a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey return session; 6833a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 6843a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 6853a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 6863a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private int allocateSessionIdLocked() { 6871cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey int n = 0; 6881cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey int sessionId; 6891cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey do { 690f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey sessionId = mRandom.nextInt(Integer.MAX_VALUE - 1) + 1; 691742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey if (mSessions.get(sessionId) == null && mHistoricalSessions.get(sessionId) == null 692742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey && !mLegacySessions.get(sessionId, false)) { 6931cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey return sessionId; 6941cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 6951cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } while (n++ < 32); 6961cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 6971cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey throw new IllegalStateException("Failed to allocate session ID"); 6983a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 6993a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 700b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey private File buildInternalStagingDir() { 701b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey return new File(Environment.getDataDirectory(), "app"); 702b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey } 703b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey 704b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey private File buildStagingDir(String volumeUuid) throws FileNotFoundException { 705b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey if (volumeUuid == null) { 706b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey return buildInternalStagingDir(); 707b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey } else { 708b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey final VolumeInfo vol = mStorage.findVolumeByUuid(volumeUuid); 709b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey if (vol != null && vol.type == VolumeInfo.TYPE_PRIVATE 710b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey && vol.state == VolumeInfo.STATE_MOUNTED) { 711b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey return new File(vol.path, "app"); 712b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey } else { 713b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey throw new FileNotFoundException("Failed to find volume for UUID " + volumeUuid); 714b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey } 715b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey } 716b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey } 717b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey 718b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey private File buildStageDir(String volumeUuid, int sessionId) throws FileNotFoundException { 719b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey final File stagingDir = buildStagingDir(volumeUuid); 720b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey return new File(stagingDir, "vmdl" + sessionId + ".tmp"); 72177d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey } 722ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 723b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey static void prepareStageDir(File stageDir) throws IOException { 72477d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey if (stageDir.exists()) { 72577d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey throw new IOException("Session dir already exists: " + stageDir); 726ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 727ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 728ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey try { 72977d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey Os.mkdir(stageDir.getAbsolutePath(), 0755); 73077d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey Os.chmod(stageDir.getAbsolutePath(), 0755); 731ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } catch (ErrnoException e) { 732ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey // This purposefully throws if directory already exists 73377d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey throw new IOException("Failed to prepare session dir: " + stageDir, e); 734ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 735ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 73677d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey if (!SELinux.restorecon(stageDir)) { 73777d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey throw new IOException("Failed to restorecon session dir: " + stageDir); 738ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 739ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 740ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 74177d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey private String buildExternalStageCid(int sessionId) { 74277d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey return "smdl" + sessionId + ".tmp"; 74377d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey } 744742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 74577d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey static void prepareExternalStageCid(String stageCid, long sizeBytes) throws IOException { 74677d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey if (PackageHelper.createSdDir(sizeBytes, stageCid, PackageManagerService.getEncryptKey(), 747742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey Process.SYSTEM_UID, true) == null) { 74877d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey throw new IOException("Failed to create session cid: " + stageCid); 749742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 750742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 751742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 7523a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey @Override 753a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey public SessionInfo getSessionInfo(int sessionId) { 75416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey synchronized (mSessions) { 75516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey final PackageInstallerSession session = mSessions.get(sessionId); 75616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey return session != null ? session.generateInfo() : null; 75716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 75816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 75916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey 76016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey @Override 76197d47ed036ff7bd3d7d2ddc1c6df1104ec237559Jeff Sharkey public ParceledListSlice<SessionInfo> getAllSessions(int userId) { 7628cd28b57ed732656d002d97879e15c5695b54fffAmith Yamasani mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, "getAllSessions"); 7633a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 764a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey final List<SessionInfo> result = new ArrayList<>(); 7653a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey synchronized (mSessions) { 7663a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey for (int i = 0; i < mSessions.size(); i++) { 7673a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey final PackageInstallerSession session = mSessions.valueAt(i); 768bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey if (session.userId == userId) { 769bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey result.add(session.generateInfo()); 7703a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 7713a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 7723a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 77397d47ed036ff7bd3d7d2ddc1c6df1104ec237559Jeff Sharkey return new ParceledListSlice<>(result); 7743a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 7753a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 7763a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey @Override 77797d47ed036ff7bd3d7d2ddc1c6df1104ec237559Jeff Sharkey public ParceledListSlice<SessionInfo> getMySessions(String installerPackageName, int userId) { 7788cd28b57ed732656d002d97879e15c5695b54fffAmith Yamasani mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, "getMySessions"); 77916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey mAppOps.checkPackage(Binder.getCallingUid(), installerPackageName); 78016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey 781a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey final List<SessionInfo> result = new ArrayList<>(); 78216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey synchronized (mSessions) { 78316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey for (int i = 0; i < mSessions.size(); i++) { 78416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey final PackageInstallerSession session = mSessions.valueAt(i); 78516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey if (Objects.equals(session.installerPackageName, installerPackageName) 78616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey && session.userId == userId) { 78716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey result.add(session.generateInfo()); 78816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 78916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 79016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 79197d47ed036ff7bd3d7d2ddc1c6df1104ec237559Jeff Sharkey return new ParceledListSlice<>(result); 79216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 79316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey 79416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey @Override 79539fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz public void uninstall(String packageName, String callerPackageName, int flags, 79639fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz IntentSender statusReceiver, int userId) { 79739fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz final int callingUid = Binder.getCallingUid(); 79839fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz mPm.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall"); 79939fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz if ((callingUid != Process.SHELL_UID) && (callingUid != Process.ROOT_UID)) { 80039fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz mAppOps.checkPackage(callingUid, callerPackageName); 80139fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz } 80239fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz 80339fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz // Check whether the caller is device owner 80439fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService( 80539fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz Context.DEVICE_POLICY_SERVICE); 80639fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz boolean isDeviceOwner = (dpm != null) && dpm.isDeviceOwnerApp(callerPackageName); 80716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey 808a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext, 80939fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz statusReceiver, packageName, isDeviceOwner, userId); 810f06009542390472872da986486d385001e91a2a7Jeff Sharkey if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES) 811f06009542390472872da986486d385001e91a2a7Jeff Sharkey == PackageManager.PERMISSION_GRANTED) { 812f06009542390472872da986486d385001e91a2a7Jeff Sharkey // Sweet, call straight through! 813a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey mPm.deletePackage(packageName, adapter.getBinder(), userId, flags); 81439fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz } else if (isDeviceOwner) { 81539fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz // Allow the DeviceOwner to silently delete packages 81639fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz // Need to clear the calling identity to get DELETE_PACKAGES permission 81739fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz long ident = Binder.clearCallingIdentity(); 81839fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz try { 81939fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz mPm.deletePackage(packageName, adapter.getBinder(), userId, flags); 82039fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz } finally { 82139fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz Binder.restoreCallingIdentity(ident); 82239fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz } 823f06009542390472872da986486d385001e91a2a7Jeff Sharkey } else { 824f06009542390472872da986486d385001e91a2a7Jeff Sharkey // Take a short detour to confirm with user 825f06009542390472872da986486d385001e91a2a7Jeff Sharkey final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE); 826f06009542390472872da986486d385001e91a2a7Jeff Sharkey intent.setData(Uri.fromParts("package", packageName, null)); 827a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey intent.putExtra(PackageInstaller.EXTRA_CALLBACK, adapter.getBinder().asBinder()); 828a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey adapter.onUserActionRequired(intent); 829f06009542390472872da986486d385001e91a2a7Jeff Sharkey } 8303a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 8313a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 8323a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey @Override 8337328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey public void setPermissionsResult(int sessionId, boolean accepted) { 8347328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, TAG); 8357328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey 8367328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey synchronized (mSessions) { 8377328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey mSessions.get(sessionId).setPermissionsResult(accepted); 8387328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey } 8397328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey } 8407328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey 8417328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey @Override 84216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public void registerCallback(IPackageInstallerCallback callback, int userId) { 8438cd28b57ed732656d002d97879e15c5695b54fffAmith Yamasani mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, "registerCallback"); 8441cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mCallbacks.register(callback, userId); 845bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey } 846bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey 847bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey @Override 84816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public void unregisterCallback(IPackageInstallerCallback callback) { 84916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey mCallbacks.unregister(callback); 850a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 851a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 852f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey private static int getSessionCount(SparseArray<PackageInstallerSession> sessions, 853f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey int installerUid) { 8541cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey int count = 0; 855f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey final int size = sessions.size(); 8561cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey for (int i = 0; i < size; i++) { 857f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey final PackageInstallerSession session = sessions.valueAt(i); 8581cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (session.installerUid == installerUid) { 8591cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey count++; 8601cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 8611cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 8621cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey return count; 8631cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 8641cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 8651cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private boolean isCallingUidOwner(PackageInstallerSession session) { 8661cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final int callingUid = Binder.getCallingUid(); 8671cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (callingUid == Process.ROOT_UID) { 8681cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey return true; 8691cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } else { 8701cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey return (session != null) && (callingUid == session.installerUid); 871a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 872a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 873a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 874a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey static class PackageDeleteObserverAdapter extends PackageDeleteObserver { 875a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey private final Context mContext; 876a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey private final IntentSender mTarget; 877bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey private final String mPackageName; 87839fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz private final Notification mNotification; 879a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey 880bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey public PackageDeleteObserverAdapter(Context context, IntentSender target, 88139fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz String packageName, boolean showNotification, int userId) { 882a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey mContext = context; 883a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey mTarget = target; 884bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey mPackageName = packageName; 88539fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz if (showNotification) { 88639fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz mNotification = buildSuccessNotification(mContext, 88739fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz mContext.getResources().getString(R.string.package_deleted_device_owner), 88839fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz packageName, 88939fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz userId); 89039fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz } else { 89139fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz mNotification = null; 89239fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz } 893a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 894a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey 895a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey @Override 896a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey public void onUserActionRequired(Intent intent) { 897a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey final Intent fillIn = new Intent(); 898bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName); 899a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_STATUS, 900742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey PackageInstaller.STATUS_PENDING_USER_ACTION); 901a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey fillIn.putExtra(Intent.EXTRA_INTENT, intent); 902a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey try { 903a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey mTarget.sendIntent(mContext, 0, fillIn, null, null); 904a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } catch (SendIntentException ignored) { 905a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 906a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 907a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey 908a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey @Override 909a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey public void onPackageDeleted(String basePackageName, int returnCode, String msg) { 91039fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz if (PackageManager.DELETE_SUCCEEDED == returnCode && mNotification != null) { 91139fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz NotificationManager notificationManager = (NotificationManager) 91239fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz mContext.getSystemService(Context.NOTIFICATION_SERVICE); 91339fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz notificationManager.notify(basePackageName, 0, mNotification); 91439fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz } 915a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey final Intent fillIn = new Intent(); 916bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName); 917a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_STATUS, 918a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey PackageManager.deleteStatusToPublicStatus(returnCode)); 919a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, 920a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey PackageManager.deleteStatusToString(returnCode, msg)); 921a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode); 922a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey try { 923a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey mTarget.sendIntent(mContext, 0, fillIn, null, null); 924a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } catch (SendIntentException ignored) { 925a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 926a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 927a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 928a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey 929a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey static class PackageInstallObserverAdapter extends PackageInstallObserver { 930a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey private final Context mContext; 931a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey private final IntentSender mTarget; 932bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey private final int mSessionId; 93339fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz private final boolean mShowNotification; 93439fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz private final int mUserId; 935a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey 93639fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz public PackageInstallObserverAdapter(Context context, IntentSender target, int sessionId, 93739fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz boolean showNotification, int userId) { 938a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey mContext = context; 939a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey mTarget = target; 940bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey mSessionId = sessionId; 94139fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz mShowNotification = showNotification; 94239fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz mUserId = userId; 943a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 944a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey 945a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey @Override 946a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey public void onUserActionRequired(Intent intent) { 947a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey final Intent fillIn = new Intent(); 948bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId); 949a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_STATUS, 950742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey PackageInstaller.STATUS_PENDING_USER_ACTION); 951a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey fillIn.putExtra(Intent.EXTRA_INTENT, intent); 952a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey try { 953a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey mTarget.sendIntent(mContext, 0, fillIn, null, null); 954a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } catch (SendIntentException ignored) { 955a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 956a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 957a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey 958a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey @Override 959a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey public void onPackageInstalled(String basePackageName, int returnCode, String msg, 960a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey Bundle extras) { 96139fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz if (PackageManager.INSTALL_SUCCEEDED == returnCode && mShowNotification) { 96239fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz Notification notification = buildSuccessNotification(mContext, 96339fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz mContext.getResources().getString(R.string.package_installed_device_owner), 96439fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz basePackageName, 96539fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz mUserId); 96639fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz if (notification != null) { 96739fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz NotificationManager notificationManager = (NotificationManager) 96839fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz mContext.getSystemService(Context.NOTIFICATION_SERVICE); 96939fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz notificationManager.notify(basePackageName, 0, notification); 97039fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz } 97139fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz } 972a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey final Intent fillIn = new Intent(); 973bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId); 974a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_STATUS, 975a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey PackageManager.installStatusToPublicStatus(returnCode)); 976a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, 977a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey PackageManager.installStatusToString(returnCode, msg)); 978a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode); 979a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey if (extras != null) { 980a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey final String existing = extras.getString( 981a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE); 982a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey if (!TextUtils.isEmpty(existing)) { 983941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_OTHER_PACKAGE_NAME, existing); 984a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 985a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 986a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey try { 987a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey mTarget.sendIntent(mContext, 0, fillIn, null, null); 988a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } catch (SendIntentException ignored) { 989a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 990a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 991a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 992a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey 99339fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz /** 99439fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz * Build a notification for package installation / deletion by device owners that is shown if 99539fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz * the operation succeeds. 99639fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz */ 99739fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz private static Notification buildSuccessNotification(Context context, String contentText, 99839fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz String basePackageName, int userId) { 99939fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz PackageInfo packageInfo = null; 100039fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz try { 100139fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz packageInfo = AppGlobals.getPackageManager().getPackageInfo( 100239fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz basePackageName, 0, userId); 100339fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz } catch (RemoteException ignored) { 100439fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz } 100539fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz if (packageInfo == null || packageInfo.applicationInfo == null) { 100639fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz Slog.w(TAG, "Notification not built for package: " + basePackageName); 100739fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz return null; 100839fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz } 100939fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz PackageManager pm = context.getPackageManager(); 101039fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz Bitmap packageIcon = ImageUtils.buildScaledBitmap( 101139fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz packageInfo.applicationInfo.loadIcon(pm), 101239fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz context.getResources().getDimensionPixelSize( 101339fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz android.R.dimen.notification_large_icon_width), 101439fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz context.getResources().getDimensionPixelSize( 101539fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz android.R.dimen.notification_large_icon_height)); 101639fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz CharSequence packageLabel = packageInfo.applicationInfo.loadLabel(pm); 101739fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz return new Notification.Builder(context) 101839fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz .setSmallIcon(R.drawable.ic_check_circle_24px) 101939fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz .setColor(context.getResources().getColor( 102039fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz R.color.system_notification_accent_color)) 102139fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz .setContentTitle(packageLabel) 102239fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz .setContentText(contentText) 102339fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz .setLargeIcon(packageIcon) 102439fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz .build(); 102539fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz } 102639fb7fd730dc2113ced7e663d7a35e48a4c6b1aeBenjamin Franz 10271cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static class Callbacks extends Handler { 10281cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final int MSG_SESSION_CREATED = 1; 1029ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey private static final int MSG_SESSION_BADGING_CHANGED = 2; 1030bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey private static final int MSG_SESSION_ACTIVE_CHANGED = 3; 1031ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey private static final int MSG_SESSION_PROGRESS_CHANGED = 4; 1032bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey private static final int MSG_SESSION_FINISHED = 5; 10331cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 10341cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private final RemoteCallbackList<IPackageInstallerCallback> 10351cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mCallbacks = new RemoteCallbackList<>(); 10361cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 10371cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey public Callbacks(Looper looper) { 10381cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey super(looper); 1039a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 1040a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 10411cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey public void register(IPackageInstallerCallback callback, int userId) { 10421cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mCallbacks.register(callback, new UserHandle(userId)); 10431cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 10441cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 10451cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey public void unregister(IPackageInstallerCallback callback) { 10461cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mCallbacks.unregister(callback); 10471cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 10481cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 10491cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey @Override 10501cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey public void handleMessage(Message msg) { 10511cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final int userId = msg.arg2; 10521cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final int n = mCallbacks.beginBroadcast(); 10531cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey for (int i = 0; i < n; i++) { 10541cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final IPackageInstallerCallback callback = mCallbacks.getBroadcastItem(i); 10551cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final UserHandle user = (UserHandle) mCallbacks.getBroadcastCookie(i); 10561cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey // TODO: dispatch notifications for slave profiles 10571cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (userId == user.getIdentifier()) { 10581cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey try { 10591cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey invokeCallback(callback, msg); 10601cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } catch (RemoteException ignored) { 10611cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 1062a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 1063a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 10641cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mCallbacks.finishBroadcast(); 1065a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 1066a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 10671cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private void invokeCallback(IPackageInstallerCallback callback, Message msg) 10681cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey throws RemoteException { 10691cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final int sessionId = msg.arg1; 10701cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey switch (msg.what) { 10711cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey case MSG_SESSION_CREATED: 10721cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey callback.onSessionCreated(sessionId); 10731cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey break; 1074ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey case MSG_SESSION_BADGING_CHANGED: 1075ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey callback.onSessionBadgingChanged(sessionId); 1076ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey break; 1077bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey case MSG_SESSION_ACTIVE_CHANGED: 1078bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey callback.onSessionActiveChanged(sessionId, (boolean) msg.obj); 10791cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey break; 10801cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey case MSG_SESSION_PROGRESS_CHANGED: 10811cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey callback.onSessionProgressChanged(sessionId, (float) msg.obj); 10821cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey break; 10831cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey case MSG_SESSION_FINISHED: 10841cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey callback.onSessionFinished(sessionId, (boolean) msg.obj); 10851cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey break; 1086a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 1087a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 10881cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 10891cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private void notifySessionCreated(int sessionId, int userId) { 10901cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey obtainMessage(MSG_SESSION_CREATED, sessionId, userId).sendToTarget(); 10911cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 10921cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 1093ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey private void notifySessionBadgingChanged(int sessionId, int userId) { 1094ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey obtainMessage(MSG_SESSION_BADGING_CHANGED, sessionId, userId).sendToTarget(); 1095ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey } 1096ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey 1097bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey private void notifySessionActiveChanged(int sessionId, int userId, boolean active) { 1098bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey obtainMessage(MSG_SESSION_ACTIVE_CHANGED, sessionId, userId, active).sendToTarget(); 10991cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 11001cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 11011cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private void notifySessionProgressChanged(int sessionId, int userId, float progress) { 11021cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey obtainMessage(MSG_SESSION_PROGRESS_CHANGED, sessionId, userId, progress).sendToTarget(); 11031cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 11041cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 11051cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey public void notifySessionFinished(int sessionId, int userId, boolean success) { 11061cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey obtainMessage(MSG_SESSION_FINISHED, sessionId, userId, success).sendToTarget(); 11071cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 1108a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 1109a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 1110a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey void dump(IndentingPrintWriter pw) { 1111a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey synchronized (mSessions) { 11129a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.println("Active install sessions:"); 11139a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.increaseIndent(); 11149a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey int N = mSessions.size(); 1115a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey for (int i = 0; i < N; i++) { 1116a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey final PackageInstallerSession session = mSessions.valueAt(i); 1117a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey session.dump(pw); 1118a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey pw.println(); 1119a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 11209a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.println(); 11219a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.decreaseIndent(); 11229a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey 11239a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.println("Historical install sessions:"); 11249a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.increaseIndent(); 11259a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey N = mHistoricalSessions.size(); 11269a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey for (int i = 0; i < N; i++) { 11279a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey final PackageInstallerSession session = mHistoricalSessions.valueAt(i); 11289a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey session.dump(pw); 11299a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.println(); 11309a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey } 11319a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.println(); 11329a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.decreaseIndent(); 1133742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 1134742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey pw.println("Legacy install sessions:"); 1135742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey pw.increaseIndent(); 1136742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey pw.println(mLegacySessions.toString()); 1137742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey pw.decreaseIndent(); 1138a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 1139bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey } 1140bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey 11411cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey class InternalCallback { 1142ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey public void onSessionBadgingChanged(PackageInstallerSession session) { 1143ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey mCallbacks.notifySessionBadgingChanged(session.sessionId, session.userId); 1144ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey writeSessionsAsync(); 11451cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 11461cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 1147bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey public void onSessionActiveChanged(PackageInstallerSession session, boolean active) { 1148bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey mCallbacks.notifySessionActiveChanged(session.sessionId, session.userId, active); 1149742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 1150742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 1151ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey public void onSessionProgressChanged(PackageInstallerSession session, float progress) { 1152ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey mCallbacks.notifySessionProgressChanged(session.sessionId, session.userId, progress); 1153ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey } 1154ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey 1155cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey public void onSessionFinished(final PackageInstallerSession session, boolean success) { 11561cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mCallbacks.notifySessionFinished(session.sessionId, session.userId, success); 1157cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey 1158cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey mInstallHandler.post(new Runnable() { 1159cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey @Override 1160cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey public void run() { 1161cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey synchronized (mSessions) { 1162cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey mSessions.remove(session.sessionId); 1163cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey mHistoricalSessions.put(session.sessionId, session); 116402bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey 116502bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey final File appIconFile = buildAppIconFile(session.sessionId); 116602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey if (appIconFile.exists()) { 116702bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey appIconFile.delete(); 116802bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey } 116902bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey 1170cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey writeSessionsLocked(); 1171cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey } 1172cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey } 1173cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey }); 11743a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 1175bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey 117677d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey public void onSessionPrepared(PackageInstallerSession session) { 117777d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey // We prepared the destination to write into; we want to persist 117877d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey // this, but it's not critical enough to block for. 117977d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey writeSessionsAsync(); 118077d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey } 118177d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey 1182cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey public void onSessionSealedBlocking(PackageInstallerSession session) { 1183bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey // It's very important that we block until we've recorded the 1184bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey // session as being sealed, since we never want to allow mutation 1185bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey // after sealing. 1186cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey synchronized (mSessions) { 1187cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey writeSessionsLocked(); 1188cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey } 1189bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey } 11903a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 11913a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey} 1192