PackageInstallerService.java revision bb7b7bea19223c1eba74f525c7fe87ca3911813b
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; 22742e790294b3441b79f715fe447069b63c6065dbJeff Sharkeyimport static android.net.TrafficStats.MB_IN_BYTES; 231cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.readBitmapAttribute; 241cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.readBooleanAttribute; 251cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.readIntAttribute; 261cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.readLongAttribute; 271cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.readStringAttribute; 281cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.readUriAttribute; 291cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.writeBitmapAttribute; 301cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.writeBooleanAttribute; 311cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.writeIntAttribute; 321cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.writeLongAttribute; 331cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.writeStringAttribute; 341cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.writeUriAttribute; 351cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; 361cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static org.xmlpull.v1.XmlPullParser.START_TAG; 371cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 381cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.app.ActivityManager; 393a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.app.AppOpsManager; 40a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.app.PackageDeleteObserver; 41a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.app.PackageInstallObserver; 423a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.content.Context; 43f06009542390472872da986486d385001e91a2a7Jeff Sharkeyimport android.content.Intent; 44a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.content.IntentSender; 45a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.content.IntentSender.SendIntentException; 46742e790294b3441b79f715fe447069b63c6065dbJeff Sharkeyimport android.content.pm.ApplicationInfo; 473a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.content.pm.IPackageInstaller; 4816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkeyimport android.content.pm.IPackageInstallerCallback; 493a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.content.pm.IPackageInstallerSession; 50f06009542390472872da986486d385001e91a2a7Jeff Sharkeyimport android.content.pm.PackageInstaller; 51a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.content.pm.PackageInstaller.SessionInfo; 52a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.content.pm.PackageInstaller.SessionParams; 5316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkeyimport android.content.pm.PackageManager; 541cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.graphics.Bitmap; 55f06009542390472872da986486d385001e91a2a7Jeff Sharkeyimport android.net.Uri; 563a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.Binder; 57a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.os.Bundle; 581cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.os.Environment; 59bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkeyimport android.os.Environment.UserEnvironment; 603a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.FileUtils; 611cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.os.Handler; 623a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.HandlerThread; 631cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.os.Looper; 641cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.os.Message; 653a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.Process; 66a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkeyimport android.os.RemoteCallbackList; 67a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkeyimport android.os.RemoteException; 68ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport android.os.SELinux; 693a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.UserHandle; 703a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.UserManager; 71742e790294b3441b79f715fe447069b63c6065dbJeff Sharkeyimport android.os.storage.StorageManager; 72ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport android.system.ErrnoException; 73ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport android.system.Os; 74a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.text.TextUtils; 751cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.text.format.DateUtils; 763a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.util.ArraySet; 771cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.util.AtomicFile; 78a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkeyimport android.util.ExceptionUtils; 791cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.util.Log; 803a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.util.Slog; 813a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.util.SparseArray; 82742e790294b3441b79f715fe447069b63c6065dbJeff Sharkeyimport android.util.SparseBooleanArray; 831cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.util.Xml; 843a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 853a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport com.android.internal.annotations.GuardedBy; 86742e790294b3441b79f715fe447069b63c6065dbJeff Sharkeyimport com.android.internal.content.PackageHelper; 871cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport com.android.internal.util.FastXmlSerializer; 88a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkeyimport com.android.internal.util.IndentingPrintWriter; 893a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport com.android.server.IoThread; 903a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport com.google.android.collect.Sets; 913a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 921cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport libcore.io.IoUtils; 931cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 941cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport org.xmlpull.v1.XmlPullParser; 951cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport org.xmlpull.v1.XmlPullParserException; 961cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport org.xmlpull.v1.XmlSerializer; 971cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 983a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport java.io.File; 991cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport java.io.FileInputStream; 1001cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport java.io.FileNotFoundException; 1011cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport java.io.FileOutputStream; 102ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport java.io.FilenameFilter; 103ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport java.io.IOException; 1041cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport java.security.SecureRandom; 105bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkeyimport java.util.ArrayList; 106bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkeyimport java.util.List; 10716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkeyimport java.util.Objects; 1081cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport java.util.Random; 1093a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1103a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeypublic class PackageInstallerService extends IPackageInstaller.Stub { 1113a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private static final String TAG = "PackageInstaller"; 1121cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final boolean LOGD = true; 1133a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1143a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey // TODO: remove outstanding sessions when installer package goes away 1156c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey // TODO: notify listeners in other users when package has been installed there 116742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey // TODO: purge expired sessions periodically in addition to at reboot 1173a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1181cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey /** XML constants used in {@link #mSessionsFile} */ 1191cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String TAG_SESSIONS = "sessions"; 1201cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String TAG_SESSION = "session"; 1211cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_SESSION_ID = "sessionId"; 1221cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_USER_ID = "userId"; 1231cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_INSTALLER_PACKAGE_NAME = "installerPackageName"; 1241cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_CREATED_MILLIS = "createdMillis"; 1251cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_SESSION_STAGE_DIR = "sessionStageDir"; 126742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey private static final String ATTR_SESSION_STAGE_CID = "sessionStageCid"; 1271cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_SEALED = "sealed"; 1281cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_MODE = "mode"; 1291cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_INSTALL_FLAGS = "installFlags"; 1301cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_INSTALL_LOCATION = "installLocation"; 1311cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_SIZE_BYTES = "sizeBytes"; 1321cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_APP_PACKAGE_NAME = "appPackageName"; 1331cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_APP_ICON = "appIcon"; 1341cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_APP_LABEL = "appLabel"; 1351cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_ORIGINATING_URI = "originatingUri"; 1361cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_REFERRER_URI = "referrerUri"; 1371cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_ABI_OVERRIDE = "abiOverride"; 1381cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 139f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey /** Automatically destroy sessions older than this */ 1401cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final long MAX_AGE_MILLIS = 3 * DateUtils.DAY_IN_MILLIS; 141f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey /** Upper bound on number of active sessions for a UID */ 1421cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final long MAX_ACTIVE_SESSIONS = 1024; 143f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey /** Upper bound on number of historical sessions for a UID */ 144f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey private static final long MAX_HISTORICAL_SESSIONS = 1048576; 1451cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 1463a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private final Context mContext; 1473a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private final PackageManagerService mPm; 1483a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private final AppOpsManager mAppOps; 149742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey private final StorageManager mStorage; 1503a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1513a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private final File mStagingDir; 152ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey private final HandlerThread mInstallThread; 1533a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1541cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private final Callbacks mCallbacks; 1551cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 1561cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey /** 1571cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * File storing persisted {@link #mSessions}. 1581cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey */ 1591cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private final AtomicFile mSessionsFile; 1601cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 1611cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private final InternalCallback mInternalCallback = new InternalCallback(); 1621cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 1631cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey /** 1641cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * Used for generating session IDs. Since this is created at boot time, 1651cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * normal random might be predictable. 1661cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey */ 1671cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private final Random mRandom = new SecureRandom(); 1683a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1693a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey @GuardedBy("mSessions") 1703a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>(); 1713a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1729a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey /** Historical sessions kept around for debugging purposes */ 1739a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey @GuardedBy("mSessions") 1749a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey private final SparseArray<PackageInstallerSession> mHistoricalSessions = new SparseArray<>(); 1759a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey 176742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey /** Sessions allocated to legacy users */ 177742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey @GuardedBy("mSessions") 178742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey private final SparseBooleanArray mLegacySessions = new SparseBooleanArray(); 179742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 180ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey private static final FilenameFilter sStageFilter = new FilenameFilter() { 181ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey @Override 182ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey public boolean accept(File dir, String name) { 183742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey return isStageName(name); 184ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 185ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey }; 186ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 1873a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey public PackageInstallerService(Context context, PackageManagerService pm, File stagingDir) { 1883a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey mContext = context; 1893a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey mPm = pm; 1903a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); 191742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey mStorage = StorageManager.from(mContext); 1923a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1933a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey mStagingDir = stagingDir; 194ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 195ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey mInstallThread = new HandlerThread(TAG); 196ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey mInstallThread.start(); 1973a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1981cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mCallbacks = new Callbacks(mInstallThread.getLooper()); 1991cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 2001cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mSessionsFile = new AtomicFile( 2011cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey new File(Environment.getSystemSecureDirectory(), "install_sessions.xml")); 2021cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 2033a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey synchronized (mSessions) { 2043a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey readSessionsLocked(); 2053a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 206742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final ArraySet<File> unclaimed = Sets.newArraySet(mStagingDir.listFiles(sStageFilter)); 207742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 208742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey // Ignore stages claimed by active sessions 2093a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey for (int i = 0; i < mSessions.size(); i++) { 210ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey final PackageInstallerSession session = mSessions.valueAt(i); 211742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey unclaimed.remove(session.internalStageDir); 212ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 213742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 214742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey // Clean up orphaned staging directories 215742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey for (File stage : unclaimed) { 216ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey Slog.w(TAG, "Deleting orphan stage " + stage); 217ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey if (stage.isDirectory()) { 218ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey FileUtils.deleteContents(stage); 219ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 220ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey stage.delete(); 2213a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 222ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 223ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 224ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 225742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey public void onSecureContainersAvailable() { 226742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey synchronized (mSessions) { 227742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final ArraySet<String> unclaimed = new ArraySet<>(); 228742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey for (String cid : PackageHelper.getSecureContainerList()) { 229742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey if (isStageName(cid)) { 230742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey unclaimed.add(cid); 231742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 232742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 233742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 234742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey // Ignore stages claimed by active sessions 235742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey for (int i = 0; i < mSessions.size(); i++) { 236742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final PackageInstallerSession session = mSessions.valueAt(i); 237742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final String cid = session.externalStageCid; 238742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 239742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey if (unclaimed.remove(cid)) { 240742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey // Claimed by active session, mount it 241742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey PackageHelper.mountSdDir(cid, PackageManagerService.getEncryptKey(), 242742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey Process.SYSTEM_UID); 243742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 244742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 245742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 246742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey // Clean up orphaned staging containers 247742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey for (String cid : unclaimed) { 248742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey Slog.w(TAG, "Deleting orphan container " + cid); 249742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey PackageHelper.destroySdDir(cid); 250742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 251742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 252742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 253742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 254742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey public static boolean isStageName(String name) { 255742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final boolean isFile = name.startsWith("vmdl") && name.endsWith(".tmp"); 256742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final boolean isContainer = name.startsWith("smdl") && name.endsWith(".tmp"); 257742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final boolean isLegacyContainer = name.startsWith("smdl2tmp"); 258742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey return isFile || isContainer || isLegacyContainer; 2597328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey } 2607328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey 261ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey @Deprecated 262742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey public File allocateInternalStageDirLegacy() throws IOException { 263ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey synchronized (mSessions) { 264ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey try { 265ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey final int sessionId = allocateSessionIdLocked(); 266742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey mLegacySessions.put(sessionId, true); 267742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey return prepareInternalStageDir(sessionId); 268ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } catch (IllegalStateException e) { 269ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey throw new IOException(e); 2703a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 2713a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 2723a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 2733a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 274742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey @Deprecated 275742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey public String allocateExternalStageCidLegacy() { 276742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey synchronized (mSessions) { 277742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final int sessionId = allocateSessionIdLocked(); 278742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey mLegacySessions.put(sessionId, true); 279742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey return "smdl" + sessionId + ".tmp"; 280742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 281742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 282742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 2833a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private void readSessionsLocked() { 2841cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (LOGD) Slog.v(TAG, "readSessionsLocked()"); 2851cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 2863a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey mSessions.clear(); 2871cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 2881cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey FileInputStream fis = null; 2891cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey try { 2901cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey fis = mSessionsFile.openRead(); 2911cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final XmlPullParser in = Xml.newPullParser(); 2921cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey in.setInput(fis, null); 2931cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 2941cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey int type; 2951cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey while ((type = in.next()) != END_DOCUMENT) { 2961cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (type == START_TAG) { 2971cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final String tag = in.getName(); 2981cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (TAG_SESSION.equals(tag)) { 2991cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final PackageInstallerSession session = readSessionLocked(in); 3001cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final long age = System.currentTimeMillis() - session.createdMillis; 3011cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 3021cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final boolean valid; 3031cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (age >= MAX_AGE_MILLIS) { 3041cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey Slog.w(TAG, "Abandoning old session first created at " 3051cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey + session.createdMillis); 3061cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey valid = false; 307742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } else if (session.internalStageDir != null 308742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey && !session.internalStageDir.exists()) { 309742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey Slog.w(TAG, "Abandoning internal session with missing stage " 310742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey + session.internalStageDir); 3111cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey valid = false; 3121cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } else { 3131cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey valid = true; 3141cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 3151cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 3161cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (valid) { 3171cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mSessions.put(session.sessionId, session); 3181cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } else { 3191cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey // Since this is early during boot we don't send 3201cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey // any observer events about the session, but we 3211cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey // keep details around for dumpsys. 3221cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mHistoricalSessions.put(session.sessionId, session); 3231cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 3241cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 3251cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 3261cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 3271cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } catch (FileNotFoundException e) { 3281cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey // Missing sessions are okay, probably first boot 3291cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } catch (IOException e) { 3301cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey Log.wtf(TAG, "Failed reading install sessions", e); 3311cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } catch (XmlPullParserException e) { 3321cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey Log.wtf(TAG, "Failed reading install sessions", e); 3331cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } finally { 3341cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey IoUtils.closeQuietly(fis); 3351cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 3361cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 3371cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 3381cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private PackageInstallerSession readSessionLocked(XmlPullParser in) throws IOException { 3391cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final int sessionId = readIntAttribute(in, ATTR_SESSION_ID); 3401cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final int userId = readIntAttribute(in, ATTR_USER_ID); 3411cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final String installerPackageName = readStringAttribute(in, ATTR_INSTALLER_PACKAGE_NAME); 3421cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final long createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS); 343742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final String stageDirRaw = readStringAttribute(in, ATTR_SESSION_STAGE_DIR); 344742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final File stageDir = (stageDirRaw != null) ? new File(stageDirRaw) : null; 345742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final String stageCid = readStringAttribute(in, ATTR_SESSION_STAGE_CID); 3461cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final boolean sealed = readBooleanAttribute(in, ATTR_SEALED); 3471cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 348a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey final SessionParams params = new SessionParams( 349a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey SessionParams.MODE_INVALID); 3501cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.mode = readIntAttribute(in, ATTR_MODE); 3511cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.installFlags = readIntAttribute(in, ATTR_INSTALL_FLAGS); 3521cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.installLocation = readIntAttribute(in, ATTR_INSTALL_LOCATION); 3531cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.sizeBytes = readLongAttribute(in, ATTR_SIZE_BYTES); 3541cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.appPackageName = readStringAttribute(in, ATTR_APP_PACKAGE_NAME); 3551cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.appIcon = readBitmapAttribute(in, ATTR_APP_ICON); 3561cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.appLabel = readStringAttribute(in, ATTR_APP_LABEL); 3571cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.originatingUri = readUriAttribute(in, ATTR_ORIGINATING_URI); 3581cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.referrerUri = readUriAttribute(in, ATTR_REFERRER_URI); 3591cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.abiOverride = readStringAttribute(in, ATTR_ABI_OVERRIDE); 3601cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 361a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey return new PackageInstallerSession(mInternalCallback, mContext, mPm, 362a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey mInstallThread.getLooper(), sessionId, userId, installerPackageName, params, 363742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey createdMillis, stageDir, stageCid, sealed); 3643a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 3653a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 3663a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private void writeSessionsLocked() { 3671cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (LOGD) Slog.v(TAG, "writeSessionsLocked()"); 3681cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 3691cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey FileOutputStream fos = null; 3701cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey try { 3711cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey fos = mSessionsFile.startWrite(); 3721cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 3731cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey XmlSerializer out = new FastXmlSerializer(); 3741cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey out.setOutput(fos, "utf-8"); 3751cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey out.startDocument(null, true); 3761cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey out.startTag(null, TAG_SESSIONS); 3771cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final int size = mSessions.size(); 3781cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey for (int i = 0; i < size; i++) { 3791cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final PackageInstallerSession session = mSessions.valueAt(i); 3801cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeSessionLocked(out, session); 3811cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 3821cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey out.endTag(null, TAG_SESSIONS); 3831cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey out.endDocument(); 3841cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 3851cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mSessionsFile.finishWrite(fos); 3861cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } catch (IOException e) { 3871cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (fos != null) { 3881cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mSessionsFile.failWrite(fos); 3891cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 3901cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 3911cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 3921cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 3931cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private void writeSessionLocked(XmlSerializer out, PackageInstallerSession session) 3941cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey throws IOException { 395a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey final SessionParams params = session.params; 3961cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 3971cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey out.startTag(null, TAG_SESSION); 3981cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 3991cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeIntAttribute(out, ATTR_SESSION_ID, session.sessionId); 4001cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeIntAttribute(out, ATTR_USER_ID, session.userId); 4011cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeStringAttribute(out, ATTR_INSTALLER_PACKAGE_NAME, 4021cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey session.installerPackageName); 4031cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeLongAttribute(out, ATTR_CREATED_MILLIS, session.createdMillis); 404742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey if (session.internalStageDir != null) { 405742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey writeStringAttribute(out, ATTR_SESSION_STAGE_DIR, 406742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey session.internalStageDir.getAbsolutePath()); 407742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 408742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey if (session.externalStageCid != null) { 409742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey writeStringAttribute(out, ATTR_SESSION_STAGE_CID, session.externalStageCid); 410742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 411742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey writeBooleanAttribute(out, ATTR_SEALED, session.isSealed()); 4121cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 4131cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeIntAttribute(out, ATTR_MODE, params.mode); 4141cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeIntAttribute(out, ATTR_INSTALL_FLAGS, params.installFlags); 4151cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeIntAttribute(out, ATTR_INSTALL_LOCATION, params.installLocation); 4161cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeLongAttribute(out, ATTR_SIZE_BYTES, params.sizeBytes); 4171cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeStringAttribute(out, ATTR_APP_PACKAGE_NAME, params.appPackageName); 4181cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeBitmapAttribute(out, ATTR_APP_ICON, params.appIcon); 4191cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeStringAttribute(out, ATTR_APP_LABEL, params.appLabel); 4201cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeUriAttribute(out, ATTR_ORIGINATING_URI, params.originatingUri); 4211cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeUriAttribute(out, ATTR_REFERRER_URI, params.referrerUri); 4221cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeStringAttribute(out, ATTR_ABI_OVERRIDE, params.abiOverride); 4231cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 4241cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey out.endTag(null, TAG_SESSION); 4253a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 4263a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 4273a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private void writeSessionsAsync() { 4283a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey IoThread.getHandler().post(new Runnable() { 4293a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey @Override 4303a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey public void run() { 4313a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey synchronized (mSessions) { 4323a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey writeSessionsLocked(); 4333a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 4343a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 4353a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey }); 4363a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 4373a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 4383a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey @Override 439a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey public int createSession(SessionParams params, String installerPackageName, int userId) { 440742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey try { 441742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey return createSessionInternal(params, installerPackageName, userId); 442742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } catch (IOException e) { 443742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey throw ExceptionUtils.wrap(e); 444742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 445742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 446742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 447742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey private int createSessionInternal(SessionParams params, String installerPackageName, int userId) 448742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey throws IOException { 4493a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey final int callingUid = Binder.getCallingUid(); 450a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey mPm.enforceCrossUserPermission(callingUid, userId, true, "createSession"); 4513a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 4523a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey if (mPm.isUserRestricted(UserHandle.getUserId(callingUid), 4533a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey UserManager.DISALLOW_INSTALL_APPS)) { 4543a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey throw new SecurityException("User restriction prevents installing"); 4553a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 4563a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 4571cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) { 4581cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey installerPackageName = "com.android.shell"; 4591cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 4603a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey params.installFlags |= INSTALL_FROM_ADB; 4611cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 4623a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } else { 463ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey mAppOps.checkPackage(callingUid, installerPackageName); 464ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 4653a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey params.installFlags &= ~INSTALL_FROM_ADB; 4663a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey params.installFlags &= ~INSTALL_ALL_USERS; 4673a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey params.installFlags |= INSTALL_REPLACE_EXISTING; 4683a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 4693a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 4701cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey // Defensively resize giant app icons 4711cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (params.appIcon != null) { 4721cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final ActivityManager am = (ActivityManager) mContext.getSystemService( 4731cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey Context.ACTIVITY_SERVICE); 4741cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final int iconSize = am.getLauncherLargeIconSize(); 4751cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if ((params.appIcon.getWidth() > iconSize * 2) 4761cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey || (params.appIcon.getHeight() > iconSize * 2)) { 4771cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.appIcon = Bitmap.createScaledBitmap(params.appIcon, iconSize, iconSize, 4781cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey true); 4791cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 4801cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 4811cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 482742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey // Figure out where we're going to be staging session data 483742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final boolean stageInternal; 484742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 485742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey if (params.mode == SessionParams.MODE_FULL_INSTALL) { 486742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey // Brand new install, use best resolved location. This also verifies 487742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey // that target has enough free space for the install. 488742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final int resolved = PackageHelper.resolveInstallLocation(mContext, 489bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey params.appPackageName, params.installLocation, params.sizeBytes, 490bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey params.installFlags); 491742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey if (resolved == PackageHelper.RECOMMEND_INSTALL_INTERNAL) { 492742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey stageInternal = true; 493742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } else if (resolved == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) { 494742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey stageInternal = false; 495742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } else { 496742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey throw new IOException("No storage with enough free space; res=" + resolved); 497a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 498742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 499742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } else if (params.mode == SessionParams.MODE_INHERIT_EXISTING) { 500742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey // We always stage inheriting sessions on internal storage first, 501742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey // since we don't want to grow containers until we're sure that 502742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey // everything looks legit. 503742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey stageInternal = true; 504742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey checkInternalStorage(params.sizeBytes); 505742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 506742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey // If we have a good hunch we'll end up on external storage, verify 507742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey // free space there too. 508742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final ApplicationInfo info = mPm.getApplicationInfo(params.appPackageName, 0, 509742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey userId); 510742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey if (info != null && (info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) { 511742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey checkExternalStorage(params.sizeBytes); 512742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 513742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey throw new UnsupportedOperationException("TODO: finish fleshing out ASEC support"); 514742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 515742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 516742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } else { 517742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey throw new IllegalArgumentException("Invalid install mode: " + params.mode); 518a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 519a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 520a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey final int sessionId; 521a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey final PackageInstallerSession session; 5223a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey synchronized (mSessions) { 5231cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey // Sanity check that installer isn't going crazy 524f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey final int activeCount = getSessionCount(mSessions, callingUid); 5251cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (activeCount >= MAX_ACTIVE_SESSIONS) { 526f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey throw new IllegalStateException( 527f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey "Too many active sessions for UID " + callingUid); 528f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey } 529f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey final int historicalCount = getSessionCount(mHistoricalSessions, callingUid); 530f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey if (historicalCount >= MAX_HISTORICAL_SESSIONS) { 531f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey throw new IllegalStateException( 532f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey "Too many historical sessions for UID " + callingUid); 5331cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 5341cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 535742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final long createdMillis = System.currentTimeMillis(); 536a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey sessionId = allocateSessionIdLocked(); 537a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 538742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey // We're staging to exactly one location 539742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey File stageDir = null; 540742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey String stageCid = null; 541742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey if (stageInternal) { 542742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey stageDir = prepareInternalStageDir(sessionId); 543742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } else { 544742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey stageCid = prepareExternalStageCid(sessionId, params.sizeBytes); 545742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 5463a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 547a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey session = new PackageInstallerSession(mInternalCallback, mContext, mPm, 5481cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mInstallThread.getLooper(), sessionId, userId, installerPackageName, params, 549742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey createdMillis, stageDir, stageCid, false); 5503a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey mSessions.put(sessionId, session); 5513a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 552a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 5531cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mCallbacks.notifySessionCreated(session.sessionId, session.userId); 554a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey writeSessionsAsync(); 555a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey return sessionId; 5563a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 5573a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 558742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey private void checkInternalStorage(long sizeBytes) throws IOException { 559742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey if (sizeBytes <= 0) return; 560742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 561742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final File target = Environment.getDataDirectory(); 562742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final long targetBytes = sizeBytes + mStorage.getStorageLowBytes(target); 563742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 564742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey mPm.freeStorage(targetBytes); 565742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey if (target.getUsableSpace() < targetBytes) { 566742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey throw new IOException("Not enough internal space to write " + sizeBytes + " bytes"); 567742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 568742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 569742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 570742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey private void checkExternalStorage(long sizeBytes) throws IOException { 571742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey if (sizeBytes <= 0) return; 572742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 573bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey final File target = new UserEnvironment(UserHandle.USER_OWNER) 574bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey .getExternalStorageDirectory(); 575742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final long targetBytes = sizeBytes + mStorage.getStorageLowBytes(target); 576742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 577742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey if (target.getUsableSpace() < targetBytes) { 578742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey throw new IOException("Not enough external space to write " + sizeBytes + " bytes"); 579742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 580742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 581742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 5823a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey @Override 5833a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey public IPackageInstallerSession openSession(int sessionId) { 5843a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey synchronized (mSessions) { 5853a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey final PackageInstallerSession session = mSessions.get(sessionId); 5863a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey if (session == null) { 5873a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey throw new IllegalStateException("Missing session " + sessionId); 5883a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 5891cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (!isCallingUidOwner(session)) { 5903a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey throw new SecurityException("Caller has no access to session " + sessionId); 5913a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 592742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey session.open(); 5933a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey return session; 5943a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 5953a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 5963a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 5973a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private int allocateSessionIdLocked() { 5981cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey int n = 0; 5991cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey int sessionId; 6001cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey do { 601f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey sessionId = mRandom.nextInt(Integer.MAX_VALUE - 1) + 1; 602742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey if (mSessions.get(sessionId) == null && mHistoricalSessions.get(sessionId) == null 603742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey && !mLegacySessions.get(sessionId, false)) { 6041cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey return sessionId; 6051cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 6061cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } while (n++ < 32); 6071cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 6081cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey throw new IllegalStateException("Failed to allocate session ID"); 6093a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 6103a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 611742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey private File prepareInternalStageDir(int sessionId) throws IOException { 612ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey final File file = new File(mStagingDir, "vmdl" + sessionId + ".tmp"); 613ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 614ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey if (file.exists()) { 615742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey throw new IOException("Session dir already exists: " + file); 616ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 617ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 618ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey try { 619ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey Os.mkdir(file.getAbsolutePath(), 0755); 620ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey Os.chmod(file.getAbsolutePath(), 0755); 621ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } catch (ErrnoException e) { 622ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey // This purposefully throws if directory already exists 623742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey throw new IOException("Failed to prepare session dir", e); 624ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 625ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 626ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey if (!SELinux.restorecon(file)) { 627742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey throw new IOException("Failed to restorecon session dir"); 628ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 629ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 630ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey return file; 631ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 632ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 633742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey private String prepareExternalStageCid(int sessionId, long sizeBytes) throws IOException { 634742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey if (sizeBytes <= 0) { 635742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey throw new IOException("Session must provide valid size for ASEC"); 636742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 637742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 638742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final String cid = "smdl" + sessionId + ".tmp"; 639742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 640742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey // Round up to nearest MB, plus another MB for filesystem overhead 641742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final int sizeMb = (int) ((sizeBytes + MB_IN_BYTES) / MB_IN_BYTES) + 1; 642742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 643742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey if (PackageHelper.createSdDir(sizeMb, cid, PackageManagerService.getEncryptKey(), 644742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey Process.SYSTEM_UID, true) == null) { 645742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey throw new IOException("Failed to create ASEC"); 646742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 647742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 648742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey return cid; 649742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 650742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 6513a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey @Override 652a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey public SessionInfo getSessionInfo(int sessionId) { 65316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey synchronized (mSessions) { 65416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey final PackageInstallerSession session = mSessions.get(sessionId); 6551cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (!isCallingUidOwner(session)) { 65616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey enforceCallerCanReadSessions(); 65716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 65816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey return session != null ? session.generateInfo() : null; 65916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 66016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 66116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey 66216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey @Override 663a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey public List<SessionInfo> getAllSessions(int userId) { 66416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "getAllSessions"); 66516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey enforceCallerCanReadSessions(); 6663a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 667a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey final List<SessionInfo> result = new ArrayList<>(); 6683a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey synchronized (mSessions) { 6693a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey for (int i = 0; i < mSessions.size(); i++) { 6703a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey final PackageInstallerSession session = mSessions.valueAt(i); 671bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey if (session.userId == userId) { 672bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey result.add(session.generateInfo()); 6733a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 6743a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 6753a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 676bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey return result; 6773a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 6783a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 6793a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey @Override 680a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey public List<SessionInfo> getMySessions(String installerPackageName, int userId) { 68116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "getMySessions"); 68216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey mAppOps.checkPackage(Binder.getCallingUid(), installerPackageName); 68316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey 684a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey final List<SessionInfo> result = new ArrayList<>(); 68516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey synchronized (mSessions) { 68616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey for (int i = 0; i < mSessions.size(); i++) { 68716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey final PackageInstallerSession session = mSessions.valueAt(i); 68816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey if (Objects.equals(session.installerPackageName, installerPackageName) 68916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey && session.userId == userId) { 69016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey result.add(session.generateInfo()); 69116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 69216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 69316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 69416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey return result; 69516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 69616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey 69716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey @Override 698a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey public void uninstall(String packageName, int flags, IntentSender statusReceiver, int userId) { 699a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "uninstall"); 70016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey 701a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext, 702bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey statusReceiver, packageName); 703f06009542390472872da986486d385001e91a2a7Jeff Sharkey if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES) 704f06009542390472872da986486d385001e91a2a7Jeff Sharkey == PackageManager.PERMISSION_GRANTED) { 705f06009542390472872da986486d385001e91a2a7Jeff Sharkey // Sweet, call straight through! 706a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey mPm.deletePackage(packageName, adapter.getBinder(), userId, flags); 707f06009542390472872da986486d385001e91a2a7Jeff Sharkey 708f06009542390472872da986486d385001e91a2a7Jeff Sharkey } else { 709f06009542390472872da986486d385001e91a2a7Jeff Sharkey // Take a short detour to confirm with user 710f06009542390472872da986486d385001e91a2a7Jeff Sharkey final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE); 711f06009542390472872da986486d385001e91a2a7Jeff Sharkey intent.setData(Uri.fromParts("package", packageName, null)); 712a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey intent.putExtra(PackageInstaller.EXTRA_CALLBACK, adapter.getBinder().asBinder()); 713a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey adapter.onUserActionRequired(intent); 714f06009542390472872da986486d385001e91a2a7Jeff Sharkey } 7153a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 7163a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 7173a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey @Override 7187328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey public void setPermissionsResult(int sessionId, boolean accepted) { 7197328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, TAG); 7207328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey 7217328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey synchronized (mSessions) { 7227328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey mSessions.get(sessionId).setPermissionsResult(accepted); 7237328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey } 7247328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey } 7257328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey 7267328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey @Override 72716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public void registerCallback(IPackageInstallerCallback callback, int userId) { 72816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "registerCallback"); 72916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey enforceCallerCanReadSessions(); 730a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 7311cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mCallbacks.register(callback, userId); 732bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey } 733bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey 734bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey @Override 73516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public void unregisterCallback(IPackageInstallerCallback callback) { 73616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey mCallbacks.unregister(callback); 737a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 738a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 739f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey private static int getSessionCount(SparseArray<PackageInstallerSession> sessions, 740f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey int installerUid) { 7411cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey int count = 0; 742f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey final int size = sessions.size(); 7431cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey for (int i = 0; i < size; i++) { 744f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey final PackageInstallerSession session = sessions.valueAt(i); 7451cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (session.installerUid == installerUid) { 7461cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey count++; 7471cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 7481cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 7491cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey return count; 7501cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 7511cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 7521cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private boolean isCallingUidOwner(PackageInstallerSession session) { 7531cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final int callingUid = Binder.getCallingUid(); 7541cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (callingUid == Process.ROOT_UID) { 7551cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey return true; 7561cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } else { 7571cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey return (session != null) && (callingUid == session.installerUid); 758a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 759a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 760a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 76116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey /** 76216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * We allow those with permission, or the current home app. 76316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey */ 76416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey private void enforceCallerCanReadSessions() { 76516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey final boolean hasPermission = (mContext.checkCallingOrSelfPermission( 76616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey android.Manifest.permission.READ_INSTALL_SESSIONS) 76716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey == PackageManager.PERMISSION_GRANTED); 76816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey final boolean isHomeApp = mPm.checkCallerIsHomeApp(); 76916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey if (hasPermission || isHomeApp) { 77016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey return; 77116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } else { 77216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey throw new SecurityException("Caller must be current home app to read install sessions"); 77316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 77416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 77516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey 776a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey static class PackageDeleteObserverAdapter extends PackageDeleteObserver { 777a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey private final Context mContext; 778a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey private final IntentSender mTarget; 779bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey private final String mPackageName; 780a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey 781bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey public PackageDeleteObserverAdapter(Context context, IntentSender target, 782bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey String packageName) { 783a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey mContext = context; 784a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey mTarget = target; 785bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey mPackageName = packageName; 786a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 787a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey 788a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey @Override 789a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey public void onUserActionRequired(Intent intent) { 790a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey final Intent fillIn = new Intent(); 791bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName); 792a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_STATUS, 793742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey PackageInstaller.STATUS_PENDING_USER_ACTION); 794a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey fillIn.putExtra(Intent.EXTRA_INTENT, intent); 795a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey try { 796a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey mTarget.sendIntent(mContext, 0, fillIn, null, null); 797a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } catch (SendIntentException ignored) { 798a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 799a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 800a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey 801a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey @Override 802a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey public void onPackageDeleted(String basePackageName, int returnCode, String msg) { 803a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey final Intent fillIn = new Intent(); 804bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName); 805a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_STATUS, 806a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey PackageManager.deleteStatusToPublicStatus(returnCode)); 807a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, 808a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey PackageManager.deleteStatusToString(returnCode, msg)); 809a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode); 810a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey try { 811a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey mTarget.sendIntent(mContext, 0, fillIn, null, null); 812a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } catch (SendIntentException ignored) { 813a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 814a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 815a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 816a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey 817a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey static class PackageInstallObserverAdapter extends PackageInstallObserver { 818a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey private final Context mContext; 819a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey private final IntentSender mTarget; 820bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey private final int mSessionId; 821a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey 822bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey public PackageInstallObserverAdapter(Context context, IntentSender target, int sessionId) { 823a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey mContext = context; 824a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey mTarget = target; 825bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey mSessionId = sessionId; 826a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 827a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey 828a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey @Override 829a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey public void onUserActionRequired(Intent intent) { 830a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey final Intent fillIn = new Intent(); 831bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId); 832a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_STATUS, 833742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey PackageInstaller.STATUS_PENDING_USER_ACTION); 834a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey fillIn.putExtra(Intent.EXTRA_INTENT, intent); 835a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey try { 836a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey mTarget.sendIntent(mContext, 0, fillIn, null, null); 837a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } catch (SendIntentException ignored) { 838a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 839a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 840a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey 841a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey @Override 842a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey public void onPackageInstalled(String basePackageName, int returnCode, String msg, 843a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey Bundle extras) { 844a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey final Intent fillIn = new Intent(); 845bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId); 846a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_STATUS, 847a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey PackageManager.installStatusToPublicStatus(returnCode)); 848a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, 849a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey PackageManager.installStatusToString(returnCode, msg)); 850a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode); 851a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey if (extras != null) { 852a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey final String existing = extras.getString( 853a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE); 854a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey if (!TextUtils.isEmpty(existing)) { 855bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, existing); 856a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 857a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 858a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey try { 859a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey mTarget.sendIntent(mContext, 0, fillIn, null, null); 860a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } catch (SendIntentException ignored) { 861a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 862a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 863a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 864a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey 8651cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static class Callbacks extends Handler { 8661cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final int MSG_SESSION_CREATED = 1; 8671cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final int MSG_SESSION_OPENED = 2; 8681cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final int MSG_SESSION_PROGRESS_CHANGED = 3; 8691cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final int MSG_SESSION_CLOSED = 4; 8701cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final int MSG_SESSION_FINISHED = 5; 8711cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 8721cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private final RemoteCallbackList<IPackageInstallerCallback> 8731cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mCallbacks = new RemoteCallbackList<>(); 8741cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 8751cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey public Callbacks(Looper looper) { 8761cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey super(looper); 877a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 878a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 8791cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey public void register(IPackageInstallerCallback callback, int userId) { 8801cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mCallbacks.register(callback, new UserHandle(userId)); 8811cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 8821cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 8831cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey public void unregister(IPackageInstallerCallback callback) { 8841cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mCallbacks.unregister(callback); 8851cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 8861cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 8871cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey @Override 8881cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey public void handleMessage(Message msg) { 8891cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final int userId = msg.arg2; 8901cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final int n = mCallbacks.beginBroadcast(); 8911cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey for (int i = 0; i < n; i++) { 8921cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final IPackageInstallerCallback callback = mCallbacks.getBroadcastItem(i); 8931cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final UserHandle user = (UserHandle) mCallbacks.getBroadcastCookie(i); 8941cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey // TODO: dispatch notifications for slave profiles 8951cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (userId == user.getIdentifier()) { 8961cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey try { 8971cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey invokeCallback(callback, msg); 8981cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } catch (RemoteException ignored) { 8991cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 900a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 901a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 9021cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mCallbacks.finishBroadcast(); 903a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 904a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 9051cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private void invokeCallback(IPackageInstallerCallback callback, Message msg) 9061cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey throws RemoteException { 9071cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final int sessionId = msg.arg1; 9081cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey switch (msg.what) { 9091cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey case MSG_SESSION_CREATED: 9101cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey callback.onSessionCreated(sessionId); 9111cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey break; 9121cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey case MSG_SESSION_OPENED: 9131cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey callback.onSessionOpened(sessionId); 9141cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey break; 9151cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey case MSG_SESSION_PROGRESS_CHANGED: 9161cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey callback.onSessionProgressChanged(sessionId, (float) msg.obj); 9171cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey break; 9181cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey case MSG_SESSION_CLOSED: 9191cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey callback.onSessionClosed(sessionId); 9201cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey break; 9211cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey case MSG_SESSION_FINISHED: 9221cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey callback.onSessionFinished(sessionId, (boolean) msg.obj); 9231cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey break; 924a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 925a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 9261cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 9271cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private void notifySessionCreated(int sessionId, int userId) { 9281cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey obtainMessage(MSG_SESSION_CREATED, sessionId, userId).sendToTarget(); 9291cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 9301cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 9311cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private void notifySessionOpened(int sessionId, int userId) { 9321cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey obtainMessage(MSG_SESSION_OPENED, sessionId, userId).sendToTarget(); 9331cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 9341cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 9351cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private void notifySessionProgressChanged(int sessionId, int userId, float progress) { 9361cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey obtainMessage(MSG_SESSION_PROGRESS_CHANGED, sessionId, userId, progress).sendToTarget(); 9371cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 9381cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 9391cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private void notifySessionClosed(int sessionId, int userId) { 9401cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey obtainMessage(MSG_SESSION_CLOSED, sessionId, userId).sendToTarget(); 9411cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 9421cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 9431cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey public void notifySessionFinished(int sessionId, int userId, boolean success) { 9441cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey obtainMessage(MSG_SESSION_FINISHED, sessionId, userId, success).sendToTarget(); 9451cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 946a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 947a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 948a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey void dump(IndentingPrintWriter pw) { 949a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey synchronized (mSessions) { 9509a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.println("Active install sessions:"); 9519a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.increaseIndent(); 9529a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey int N = mSessions.size(); 953a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey for (int i = 0; i < N; i++) { 954a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey final PackageInstallerSession session = mSessions.valueAt(i); 955a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey session.dump(pw); 956a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey pw.println(); 957a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 9589a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.println(); 9599a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.decreaseIndent(); 9609a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey 9619a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.println("Historical install sessions:"); 9629a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.increaseIndent(); 9639a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey N = mHistoricalSessions.size(); 9649a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey for (int i = 0; i < N; i++) { 9659a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey final PackageInstallerSession session = mHistoricalSessions.valueAt(i); 9669a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey session.dump(pw); 9679a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.println(); 9689a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey } 9699a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.println(); 9709a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.decreaseIndent(); 971742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 972742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey pw.println("Legacy install sessions:"); 973742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey pw.increaseIndent(); 974742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey pw.println(mLegacySessions.toString()); 975742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey pw.decreaseIndent(); 976a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 977bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey } 978bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey 9791cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey class InternalCallback { 98016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public void onSessionProgressChanged(PackageInstallerSession session, float progress) { 9811cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mCallbacks.notifySessionProgressChanged(session.sessionId, session.userId, progress); 9821cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 9831cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 984742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey public void onSessionOpened(PackageInstallerSession session) { 985742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey mCallbacks.notifySessionOpened(session.sessionId, session.userId); 986742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 987742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 9881cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey public void onSessionClosed(PackageInstallerSession session) { 9891cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mCallbacks.notifySessionClosed(session.sessionId, session.userId); 9903a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 9913a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 992a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey public void onSessionFinished(PackageInstallerSession session, boolean success) { 9931cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mCallbacks.notifySessionFinished(session.sessionId, session.userId, success); 994a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey synchronized (mSessions) { 995a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey mSessions.remove(session.sessionId); 9969a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey mHistoricalSessions.put(session.sessionId, session); 997a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 9983a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey writeSessionsAsync(); 9993a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 1000bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey 1001bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey public void onSessionSealed(PackageInstallerSession session) { 1002bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey // It's very important that we block until we've recorded the 1003bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey // session as being sealed, since we never want to allow mutation 1004bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey // after sealing. 1005bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey writeSessionsLocked(); 1006bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey } 10073a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 10083a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey} 1009