PackageInstallerService.java revision 381d94b712605112b35d7f70064b0d18bd877877
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 193a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport static android.content.pm.PackageManager.INSTALL_ALL_USERS; 203a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport static android.content.pm.PackageManager.INSTALL_FROM_ADB; 213a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport static android.content.pm.PackageManager.INSTALL_REPLACE_EXISTING; 221cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.readBitmapAttribute; 231cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.readBooleanAttribute; 241cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.readIntAttribute; 251cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.readLongAttribute; 261cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.readStringAttribute; 271cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.readUriAttribute; 281cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.writeBitmapAttribute; 291cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.writeBooleanAttribute; 301cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.writeIntAttribute; 311cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.writeLongAttribute; 321cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.writeStringAttribute; 331cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.writeUriAttribute; 341cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; 351cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static org.xmlpull.v1.XmlPullParser.START_TAG; 361cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 371cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.app.ActivityManager; 383a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.app.AppOpsManager; 39a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.app.PackageDeleteObserver; 40a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.app.PackageInstallObserver; 413a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.content.Context; 42f06009542390472872da986486d385001e91a2a7Jeff Sharkeyimport android.content.Intent; 43a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.content.IntentSender; 44a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.content.IntentSender.SendIntentException; 45742e790294b3441b79f715fe447069b63c6065dbJeff Sharkeyimport android.content.pm.ApplicationInfo; 463a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.content.pm.IPackageInstaller; 4716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkeyimport android.content.pm.IPackageInstallerCallback; 483a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.content.pm.IPackageInstallerSession; 49f06009542390472872da986486d385001e91a2a7Jeff Sharkeyimport android.content.pm.PackageInstaller; 50941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkeyimport android.content.pm.PackageParser; 51a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.content.pm.PackageInstaller.SessionInfo; 52a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.content.pm.PackageInstaller.SessionParams; 53941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkeyimport android.content.pm.PackageParser.PackageLite; 54941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkeyimport android.content.pm.PackageParser.PackageParserException; 5516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkeyimport android.content.pm.PackageManager; 561cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.graphics.Bitmap; 57f06009542390472872da986486d385001e91a2a7Jeff Sharkeyimport android.net.Uri; 583a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.Binder; 59a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.os.Bundle; 601cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.os.Environment; 61bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkeyimport android.os.Environment.UserEnvironment; 623a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.FileUtils; 631cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.os.Handler; 643a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.HandlerThread; 651cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.os.Looper; 661cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.os.Message; 673a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.Process; 68a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkeyimport android.os.RemoteCallbackList; 69a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkeyimport android.os.RemoteException; 70ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport android.os.SELinux; 713a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.UserHandle; 723a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.UserManager; 73742e790294b3441b79f715fe447069b63c6065dbJeff Sharkeyimport android.os.storage.StorageManager; 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; 811cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.util.Log; 823a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.util.Slog; 833a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.util.SparseArray; 84742e790294b3441b79f715fe447069b63c6065dbJeff Sharkeyimport android.util.SparseBooleanArray; 851cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.util.Xml; 863a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 873a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport com.android.internal.annotations.GuardedBy; 88742e790294b3441b79f715fe447069b63c6065dbJeff Sharkeyimport com.android.internal.content.PackageHelper; 891cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport com.android.internal.util.FastXmlSerializer; 90a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkeyimport com.android.internal.util.IndentingPrintWriter; 913a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport com.android.server.IoThread; 923a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport com.google.android.collect.Sets; 933a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 941cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport libcore.io.IoUtils; 951cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 961cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport org.xmlpull.v1.XmlPullParser; 971cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport org.xmlpull.v1.XmlPullParserException; 981cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport org.xmlpull.v1.XmlSerializer; 991cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 1003a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport java.io.File; 1011cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport java.io.FileInputStream; 1021cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport java.io.FileNotFoundException; 1031cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport java.io.FileOutputStream; 104ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport java.io.FilenameFilter; 105ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport java.io.IOException; 1061cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport java.security.SecureRandom; 107bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkeyimport java.util.ArrayList; 108bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkeyimport java.util.List; 10916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkeyimport java.util.Objects; 1101cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport java.util.Random; 1113a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1123a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeypublic class PackageInstallerService extends IPackageInstaller.Stub { 1133a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private static final String TAG = "PackageInstaller"; 1141cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final boolean LOGD = true; 1153a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1163a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey // TODO: remove outstanding sessions when installer package goes away 1176c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey // TODO: notify listeners in other users when package has been installed there 118742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey // TODO: purge expired sessions periodically in addition to at reboot 1193a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1201cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey /** XML constants used in {@link #mSessionsFile} */ 1211cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String TAG_SESSIONS = "sessions"; 1221cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String TAG_SESSION = "session"; 1231cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_SESSION_ID = "sessionId"; 1241cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_USER_ID = "userId"; 1251cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_INSTALLER_PACKAGE_NAME = "installerPackageName"; 1261cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_CREATED_MILLIS = "createdMillis"; 1271cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_SESSION_STAGE_DIR = "sessionStageDir"; 128742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey private static final String ATTR_SESSION_STAGE_CID = "sessionStageCid"; 1291cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_SEALED = "sealed"; 1301cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_MODE = "mode"; 1311cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_INSTALL_FLAGS = "installFlags"; 1321cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_INSTALL_LOCATION = "installLocation"; 1331cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_SIZE_BYTES = "sizeBytes"; 1341cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_APP_PACKAGE_NAME = "appPackageName"; 1351cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_APP_ICON = "appIcon"; 1361cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_APP_LABEL = "appLabel"; 1371cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_ORIGINATING_URI = "originatingUri"; 1381cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_REFERRER_URI = "referrerUri"; 1391cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_ABI_OVERRIDE = "abiOverride"; 1401cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 141f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey /** Automatically destroy sessions older than this */ 1421cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final long MAX_AGE_MILLIS = 3 * DateUtils.DAY_IN_MILLIS; 143f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey /** Upper bound on number of active sessions for a UID */ 1441cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final long MAX_ACTIVE_SESSIONS = 1024; 145f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey /** Upper bound on number of historical sessions for a UID */ 146f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey private static final long MAX_HISTORICAL_SESSIONS = 1048576; 1471cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 1483a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private final Context mContext; 1493a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private final PackageManagerService mPm; 1503a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private final AppOpsManager mAppOps; 151742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey private final StorageManager mStorage; 1523a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1533a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private final File mStagingDir; 154ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey private final HandlerThread mInstallThread; 1553a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1561cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private final Callbacks mCallbacks; 1571cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 1581cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey /** 1591cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * File storing persisted {@link #mSessions}. 1601cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey */ 1611cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private final AtomicFile mSessionsFile; 1621cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 1631cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private final InternalCallback mInternalCallback = new InternalCallback(); 1641cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 1651cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey /** 1661cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * Used for generating session IDs. Since this is created at boot time, 1671cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * normal random might be predictable. 1681cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey */ 1691cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private final Random mRandom = new SecureRandom(); 1703a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1713a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey @GuardedBy("mSessions") 1723a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>(); 1733a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1749a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey /** Historical sessions kept around for debugging purposes */ 1759a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey @GuardedBy("mSessions") 1769a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey private final SparseArray<PackageInstallerSession> mHistoricalSessions = new SparseArray<>(); 1779a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey 178742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey /** Sessions allocated to legacy users */ 179742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey @GuardedBy("mSessions") 180742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey private final SparseBooleanArray mLegacySessions = new SparseBooleanArray(); 181742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 182ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey private static final FilenameFilter sStageFilter = new FilenameFilter() { 183ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey @Override 184ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey public boolean accept(File dir, String name) { 185742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey return isStageName(name); 186ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 187ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey }; 188ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 1893a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey public PackageInstallerService(Context context, PackageManagerService pm, File stagingDir) { 1903a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey mContext = context; 1913a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey mPm = pm; 1923a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); 193742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey mStorage = StorageManager.from(mContext); 1943a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1953a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey mStagingDir = stagingDir; 196ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 197ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey mInstallThread = new HandlerThread(TAG); 198ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey mInstallThread.start(); 1993a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 2001cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mCallbacks = new Callbacks(mInstallThread.getLooper()); 2011cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 2021cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mSessionsFile = new AtomicFile( 2031cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey new File(Environment.getSystemSecureDirectory(), "install_sessions.xml")); 2041cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 2053a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey synchronized (mSessions) { 2063a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey readSessionsLocked(); 2073a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 208742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final ArraySet<File> unclaimed = Sets.newArraySet(mStagingDir.listFiles(sStageFilter)); 209742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 210742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey // Ignore stages claimed by active sessions 2113a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey for (int i = 0; i < mSessions.size(); i++) { 212ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey final PackageInstallerSession session = mSessions.valueAt(i); 213941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey unclaimed.remove(session.stageDir); 214ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 215742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 216742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey // Clean up orphaned staging directories 217742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey for (File stage : unclaimed) { 218ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey Slog.w(TAG, "Deleting orphan stage " + stage); 219ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey if (stage.isDirectory()) { 220ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey FileUtils.deleteContents(stage); 221ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 222ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey stage.delete(); 2233a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 224ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 225ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 226ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 227742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey public void onSecureContainersAvailable() { 228742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey synchronized (mSessions) { 229742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final ArraySet<String> unclaimed = new ArraySet<>(); 230742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey for (String cid : PackageHelper.getSecureContainerList()) { 231742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey if (isStageName(cid)) { 232742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey unclaimed.add(cid); 233742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 234742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 235742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 236742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey // Ignore stages claimed by active sessions 237742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey for (int i = 0; i < mSessions.size(); i++) { 238742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final PackageInstallerSession session = mSessions.valueAt(i); 239941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey final String cid = session.stageCid; 240742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 241742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey if (unclaimed.remove(cid)) { 242742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey // Claimed by active session, mount it 243742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey PackageHelper.mountSdDir(cid, PackageManagerService.getEncryptKey(), 244742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey Process.SYSTEM_UID); 245742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 246742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 247742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 248742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey // Clean up orphaned staging containers 249742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey for (String cid : unclaimed) { 250742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey Slog.w(TAG, "Deleting orphan container " + cid); 251742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey PackageHelper.destroySdDir(cid); 252742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 253742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 254742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 255742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 256742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey public static boolean isStageName(String name) { 257742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final boolean isFile = name.startsWith("vmdl") && name.endsWith(".tmp"); 258742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final boolean isContainer = name.startsWith("smdl") && name.endsWith(".tmp"); 259742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final boolean isLegacyContainer = name.startsWith("smdl2tmp"); 260742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey return isFile || isContainer || isLegacyContainer; 2617328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey } 2627328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey 263ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey @Deprecated 264742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey public File allocateInternalStageDirLegacy() throws IOException { 265ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey synchronized (mSessions) { 266ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey try { 267ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey final int sessionId = allocateSessionIdLocked(); 268742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey mLegacySessions.put(sessionId, true); 269742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey return prepareInternalStageDir(sessionId); 270ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } catch (IllegalStateException e) { 271ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey throw new IOException(e); 2723a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 2733a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 2743a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 2753a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 276742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey @Deprecated 277742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey public String allocateExternalStageCidLegacy() { 278742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey synchronized (mSessions) { 279742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final int sessionId = allocateSessionIdLocked(); 280742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey mLegacySessions.put(sessionId, true); 281742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey return "smdl" + sessionId + ".tmp"; 282742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 283742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 284742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 2853a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private void readSessionsLocked() { 2861cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (LOGD) Slog.v(TAG, "readSessionsLocked()"); 2871cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 2883a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey mSessions.clear(); 2891cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 2901cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey FileInputStream fis = null; 2911cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey try { 2921cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey fis = mSessionsFile.openRead(); 2931cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final XmlPullParser in = Xml.newPullParser(); 2941cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey in.setInput(fis, null); 2951cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 2961cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey int type; 2971cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey while ((type = in.next()) != END_DOCUMENT) { 2981cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (type == START_TAG) { 2991cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final String tag = in.getName(); 3001cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (TAG_SESSION.equals(tag)) { 3011cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final PackageInstallerSession session = readSessionLocked(in); 3021cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final long age = System.currentTimeMillis() - session.createdMillis; 3031cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 3041cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final boolean valid; 3051cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (age >= MAX_AGE_MILLIS) { 3061cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey Slog.w(TAG, "Abandoning old session first created at " 3071cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey + session.createdMillis); 3081cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey valid = false; 309941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey } else if (session.stageDir != null 310941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey && !session.stageDir.exists()) { 311742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey Slog.w(TAG, "Abandoning internal session with missing stage " 312941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey + session.stageDir); 3131cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey valid = false; 3141cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } else { 3151cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey valid = true; 3161cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 3171cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 3181cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (valid) { 3191cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mSessions.put(session.sessionId, session); 3201cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } else { 3211cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey // Since this is early during boot we don't send 3221cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey // any observer events about the session, but we 3231cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey // keep details around for dumpsys. 3241cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mHistoricalSessions.put(session.sessionId, session); 3251cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 3261cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 3271cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 3281cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 3291cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } catch (FileNotFoundException e) { 3301cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey // Missing sessions are okay, probably first boot 3311cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } catch (IOException e) { 3321cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey Log.wtf(TAG, "Failed reading install sessions", e); 3331cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } catch (XmlPullParserException e) { 3341cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey Log.wtf(TAG, "Failed reading install sessions", e); 3351cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } finally { 3361cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey IoUtils.closeQuietly(fis); 3371cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 3381cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 3391cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 3401cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private PackageInstallerSession readSessionLocked(XmlPullParser in) throws IOException { 3411cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final int sessionId = readIntAttribute(in, ATTR_SESSION_ID); 3421cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final int userId = readIntAttribute(in, ATTR_USER_ID); 3431cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final String installerPackageName = readStringAttribute(in, ATTR_INSTALLER_PACKAGE_NAME); 3441cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final long createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS); 345742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final String stageDirRaw = readStringAttribute(in, ATTR_SESSION_STAGE_DIR); 346742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final File stageDir = (stageDirRaw != null) ? new File(stageDirRaw) : null; 347742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final String stageCid = readStringAttribute(in, ATTR_SESSION_STAGE_CID); 3481cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final boolean sealed = readBooleanAttribute(in, ATTR_SEALED); 3491cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 350a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey final SessionParams params = new SessionParams( 351a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey SessionParams.MODE_INVALID); 3521cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.mode = readIntAttribute(in, ATTR_MODE); 3531cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.installFlags = readIntAttribute(in, ATTR_INSTALL_FLAGS); 3541cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.installLocation = readIntAttribute(in, ATTR_INSTALL_LOCATION); 3551cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.sizeBytes = readLongAttribute(in, ATTR_SIZE_BYTES); 3561cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.appPackageName = readStringAttribute(in, ATTR_APP_PACKAGE_NAME); 3571cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.appIcon = readBitmapAttribute(in, ATTR_APP_ICON); 3581cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.appLabel = readStringAttribute(in, ATTR_APP_LABEL); 3591cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.originatingUri = readUriAttribute(in, ATTR_ORIGINATING_URI); 3601cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.referrerUri = readUriAttribute(in, ATTR_REFERRER_URI); 3611cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.abiOverride = readStringAttribute(in, ATTR_ABI_OVERRIDE); 3621cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 363a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey return new PackageInstallerSession(mInternalCallback, mContext, mPm, 364a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey mInstallThread.getLooper(), sessionId, userId, installerPackageName, params, 365742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey createdMillis, stageDir, stageCid, sealed); 3663a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 3673a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 3683a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private void writeSessionsLocked() { 3691cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (LOGD) Slog.v(TAG, "writeSessionsLocked()"); 3701cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 3711cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey FileOutputStream fos = null; 3721cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey try { 3731cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey fos = mSessionsFile.startWrite(); 3741cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 3751cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey XmlSerializer out = new FastXmlSerializer(); 3761cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey out.setOutput(fos, "utf-8"); 3771cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey out.startDocument(null, true); 3781cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey out.startTag(null, TAG_SESSIONS); 3791cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final int size = mSessions.size(); 3801cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey for (int i = 0; i < size; i++) { 3811cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final PackageInstallerSession session = mSessions.valueAt(i); 3821cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeSessionLocked(out, session); 3831cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 3841cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey out.endTag(null, TAG_SESSIONS); 3851cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey out.endDocument(); 3861cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 3871cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mSessionsFile.finishWrite(fos); 3881cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } catch (IOException e) { 3891cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (fos != null) { 3901cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mSessionsFile.failWrite(fos); 3911cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 3921cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 3931cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 3941cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 3951cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private void writeSessionLocked(XmlSerializer out, PackageInstallerSession session) 3961cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey throws IOException { 397a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey final SessionParams params = session.params; 3981cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 3991cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey out.startTag(null, TAG_SESSION); 4001cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 4011cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeIntAttribute(out, ATTR_SESSION_ID, session.sessionId); 4021cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeIntAttribute(out, ATTR_USER_ID, session.userId); 4031cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeStringAttribute(out, ATTR_INSTALLER_PACKAGE_NAME, 4041cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey session.installerPackageName); 4051cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeLongAttribute(out, ATTR_CREATED_MILLIS, session.createdMillis); 406941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey if (session.stageDir != null) { 407742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey writeStringAttribute(out, ATTR_SESSION_STAGE_DIR, 408941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey session.stageDir.getAbsolutePath()); 409742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 410941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey if (session.stageCid != null) { 411941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey writeStringAttribute(out, ATTR_SESSION_STAGE_CID, session.stageCid); 412742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 413742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey writeBooleanAttribute(out, ATTR_SEALED, session.isSealed()); 4141cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 4151cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeIntAttribute(out, ATTR_MODE, params.mode); 4161cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeIntAttribute(out, ATTR_INSTALL_FLAGS, params.installFlags); 4171cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeIntAttribute(out, ATTR_INSTALL_LOCATION, params.installLocation); 4181cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeLongAttribute(out, ATTR_SIZE_BYTES, params.sizeBytes); 4191cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeStringAttribute(out, ATTR_APP_PACKAGE_NAME, params.appPackageName); 4201cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeBitmapAttribute(out, ATTR_APP_ICON, params.appIcon); 4211cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeStringAttribute(out, ATTR_APP_LABEL, params.appLabel); 4221cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeUriAttribute(out, ATTR_ORIGINATING_URI, params.originatingUri); 4231cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeUriAttribute(out, ATTR_REFERRER_URI, params.referrerUri); 4241cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeStringAttribute(out, ATTR_ABI_OVERRIDE, params.abiOverride); 4251cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 4261cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey out.endTag(null, TAG_SESSION); 4273a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 4283a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 4293a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private void writeSessionsAsync() { 4303a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey IoThread.getHandler().post(new Runnable() { 4313a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey @Override 4323a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey public void run() { 4333a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey synchronized (mSessions) { 4343a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey writeSessionsLocked(); 4353a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 4363a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 4373a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey }); 4383a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 4393a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 4403a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey @Override 441a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey public int createSession(SessionParams params, String installerPackageName, int userId) { 442742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey try { 443742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey return createSessionInternal(params, installerPackageName, userId); 444742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } catch (IOException e) { 445742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey throw ExceptionUtils.wrap(e); 446742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 447742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 448742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 449742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey private int createSessionInternal(SessionParams params, String installerPackageName, int userId) 450742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey throws IOException { 4513a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey final int callingUid = Binder.getCallingUid(); 452a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey mPm.enforceCrossUserPermission(callingUid, userId, true, "createSession"); 4533a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 4543a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey if (mPm.isUserRestricted(UserHandle.getUserId(callingUid), 4553a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey UserManager.DISALLOW_INSTALL_APPS)) { 4563a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey throw new SecurityException("User restriction prevents installing"); 4573a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 4583a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 459381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey // TODO: double check all possible install flags 460381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey 4611cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) { 4621cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey installerPackageName = "com.android.shell"; 4631cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 4643a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey params.installFlags |= INSTALL_FROM_ADB; 4651cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 4663a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } else { 467ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey mAppOps.checkPackage(callingUid, installerPackageName); 468ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 4693a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey params.installFlags &= ~INSTALL_FROM_ADB; 4703a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey params.installFlags &= ~INSTALL_ALL_USERS; 4713a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey params.installFlags |= INSTALL_REPLACE_EXISTING; 4723a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 4733a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 4741cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey // Defensively resize giant app icons 4751cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (params.appIcon != null) { 4761cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final ActivityManager am = (ActivityManager) mContext.getSystemService( 4771cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey Context.ACTIVITY_SERVICE); 4781cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final int iconSize = am.getLauncherLargeIconSize(); 4791cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if ((params.appIcon.getWidth() > iconSize * 2) 4801cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey || (params.appIcon.getHeight() > iconSize * 2)) { 4811cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.appIcon = Bitmap.createScaledBitmap(params.appIcon, iconSize, iconSize, 4821cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey true); 4831cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 4841cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 4851cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 486941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey // TODO: treat INHERIT_EXISTING as install for user 487941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey 488742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey // Figure out where we're going to be staging session data 489742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final boolean stageInternal; 490742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 491742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey if (params.mode == SessionParams.MODE_FULL_INSTALL) { 492742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey // Brand new install, use best resolved location. This also verifies 493742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey // that target has enough free space for the install. 494e812d9096915ad165de125520ed7371009587d1fRobin Lee final long ident = Binder.clearCallingIdentity(); 495e812d9096915ad165de125520ed7371009587d1fRobin Lee try { 496e812d9096915ad165de125520ed7371009587d1fRobin Lee final int resolved = PackageHelper.resolveInstallLocation(mContext, 497e812d9096915ad165de125520ed7371009587d1fRobin Lee params.appPackageName, params.installLocation, params.sizeBytes, 498e812d9096915ad165de125520ed7371009587d1fRobin Lee params.installFlags); 499e812d9096915ad165de125520ed7371009587d1fRobin Lee 500e812d9096915ad165de125520ed7371009587d1fRobin Lee if (resolved == PackageHelper.RECOMMEND_INSTALL_INTERNAL) { 501e812d9096915ad165de125520ed7371009587d1fRobin Lee stageInternal = true; 502e812d9096915ad165de125520ed7371009587d1fRobin Lee } else if (resolved == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) { 503e812d9096915ad165de125520ed7371009587d1fRobin Lee stageInternal = false; 504e812d9096915ad165de125520ed7371009587d1fRobin Lee } else { 505e812d9096915ad165de125520ed7371009587d1fRobin Lee throw new IOException("No storage with enough free space; res=" + resolved); 506e812d9096915ad165de125520ed7371009587d1fRobin Lee } 507e812d9096915ad165de125520ed7371009587d1fRobin Lee } finally { 508e812d9096915ad165de125520ed7371009587d1fRobin Lee Binder.restoreCallingIdentity(ident); 509a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 510742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } else if (params.mode == SessionParams.MODE_INHERIT_EXISTING) { 511941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey // Inheriting existing install, so stay on the same storage medium. 512941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey final ApplicationInfo existingApp = mPm.getApplicationInfo(params.appPackageName, 0, 513742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey userId); 514941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey if (existingApp == null) { 515941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey throw new IllegalStateException( 516941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey "Missing existing app " + params.appPackageName); 517941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey } 518742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 519941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey final long existingSize; 520941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey try { 521941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey final PackageLite existingPkg = PackageParser.parsePackageLite( 522941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey new File(existingApp.getCodePath()), 0); 523941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey existingSize = PackageHelper.calculateInstalledSize(existingPkg, false, 524941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey params.abiOverride); 525941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey } catch (PackageParserException e) { 526941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey throw new IllegalStateException( 527941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey "Failed to calculate size of " + params.appPackageName); 528742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 529742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 530941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey if ((existingApp.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) == 0) { 531941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey // Internal we can link existing install into place, so we only 532941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey // need enough space for the new data. 533941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey checkInternalStorage(params.sizeBytes); 534941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey stageInternal = true; 535941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey } else { 536941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey // External we're going to copy existing install into our 537941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey // container, so we need footprint of both. 538941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey checkExternalStorage(params.sizeBytes + existingSize); 539941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey stageInternal = false; 540941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey } 541742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } else { 542742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey throw new IllegalArgumentException("Invalid install mode: " + params.mode); 543a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 544a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 545a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey final int sessionId; 546a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey final PackageInstallerSession session; 5473a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey synchronized (mSessions) { 5481cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey // Sanity check that installer isn't going crazy 549f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey final int activeCount = getSessionCount(mSessions, callingUid); 5501cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (activeCount >= MAX_ACTIVE_SESSIONS) { 551f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey throw new IllegalStateException( 552f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey "Too many active sessions for UID " + callingUid); 553f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey } 554f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey final int historicalCount = getSessionCount(mHistoricalSessions, callingUid); 555f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey if (historicalCount >= MAX_HISTORICAL_SESSIONS) { 556f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey throw new IllegalStateException( 557f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey "Too many historical sessions for UID " + callingUid); 5581cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 5591cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 560742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final long createdMillis = System.currentTimeMillis(); 561a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey sessionId = allocateSessionIdLocked(); 562a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 563742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey // We're staging to exactly one location 564742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey File stageDir = null; 565742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey String stageCid = null; 566742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey if (stageInternal) { 567742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey stageDir = prepareInternalStageDir(sessionId); 568742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } else { 569742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey stageCid = prepareExternalStageCid(sessionId, params.sizeBytes); 570742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 5713a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 572a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey session = new PackageInstallerSession(mInternalCallback, mContext, mPm, 5731cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mInstallThread.getLooper(), sessionId, userId, installerPackageName, params, 574742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey createdMillis, stageDir, stageCid, false); 5753a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey mSessions.put(sessionId, session); 5763a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 577a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 5781cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mCallbacks.notifySessionCreated(session.sessionId, session.userId); 579a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey writeSessionsAsync(); 580a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey return sessionId; 5813a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 5823a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 583381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey @Override 584381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey public void abandonSession(int sessionId) { 585381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey synchronized (mSessions) { 586381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey final PackageInstallerSession session = mSessions.get(sessionId); 587381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey if (session == null || !isCallingUidOwner(session)) { 588381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey throw new SecurityException("Caller has no access to session " + sessionId); 589381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey } 590381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey session.abandon(); 591381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey } 592381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey } 593381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey 594742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey private void checkInternalStorage(long sizeBytes) throws IOException { 595742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey if (sizeBytes <= 0) return; 596742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 597742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final File target = Environment.getDataDirectory(); 598742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final long targetBytes = sizeBytes + mStorage.getStorageLowBytes(target); 599742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 600742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey mPm.freeStorage(targetBytes); 601742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey if (target.getUsableSpace() < targetBytes) { 602742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey throw new IOException("Not enough internal space to write " + sizeBytes + " bytes"); 603742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 604742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 605742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 606742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey private void checkExternalStorage(long sizeBytes) throws IOException { 607742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey if (sizeBytes <= 0) return; 608742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 609bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey final File target = new UserEnvironment(UserHandle.USER_OWNER) 610bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey .getExternalStorageDirectory(); 611742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final long targetBytes = sizeBytes + mStorage.getStorageLowBytes(target); 612742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 613742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey if (target.getUsableSpace() < targetBytes) { 614742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey throw new IOException("Not enough external space to write " + sizeBytes + " bytes"); 615742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 616742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 617742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 6183a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey @Override 6193a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey public IPackageInstallerSession openSession(int sessionId) { 6203a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey synchronized (mSessions) { 6213a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey final PackageInstallerSession session = mSessions.get(sessionId); 622381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey if (session == null || !isCallingUidOwner(session)) { 6233a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey throw new SecurityException("Caller has no access to session " + sessionId); 6243a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 625742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey session.open(); 6263a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey return session; 6273a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 6283a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 6293a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 6303a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private int allocateSessionIdLocked() { 6311cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey int n = 0; 6321cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey int sessionId; 6331cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey do { 634f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey sessionId = mRandom.nextInt(Integer.MAX_VALUE - 1) + 1; 635742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey if (mSessions.get(sessionId) == null && mHistoricalSessions.get(sessionId) == null 636742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey && !mLegacySessions.get(sessionId, false)) { 6371cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey return sessionId; 6381cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 6391cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } while (n++ < 32); 6401cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 6411cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey throw new IllegalStateException("Failed to allocate session ID"); 6423a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 6433a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 644742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey private File prepareInternalStageDir(int sessionId) throws IOException { 645ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey final File file = new File(mStagingDir, "vmdl" + sessionId + ".tmp"); 646ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 647ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey if (file.exists()) { 648742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey throw new IOException("Session dir already exists: " + file); 649ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 650ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 651ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey try { 652ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey Os.mkdir(file.getAbsolutePath(), 0755); 653ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey Os.chmod(file.getAbsolutePath(), 0755); 654ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } catch (ErrnoException e) { 655ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey // This purposefully throws if directory already exists 656742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey throw new IOException("Failed to prepare session dir", e); 657ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 658ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 659ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey if (!SELinux.restorecon(file)) { 660742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey throw new IOException("Failed to restorecon session dir"); 661ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 662ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 663ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey return file; 664ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 665ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 666742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey private String prepareExternalStageCid(int sessionId, long sizeBytes) throws IOException { 667742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey if (sizeBytes <= 0) { 668742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey throw new IOException("Session must provide valid size for ASEC"); 669742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 670742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 671742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final String cid = "smdl" + sessionId + ".tmp"; 672941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey if (PackageHelper.createSdDir(sizeBytes, cid, PackageManagerService.getEncryptKey(), 673742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey Process.SYSTEM_UID, true) == null) { 674742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey throw new IOException("Failed to create ASEC"); 675742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 676742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 677742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey return cid; 678742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 679742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 6803a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey @Override 681a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey public SessionInfo getSessionInfo(int sessionId) { 68216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey synchronized (mSessions) { 68316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey final PackageInstallerSession session = mSessions.get(sessionId); 6841cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (!isCallingUidOwner(session)) { 68516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey enforceCallerCanReadSessions(); 68616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 68716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey return session != null ? session.generateInfo() : null; 68816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 68916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 69016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey 69116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey @Override 692a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey public List<SessionInfo> getAllSessions(int userId) { 69316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "getAllSessions"); 69416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey enforceCallerCanReadSessions(); 6953a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 696a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey final List<SessionInfo> result = new ArrayList<>(); 6973a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey synchronized (mSessions) { 6983a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey for (int i = 0; i < mSessions.size(); i++) { 6993a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey final PackageInstallerSession session = mSessions.valueAt(i); 700bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey if (session.userId == userId) { 701bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey result.add(session.generateInfo()); 7023a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 7033a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 7043a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 705bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey return result; 7063a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 7073a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 7083a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey @Override 709a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey public List<SessionInfo> getMySessions(String installerPackageName, int userId) { 71016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "getMySessions"); 71116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey mAppOps.checkPackage(Binder.getCallingUid(), installerPackageName); 71216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey 713a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey final List<SessionInfo> result = new ArrayList<>(); 71416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey synchronized (mSessions) { 71516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey for (int i = 0; i < mSessions.size(); i++) { 71616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey final PackageInstallerSession session = mSessions.valueAt(i); 71716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey if (Objects.equals(session.installerPackageName, installerPackageName) 71816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey && session.userId == userId) { 71916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey result.add(session.generateInfo()); 72016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 72116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 72216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 72316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey return result; 72416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 72516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey 72616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey @Override 727a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey public void uninstall(String packageName, int flags, IntentSender statusReceiver, int userId) { 728a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "uninstall"); 72916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey 730a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext, 731bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey statusReceiver, packageName); 732f06009542390472872da986486d385001e91a2a7Jeff Sharkey if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES) 733f06009542390472872da986486d385001e91a2a7Jeff Sharkey == PackageManager.PERMISSION_GRANTED) { 734f06009542390472872da986486d385001e91a2a7Jeff Sharkey // Sweet, call straight through! 735a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey mPm.deletePackage(packageName, adapter.getBinder(), userId, flags); 736f06009542390472872da986486d385001e91a2a7Jeff Sharkey 737f06009542390472872da986486d385001e91a2a7Jeff Sharkey } else { 738f06009542390472872da986486d385001e91a2a7Jeff Sharkey // Take a short detour to confirm with user 739f06009542390472872da986486d385001e91a2a7Jeff Sharkey final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE); 740f06009542390472872da986486d385001e91a2a7Jeff Sharkey intent.setData(Uri.fromParts("package", packageName, null)); 741a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey intent.putExtra(PackageInstaller.EXTRA_CALLBACK, adapter.getBinder().asBinder()); 742a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey adapter.onUserActionRequired(intent); 743f06009542390472872da986486d385001e91a2a7Jeff Sharkey } 7443a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 7453a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 7463a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey @Override 7477328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey public void setPermissionsResult(int sessionId, boolean accepted) { 7487328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, TAG); 7497328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey 7507328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey synchronized (mSessions) { 7517328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey mSessions.get(sessionId).setPermissionsResult(accepted); 7527328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey } 7537328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey } 7547328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey 7557328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey @Override 75616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public void registerCallback(IPackageInstallerCallback callback, int userId) { 75716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "registerCallback"); 75816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey enforceCallerCanReadSessions(); 759a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 7601cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mCallbacks.register(callback, userId); 761bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey } 762bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey 763bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey @Override 76416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public void unregisterCallback(IPackageInstallerCallback callback) { 76516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey mCallbacks.unregister(callback); 766a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 767a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 768f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey private static int getSessionCount(SparseArray<PackageInstallerSession> sessions, 769f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey int installerUid) { 7701cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey int count = 0; 771f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey final int size = sessions.size(); 7721cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey for (int i = 0; i < size; i++) { 773f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey final PackageInstallerSession session = sessions.valueAt(i); 7741cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (session.installerUid == installerUid) { 7751cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey count++; 7761cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 7771cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 7781cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey return count; 7791cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 7801cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 7811cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private boolean isCallingUidOwner(PackageInstallerSession session) { 7821cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final int callingUid = Binder.getCallingUid(); 7831cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (callingUid == Process.ROOT_UID) { 7841cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey return true; 7851cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } else { 7861cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey return (session != null) && (callingUid == session.installerUid); 787a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 788a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 789a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 79016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey /** 79116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * We allow those with permission, or the current home app. 79216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey */ 79316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey private void enforceCallerCanReadSessions() { 79416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey final boolean hasPermission = (mContext.checkCallingOrSelfPermission( 79516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey android.Manifest.permission.READ_INSTALL_SESSIONS) 79616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey == PackageManager.PERMISSION_GRANTED); 79716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey final boolean isHomeApp = mPm.checkCallerIsHomeApp(); 79816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey if (hasPermission || isHomeApp) { 79916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey return; 80016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } else { 80116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey throw new SecurityException("Caller must be current home app to read install sessions"); 80216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 80316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 80416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey 805a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey static class PackageDeleteObserverAdapter extends PackageDeleteObserver { 806a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey private final Context mContext; 807a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey private final IntentSender mTarget; 808bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey private final String mPackageName; 809a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey 810bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey public PackageDeleteObserverAdapter(Context context, IntentSender target, 811bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey String packageName) { 812a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey mContext = context; 813a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey mTarget = target; 814bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey mPackageName = packageName; 815a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 816a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey 817a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey @Override 818a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey public void onUserActionRequired(Intent intent) { 819a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey final Intent fillIn = new Intent(); 820bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName); 821a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_STATUS, 822742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey PackageInstaller.STATUS_PENDING_USER_ACTION); 823a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey fillIn.putExtra(Intent.EXTRA_INTENT, intent); 824a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey try { 825a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey mTarget.sendIntent(mContext, 0, fillIn, null, null); 826a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } catch (SendIntentException ignored) { 827a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 828a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 829a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey 830a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey @Override 831a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey public void onPackageDeleted(String basePackageName, int returnCode, String msg) { 832a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey final Intent fillIn = new Intent(); 833bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName); 834a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_STATUS, 835a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey PackageManager.deleteStatusToPublicStatus(returnCode)); 836a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, 837a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey PackageManager.deleteStatusToString(returnCode, msg)); 838a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode); 839a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey try { 840a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey mTarget.sendIntent(mContext, 0, fillIn, null, null); 841a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } catch (SendIntentException ignored) { 842a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 843a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 844a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 845a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey 846a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey static class PackageInstallObserverAdapter extends PackageInstallObserver { 847a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey private final Context mContext; 848a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey private final IntentSender mTarget; 849bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey private final int mSessionId; 850a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey 851bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey public PackageInstallObserverAdapter(Context context, IntentSender target, int sessionId) { 852a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey mContext = context; 853a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey mTarget = target; 854bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey mSessionId = sessionId; 855a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 856a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey 857a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey @Override 858a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey public void onUserActionRequired(Intent intent) { 859a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey final Intent fillIn = new Intent(); 860bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId); 861a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_STATUS, 862742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey PackageInstaller.STATUS_PENDING_USER_ACTION); 863a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey fillIn.putExtra(Intent.EXTRA_INTENT, intent); 864a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey try { 865a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey mTarget.sendIntent(mContext, 0, fillIn, null, null); 866a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } catch (SendIntentException ignored) { 867a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 868a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 869a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey 870a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey @Override 871a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey public void onPackageInstalled(String basePackageName, int returnCode, String msg, 872a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey Bundle extras) { 873a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey final Intent fillIn = new Intent(); 874bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId); 875a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_STATUS, 876a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey PackageManager.installStatusToPublicStatus(returnCode)); 877a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, 878a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey PackageManager.installStatusToString(returnCode, msg)); 879a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode); 880a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey if (extras != null) { 881a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey final String existing = extras.getString( 882a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE); 883a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey if (!TextUtils.isEmpty(existing)) { 884941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_OTHER_PACKAGE_NAME, existing); 885a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 886a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 887a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey try { 888a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey mTarget.sendIntent(mContext, 0, fillIn, null, null); 889a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } catch (SendIntentException ignored) { 890a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 891a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 892a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 893a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey 8941cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static class Callbacks extends Handler { 8951cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final int MSG_SESSION_CREATED = 1; 8961cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final int MSG_SESSION_OPENED = 2; 8971cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final int MSG_SESSION_PROGRESS_CHANGED = 3; 8981cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final int MSG_SESSION_CLOSED = 4; 8991cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final int MSG_SESSION_FINISHED = 5; 9001cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 9011cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private final RemoteCallbackList<IPackageInstallerCallback> 9021cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mCallbacks = new RemoteCallbackList<>(); 9031cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 9041cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey public Callbacks(Looper looper) { 9051cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey super(looper); 906a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 907a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 9081cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey public void register(IPackageInstallerCallback callback, int userId) { 9091cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mCallbacks.register(callback, new UserHandle(userId)); 9101cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 9111cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 9121cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey public void unregister(IPackageInstallerCallback callback) { 9131cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mCallbacks.unregister(callback); 9141cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 9151cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 9161cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey @Override 9171cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey public void handleMessage(Message msg) { 9181cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final int userId = msg.arg2; 9191cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final int n = mCallbacks.beginBroadcast(); 9201cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey for (int i = 0; i < n; i++) { 9211cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final IPackageInstallerCallback callback = mCallbacks.getBroadcastItem(i); 9221cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final UserHandle user = (UserHandle) mCallbacks.getBroadcastCookie(i); 9231cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey // TODO: dispatch notifications for slave profiles 9241cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (userId == user.getIdentifier()) { 9251cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey try { 9261cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey invokeCallback(callback, msg); 9271cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } catch (RemoteException ignored) { 9281cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 929a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 930a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 9311cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mCallbacks.finishBroadcast(); 932a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 933a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 9341cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private void invokeCallback(IPackageInstallerCallback callback, Message msg) 9351cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey throws RemoteException { 9361cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final int sessionId = msg.arg1; 9371cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey switch (msg.what) { 9381cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey case MSG_SESSION_CREATED: 9391cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey callback.onSessionCreated(sessionId); 9401cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey break; 9411cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey case MSG_SESSION_OPENED: 9421cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey callback.onSessionOpened(sessionId); 9431cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey break; 9441cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey case MSG_SESSION_PROGRESS_CHANGED: 9451cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey callback.onSessionProgressChanged(sessionId, (float) msg.obj); 9461cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey break; 9471cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey case MSG_SESSION_CLOSED: 9481cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey callback.onSessionClosed(sessionId); 9491cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey break; 9501cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey case MSG_SESSION_FINISHED: 9511cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey callback.onSessionFinished(sessionId, (boolean) msg.obj); 9521cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey break; 953a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 954a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 9551cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 9561cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private void notifySessionCreated(int sessionId, int userId) { 9571cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey obtainMessage(MSG_SESSION_CREATED, sessionId, userId).sendToTarget(); 9581cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 9591cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 9601cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private void notifySessionOpened(int sessionId, int userId) { 9611cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey obtainMessage(MSG_SESSION_OPENED, sessionId, userId).sendToTarget(); 9621cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 9631cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 9641cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private void notifySessionProgressChanged(int sessionId, int userId, float progress) { 9651cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey obtainMessage(MSG_SESSION_PROGRESS_CHANGED, sessionId, userId, progress).sendToTarget(); 9661cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 9671cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 9681cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private void notifySessionClosed(int sessionId, int userId) { 9691cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey obtainMessage(MSG_SESSION_CLOSED, sessionId, userId).sendToTarget(); 9701cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 9711cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 9721cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey public void notifySessionFinished(int sessionId, int userId, boolean success) { 9731cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey obtainMessage(MSG_SESSION_FINISHED, sessionId, userId, success).sendToTarget(); 9741cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 975a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 976a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 977a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey void dump(IndentingPrintWriter pw) { 978a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey synchronized (mSessions) { 9799a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.println("Active install sessions:"); 9809a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.increaseIndent(); 9819a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey int N = mSessions.size(); 982a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey for (int i = 0; i < N; i++) { 983a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey final PackageInstallerSession session = mSessions.valueAt(i); 984a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey session.dump(pw); 985a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey pw.println(); 986a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 9879a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.println(); 9889a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.decreaseIndent(); 9899a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey 9909a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.println("Historical install sessions:"); 9919a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.increaseIndent(); 9929a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey N = mHistoricalSessions.size(); 9939a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey for (int i = 0; i < N; i++) { 9949a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey final PackageInstallerSession session = mHistoricalSessions.valueAt(i); 9959a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey session.dump(pw); 9969a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.println(); 9979a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey } 9989a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.println(); 9999a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.decreaseIndent(); 1000742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 1001742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey pw.println("Legacy install sessions:"); 1002742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey pw.increaseIndent(); 1003742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey pw.println(mLegacySessions.toString()); 1004742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey pw.decreaseIndent(); 1005a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 1006bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey } 1007bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey 10081cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey class InternalCallback { 100916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public void onSessionProgressChanged(PackageInstallerSession session, float progress) { 10101cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mCallbacks.notifySessionProgressChanged(session.sessionId, session.userId, progress); 10111cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 10121cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 1013742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey public void onSessionOpened(PackageInstallerSession session) { 1014742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey mCallbacks.notifySessionOpened(session.sessionId, session.userId); 1015742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 1016742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 10171cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey public void onSessionClosed(PackageInstallerSession session) { 10181cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mCallbacks.notifySessionClosed(session.sessionId, session.userId); 10193a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 10203a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1021a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey public void onSessionFinished(PackageInstallerSession session, boolean success) { 10221cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mCallbacks.notifySessionFinished(session.sessionId, session.userId, success); 1023a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey synchronized (mSessions) { 1024a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey mSessions.remove(session.sessionId); 10259a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey mHistoricalSessions.put(session.sessionId, session); 1026a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 10273a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey writeSessionsAsync(); 10283a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 1029bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey 1030bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey public void onSessionSealed(PackageInstallerSession session) { 1031bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey // It's very important that we block until we've recorded the 1032bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey // session as being sealed, since we never want to allow mutation 1033bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey // after sealing. 1034bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey writeSessionsLocked(); 1035bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey } 10363a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 10373a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey} 1038