PackageInstallerService.java revision b2b9ab8354da1485178cd8d8e9d89ac915b3f269
13a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey/* 23a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * Copyright (C) 2014 The Android Open Source Project 33a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * 43a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License"); 53a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * you may not use this file except in compliance with the License. 63a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * You may obtain a copy of the License at 73a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * 83a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * http://www.apache.org/licenses/LICENSE-2.0 93a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * 103a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * Unless required by applicable law or agreed to in writing, software 113a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS, 123a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * See the License for the specific language governing permissions and 143a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * limitations under the License. 153a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey */ 163a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 173a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeypackage com.android.server.pm; 183a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 191cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.readBitmapAttribute; 201cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.readBooleanAttribute; 211cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.readIntAttribute; 221cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.readLongAttribute; 231cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.readStringAttribute; 241cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.readUriAttribute; 251cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.writeBooleanAttribute; 261cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.writeIntAttribute; 271cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.writeLongAttribute; 281cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.writeStringAttribute; 291cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.writeUriAttribute; 301cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; 311cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static org.xmlpull.v1.XmlPullParser.START_TAG; 321cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 331cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.app.ActivityManager; 343a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.app.AppOpsManager; 35a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.app.PackageDeleteObserver; 36a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.app.PackageInstallObserver; 373a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.content.Context; 38f06009542390472872da986486d385001e91a2a7Jeff Sharkeyimport android.content.Intent; 39a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.content.IntentSender; 40a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.content.IntentSender.SendIntentException; 413a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.content.pm.IPackageInstaller; 4216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkeyimport android.content.pm.IPackageInstallerCallback; 433a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.content.pm.IPackageInstallerSession; 44f06009542390472872da986486d385001e91a2a7Jeff Sharkeyimport android.content.pm.PackageInstaller; 45a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.content.pm.PackageInstaller.SessionInfo; 46a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.content.pm.PackageInstaller.SessionParams; 47ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkeyimport android.content.pm.PackageManager; 4897d47ed036ff7bd3d7d2ddc1c6df1104ec237559Jeff Sharkeyimport android.content.pm.ParceledListSlice; 491cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.graphics.Bitmap; 5002bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkeyimport android.graphics.Bitmap.CompressFormat; 5102bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkeyimport android.graphics.BitmapFactory; 52f06009542390472872da986486d385001e91a2a7Jeff Sharkeyimport android.net.Uri; 533a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.Binder; 54a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.os.Bundle; 551cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.os.Environment; 561cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.os.Handler; 573a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.HandlerThread; 581cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.os.Looper; 591cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.os.Message; 603a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.Process; 61a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkeyimport android.os.RemoteCallbackList; 62a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkeyimport android.os.RemoteException; 63ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport android.os.SELinux; 643a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.UserHandle; 653a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.UserManager; 66b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkeyimport android.os.storage.StorageManager; 67b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkeyimport android.os.storage.VolumeInfo; 68ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport android.system.ErrnoException; 69ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport android.system.Os; 70a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.text.TextUtils; 711cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.text.format.DateUtils; 723a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.util.ArraySet; 731cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.util.AtomicFile; 74a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkeyimport android.util.ExceptionUtils; 753a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.util.Slog; 763a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.util.SparseArray; 77742e790294b3441b79f715fe447069b63c6065dbJeff Sharkeyimport android.util.SparseBooleanArray; 781cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.util.Xml; 793a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 80b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkeyimport libcore.io.IoUtils; 81b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey 823a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport com.android.internal.annotations.GuardedBy; 83742e790294b3441b79f715fe447069b63c6065dbJeff Sharkeyimport com.android.internal.content.PackageHelper; 841cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport com.android.internal.util.FastXmlSerializer; 85a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkeyimport com.android.internal.util.IndentingPrintWriter; 863a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport com.android.server.IoThread; 873a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport com.google.android.collect.Sets; 883a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 891cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport org.xmlpull.v1.XmlPullParser; 901cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport org.xmlpull.v1.XmlPullParserException; 911cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport org.xmlpull.v1.XmlSerializer; 921cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 933a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport java.io.File; 941cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport java.io.FileInputStream; 951cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport java.io.FileNotFoundException; 961cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport java.io.FileOutputStream; 97ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport java.io.FilenameFilter; 98ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport java.io.IOException; 991cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport java.security.SecureRandom; 100bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkeyimport java.util.ArrayList; 101bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkeyimport java.util.List; 10216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkeyimport java.util.Objects; 1031cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport java.util.Random; 1043a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1053a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeypublic class PackageInstallerService extends IPackageInstaller.Stub { 1063a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private static final String TAG = "PackageInstaller"; 107e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey private static final boolean LOGD = false; 1083a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1093a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey // TODO: remove outstanding sessions when installer package goes away 1106c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey // TODO: notify listeners in other users when package has been installed there 111742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey // TODO: purge expired sessions periodically in addition to at reboot 1123a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1131cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey /** XML constants used in {@link #mSessionsFile} */ 1141cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String TAG_SESSIONS = "sessions"; 1151cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String TAG_SESSION = "session"; 1161cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_SESSION_ID = "sessionId"; 1171cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_USER_ID = "userId"; 1181cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_INSTALLER_PACKAGE_NAME = "installerPackageName"; 119e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey private static final String ATTR_INSTALLER_UID = "installerUid"; 1201cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_CREATED_MILLIS = "createdMillis"; 1211cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_SESSION_STAGE_DIR = "sessionStageDir"; 122742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey private static final String ATTR_SESSION_STAGE_CID = "sessionStageCid"; 12377d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey private static final String ATTR_PREPARED = "prepared"; 1241cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_SEALED = "sealed"; 1251cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_MODE = "mode"; 1261cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_INSTALL_FLAGS = "installFlags"; 1271cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_INSTALL_LOCATION = "installLocation"; 1281cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_SIZE_BYTES = "sizeBytes"; 1291cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_APP_PACKAGE_NAME = "appPackageName"; 13002bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey @Deprecated 1311cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_APP_ICON = "appIcon"; 1321cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_APP_LABEL = "appLabel"; 1331cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_ORIGINATING_URI = "originatingUri"; 1341cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_REFERRER_URI = "referrerUri"; 1351cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final String ATTR_ABI_OVERRIDE = "abiOverride"; 136b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey private static final String ATTR_VOLUME_UUID = "volumeUuid"; 1371cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 138f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey /** Automatically destroy sessions older than this */ 1391cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final long MAX_AGE_MILLIS = 3 * DateUtils.DAY_IN_MILLIS; 140f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey /** Upper bound on number of active sessions for a UID */ 1411cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final long MAX_ACTIVE_SESSIONS = 1024; 142f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey /** Upper bound on number of historical sessions for a UID */ 143f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey private static final long MAX_HISTORICAL_SESSIONS = 1048576; 1441cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 1453a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private final Context mContext; 1463a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private final PackageManagerService mPm; 1473a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 148b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey private AppOpsManager mAppOps; 149b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey private StorageManager mStorage; 150b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey 151ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey private final HandlerThread mInstallThread; 152cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey private final Handler mInstallHandler; 1533a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1541cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private final Callbacks mCallbacks; 1551cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 1561cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey /** 15702bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey * File storing persisted {@link #mSessions} metadata. 1581cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey */ 1591cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private final AtomicFile mSessionsFile; 1601cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 16102bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey /** 16202bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey * Directory storing persisted {@link #mSessions} metadata which is too 16302bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey * heavy to store directly in {@link #mSessionsFile}. 16402bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey */ 16502bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey private final File mSessionsDir; 16602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey 1671cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private final InternalCallback mInternalCallback = new InternalCallback(); 1681cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 1691cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey /** 1701cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * Used for generating session IDs. Since this is created at boot time, 1711cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * normal random might be predictable. 1721cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey */ 1731cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private final Random mRandom = new SecureRandom(); 1743a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1753a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey @GuardedBy("mSessions") 1763a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>(); 1773a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1789a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey /** Historical sessions kept around for debugging purposes */ 1799a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey @GuardedBy("mSessions") 1809a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey private final SparseArray<PackageInstallerSession> mHistoricalSessions = new SparseArray<>(); 1819a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey 182742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey /** Sessions allocated to legacy users */ 183742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey @GuardedBy("mSessions") 184742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey private final SparseBooleanArray mLegacySessions = new SparseBooleanArray(); 185742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 186ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey private static final FilenameFilter sStageFilter = new FilenameFilter() { 187ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey @Override 188ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey public boolean accept(File dir, String name) { 189742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey return isStageName(name); 190ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 191ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey }; 192ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 193b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey public PackageInstallerService(Context context, PackageManagerService pm) { 1943a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey mContext = context; 1953a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey mPm = pm; 196ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 197ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey mInstallThread = new HandlerThread(TAG); 198ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey mInstallThread.start(); 1993a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 200cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey mInstallHandler = new Handler(mInstallThread.getLooper()); 201cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey 2021cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mCallbacks = new Callbacks(mInstallThread.getLooper()); 2031cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 2041cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mSessionsFile = new AtomicFile( 2051cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey new File(Environment.getSystemSecureDirectory(), "install_sessions.xml")); 20602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey mSessionsDir = new File(Environment.getSystemSecureDirectory(), "install_sessions"); 20702bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey mSessionsDir.mkdirs(); 2081cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 2093a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey synchronized (mSessions) { 2103a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey readSessionsLocked(); 2113a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 212b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey final File internalStagingDir = buildInternalStagingDir(); 21302bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey final ArraySet<File> unclaimedStages = Sets.newArraySet( 214b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey internalStagingDir.listFiles(sStageFilter)); 21502bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey final ArraySet<File> unclaimedIcons = Sets.newArraySet( 21602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey mSessionsDir.listFiles()); 217742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 21802bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey // Ignore stages and icons claimed by active sessions 2193a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey for (int i = 0; i < mSessions.size(); i++) { 220ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey final PackageInstallerSession session = mSessions.valueAt(i); 22102bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey unclaimedStages.remove(session.stageDir); 22202bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey unclaimedIcons.remove(buildAppIconFile(session.sessionId)); 223ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 224742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 225742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey // Clean up orphaned staging directories 22602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey for (File stage : unclaimedStages) { 227ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey Slog.w(TAG, "Deleting orphan stage " + stage); 228ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey if (stage.isDirectory()) { 229b94c1657eb0140f7b91f5372a9f76de5a3d87e36Fyodor Kupolov mPm.mInstaller.rmPackageDir(stage.getAbsolutePath()); 230b94c1657eb0140f7b91f5372a9f76de5a3d87e36Fyodor Kupolov } else { 231b94c1657eb0140f7b91f5372a9f76de5a3d87e36Fyodor Kupolov stage.delete(); 232ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 2333a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 23402bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey 23502bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey // Clean up orphaned icons 23602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey for (File icon : unclaimedIcons) { 23702bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey Slog.w(TAG, "Deleting orphan icon " + icon); 23802bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey icon.delete(); 23902bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey } 240ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 241ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 242ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 243b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey public void systemReady() { 244b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey mAppOps = mContext.getSystemService(AppOpsManager.class); 245b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey mStorage = mContext.getSystemService(StorageManager.class); 246b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey } 247b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey 248742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey public void onSecureContainersAvailable() { 249742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey synchronized (mSessions) { 250742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final ArraySet<String> unclaimed = new ArraySet<>(); 251742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey for (String cid : PackageHelper.getSecureContainerList()) { 252742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey if (isStageName(cid)) { 253742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey unclaimed.add(cid); 254742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 255742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 256742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 257742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey // Ignore stages claimed by active sessions 258742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey for (int i = 0; i < mSessions.size(); i++) { 259742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final PackageInstallerSession session = mSessions.valueAt(i); 260941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey final String cid = session.stageCid; 261742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 262742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey if (unclaimed.remove(cid)) { 263742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey // Claimed by active session, mount it 264742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey PackageHelper.mountSdDir(cid, PackageManagerService.getEncryptKey(), 265742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey Process.SYSTEM_UID); 266742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 267742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 268742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 269742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey // Clean up orphaned staging containers 270742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey for (String cid : unclaimed) { 271742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey Slog.w(TAG, "Deleting orphan container " + cid); 272742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey PackageHelper.destroySdDir(cid); 273742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 274742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 275742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 276742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 277742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey public static boolean isStageName(String name) { 278742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final boolean isFile = name.startsWith("vmdl") && name.endsWith(".tmp"); 279742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final boolean isContainer = name.startsWith("smdl") && name.endsWith(".tmp"); 280742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final boolean isLegacyContainer = name.startsWith("smdl2tmp"); 281742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey return isFile || isContainer || isLegacyContainer; 2827328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey } 2837328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey 284ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey @Deprecated 285b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey public File allocateStageDirLegacy(String volumeUuid) throws IOException { 286ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey synchronized (mSessions) { 287ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey try { 288ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey final int sessionId = allocateSessionIdLocked(); 289742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey mLegacySessions.put(sessionId, true); 290b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey final File stageDir = buildStageDir(volumeUuid, sessionId); 291b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey prepareStageDir(stageDir); 29277d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey return stageDir; 293ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } catch (IllegalStateException e) { 294ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey throw new IOException(e); 2953a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 2963a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 2973a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 2983a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 299742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey @Deprecated 300742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey public String allocateExternalStageCidLegacy() { 301742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey synchronized (mSessions) { 302742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final int sessionId = allocateSessionIdLocked(); 303742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey mLegacySessions.put(sessionId, true); 304742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey return "smdl" + sessionId + ".tmp"; 305742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 306742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 307742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 3083a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private void readSessionsLocked() { 3091cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (LOGD) Slog.v(TAG, "readSessionsLocked()"); 3101cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 3113a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey mSessions.clear(); 3121cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 3131cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey FileInputStream fis = null; 3141cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey try { 3151cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey fis = mSessionsFile.openRead(); 3161cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final XmlPullParser in = Xml.newPullParser(); 3171cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey in.setInput(fis, null); 3181cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 3191cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey int type; 3201cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey while ((type = in.next()) != END_DOCUMENT) { 3211cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (type == START_TAG) { 3221cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final String tag = in.getName(); 3231cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (TAG_SESSION.equals(tag)) { 3241cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final PackageInstallerSession session = readSessionLocked(in); 3251cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final long age = System.currentTimeMillis() - session.createdMillis; 3261cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 3271cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final boolean valid; 3281cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (age >= MAX_AGE_MILLIS) { 3291cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey Slog.w(TAG, "Abandoning old session first created at " 3301cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey + session.createdMillis); 3311cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey valid = false; 3321cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } else { 3331cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey valid = true; 3341cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 3351cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 3361cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (valid) { 3371cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mSessions.put(session.sessionId, session); 3381cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } else { 3391cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey // Since this is early during boot we don't send 3401cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey // any observer events about the session, but we 3411cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey // keep details around for dumpsys. 3421cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mHistoricalSessions.put(session.sessionId, session); 3431cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 3441cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 3451cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 3461cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 3471cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } catch (FileNotFoundException e) { 3481cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey // Missing sessions are okay, probably first boot 3491cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } catch (IOException e) { 3508d05172112436a81bed6e4a0810f8914509d8a4dDianne Hackborn Slog.wtf(TAG, "Failed reading install sessions", e); 3511cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } catch (XmlPullParserException e) { 3528d05172112436a81bed6e4a0810f8914509d8a4dDianne Hackborn Slog.wtf(TAG, "Failed reading install sessions", e); 3531cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } finally { 3541cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey IoUtils.closeQuietly(fis); 3551cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 3561cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 3571cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 3581cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private PackageInstallerSession readSessionLocked(XmlPullParser in) throws IOException { 3591cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final int sessionId = readIntAttribute(in, ATTR_SESSION_ID); 3601cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final int userId = readIntAttribute(in, ATTR_USER_ID); 3611cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final String installerPackageName = readStringAttribute(in, ATTR_INSTALLER_PACKAGE_NAME); 362e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey final int installerUid = readIntAttribute(in, ATTR_INSTALLER_UID, 363e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey mPm.getPackageUid(installerPackageName, userId)); 3641cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final long createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS); 365742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final String stageDirRaw = readStringAttribute(in, ATTR_SESSION_STAGE_DIR); 366742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final File stageDir = (stageDirRaw != null) ? new File(stageDirRaw) : null; 367742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final String stageCid = readStringAttribute(in, ATTR_SESSION_STAGE_CID); 36877d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey final boolean prepared = readBooleanAttribute(in, ATTR_PREPARED, true); 3691cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final boolean sealed = readBooleanAttribute(in, ATTR_SEALED); 3701cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 371a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey final SessionParams params = new SessionParams( 372a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey SessionParams.MODE_INVALID); 3731cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.mode = readIntAttribute(in, ATTR_MODE); 3741cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.installFlags = readIntAttribute(in, ATTR_INSTALL_FLAGS); 3751cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.installLocation = readIntAttribute(in, ATTR_INSTALL_LOCATION); 3761cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.sizeBytes = readLongAttribute(in, ATTR_SIZE_BYTES); 3771cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.appPackageName = readStringAttribute(in, ATTR_APP_PACKAGE_NAME); 3781cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.appIcon = readBitmapAttribute(in, ATTR_APP_ICON); 3791cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.appLabel = readStringAttribute(in, ATTR_APP_LABEL); 3801cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.originatingUri = readUriAttribute(in, ATTR_ORIGINATING_URI); 3811cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.referrerUri = readUriAttribute(in, ATTR_REFERRER_URI); 3821cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.abiOverride = readStringAttribute(in, ATTR_ABI_OVERRIDE); 383b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey params.volumeUuid = readStringAttribute(in, ATTR_VOLUME_UUID); 3841cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 38502bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey final File appIconFile = buildAppIconFile(sessionId); 38602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey if (appIconFile.exists()) { 38702bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey params.appIcon = BitmapFactory.decodeFile(appIconFile.getAbsolutePath()); 38802bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey params.appIconLastModified = appIconFile.lastModified(); 38902bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey } 39002bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey 391a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey return new PackageInstallerSession(mInternalCallback, mContext, mPm, 392e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey mInstallThread.getLooper(), sessionId, userId, installerPackageName, installerUid, 393e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey params, createdMillis, stageDir, stageCid, prepared, sealed); 3943a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 3953a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 3963a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private void writeSessionsLocked() { 3971cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (LOGD) Slog.v(TAG, "writeSessionsLocked()"); 3981cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 3991cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey FileOutputStream fos = null; 4001cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey try { 4011cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey fos = mSessionsFile.startWrite(); 4021cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 4031cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey XmlSerializer out = new FastXmlSerializer(); 4041cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey out.setOutput(fos, "utf-8"); 4051cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey out.startDocument(null, true); 4061cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey out.startTag(null, TAG_SESSIONS); 4071cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final int size = mSessions.size(); 4081cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey for (int i = 0; i < size; i++) { 4091cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final PackageInstallerSession session = mSessions.valueAt(i); 4101cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeSessionLocked(out, session); 4111cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 4121cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey out.endTag(null, TAG_SESSIONS); 4131cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey out.endDocument(); 4141cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 4151cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mSessionsFile.finishWrite(fos); 4161cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } catch (IOException e) { 4171cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (fos != null) { 4181cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mSessionsFile.failWrite(fos); 4191cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 4201cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 4211cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 4221cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 4231cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private void writeSessionLocked(XmlSerializer out, PackageInstallerSession session) 4241cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey throws IOException { 425a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey final SessionParams params = session.params; 4261cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 4271cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey out.startTag(null, TAG_SESSION); 4281cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 4291cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeIntAttribute(out, ATTR_SESSION_ID, session.sessionId); 4301cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeIntAttribute(out, ATTR_USER_ID, session.userId); 4311cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeStringAttribute(out, ATTR_INSTALLER_PACKAGE_NAME, 4321cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey session.installerPackageName); 433e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey writeIntAttribute(out, ATTR_INSTALLER_UID, session.installerUid); 4341cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeLongAttribute(out, ATTR_CREATED_MILLIS, session.createdMillis); 435941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey if (session.stageDir != null) { 436742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey writeStringAttribute(out, ATTR_SESSION_STAGE_DIR, 437941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey session.stageDir.getAbsolutePath()); 438742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 439941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey if (session.stageCid != null) { 440941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey writeStringAttribute(out, ATTR_SESSION_STAGE_CID, session.stageCid); 441742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 44277d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey writeBooleanAttribute(out, ATTR_PREPARED, session.isPrepared()); 443742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey writeBooleanAttribute(out, ATTR_SEALED, session.isSealed()); 4441cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 4451cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeIntAttribute(out, ATTR_MODE, params.mode); 4461cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeIntAttribute(out, ATTR_INSTALL_FLAGS, params.installFlags); 4471cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeIntAttribute(out, ATTR_INSTALL_LOCATION, params.installLocation); 4481cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeLongAttribute(out, ATTR_SIZE_BYTES, params.sizeBytes); 4491cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeStringAttribute(out, ATTR_APP_PACKAGE_NAME, params.appPackageName); 4501cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeStringAttribute(out, ATTR_APP_LABEL, params.appLabel); 4511cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeUriAttribute(out, ATTR_ORIGINATING_URI, params.originatingUri); 4521cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeUriAttribute(out, ATTR_REFERRER_URI, params.referrerUri); 4531cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey writeStringAttribute(out, ATTR_ABI_OVERRIDE, params.abiOverride); 454b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey writeStringAttribute(out, ATTR_VOLUME_UUID, params.volumeUuid); 4551cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 45602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey // Persist app icon if changed since last written 45702bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey final File appIconFile = buildAppIconFile(session.sessionId); 45802bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey if (params.appIcon == null && appIconFile.exists()) { 45902bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey appIconFile.delete(); 46002bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey } else if (params.appIcon != null 46102bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey && appIconFile.lastModified() != params.appIconLastModified) { 46202bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey if (LOGD) Slog.w(TAG, "Writing changed icon " + appIconFile); 46302bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey FileOutputStream os = null; 46402bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey try { 46502bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey os = new FileOutputStream(appIconFile); 46602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey params.appIcon.compress(CompressFormat.PNG, 90, os); 46702bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey } catch (IOException e) { 46802bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey Slog.w(TAG, "Failed to write icon " + appIconFile + ": " + e.getMessage()); 46902bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey } finally { 47002bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey IoUtils.closeQuietly(os); 47102bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey } 47202bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey 47302bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey params.appIconLastModified = appIconFile.lastModified(); 47402bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey } 47502bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey 4761cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey out.endTag(null, TAG_SESSION); 4773a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 4783a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 47902bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey private File buildAppIconFile(int sessionId) { 48002bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey return new File(mSessionsDir, "app_icon." + sessionId + ".png"); 48102bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey } 48202bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey 4833a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private void writeSessionsAsync() { 4843a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey IoThread.getHandler().post(new Runnable() { 4853a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey @Override 4863a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey public void run() { 4873a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey synchronized (mSessions) { 4883a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey writeSessionsLocked(); 4893a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 4903a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 4913a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey }); 4923a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 4933a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 4943a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey @Override 495a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey public int createSession(SessionParams params, String installerPackageName, int userId) { 496742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey try { 497742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey return createSessionInternal(params, installerPackageName, userId); 498742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } catch (IOException e) { 499742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey throw ExceptionUtils.wrap(e); 500742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 501742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 502742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 503742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey private int createSessionInternal(SessionParams params, String installerPackageName, int userId) 504742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey throws IOException { 5053a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey final int callingUid = Binder.getCallingUid(); 506e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey mPm.enforceCrossUserPermission(callingUid, userId, true, true, "createSession"); 5073a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 508e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey if (mPm.isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) { 5093a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey throw new SecurityException("User restriction prevents installing"); 5103a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 5113a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 5121cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) { 513e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey params.installFlags |= PackageManager.INSTALL_FROM_ADB; 5141cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 5153a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } else { 516ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey mAppOps.checkPackage(callingUid, installerPackageName); 517ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 518e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey params.installFlags &= ~PackageManager.INSTALL_FROM_ADB; 519e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey params.installFlags &= ~PackageManager.INSTALL_ALL_USERS; 520e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey params.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING; 5213a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 5223a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 5231cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey // Defensively resize giant app icons 5241cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (params.appIcon != null) { 5251cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final ActivityManager am = (ActivityManager) mContext.getSystemService( 5261cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey Context.ACTIVITY_SERVICE); 5271cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final int iconSize = am.getLauncherLargeIconSize(); 5281cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if ((params.appIcon.getWidth() > iconSize * 2) 5291cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey || (params.appIcon.getHeight() > iconSize * 2)) { 5301cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey params.appIcon = Bitmap.createScaledBitmap(params.appIcon, iconSize, iconSize, 5311cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey true); 5321cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 5331cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 5341cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 535b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey switch (params.mode) { 536b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey case SessionParams.MODE_FULL_INSTALL: 537b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey case SessionParams.MODE_INHERIT_EXISTING: 538b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey break; 539b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey default: 540b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey throw new IllegalArgumentException("Invalid install mode: " + params.mode); 541b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey } 542b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey 543b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey // If caller requested explicit location, sanity check it, otherwise 544b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey // resolve the best internal or adopted location. 545b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) { 546b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey if (!PackageHelper.fitsOnInternal(mContext, params.sizeBytes)) { 547b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey throw new IOException("No suitable internal storage available"); 548b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey } 549b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey 550b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey } else if ((params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) { 551b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey if (!PackageHelper.fitsOnExternal(mContext, params.sizeBytes)) { 552b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey throw new IOException("No suitable external storage available"); 553b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey } 554b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey 555b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey } else { 556b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey // For now, installs to adopted media are treated as internal from 557b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey // an install flag point-of-view. 558b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey params.setInstallFlagsInternal(); 559b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey 56077d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey // Resolve best location for install, based on combination of 56177d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey // requested install flags, delta size, and manifest settings. 562e812d9096915ad165de125520ed7371009587d1fRobin Lee final long ident = Binder.clearCallingIdentity(); 563e812d9096915ad165de125520ed7371009587d1fRobin Lee try { 564b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey params.volumeUuid = PackageHelper.resolveInstallVolume(mContext, 565b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey params.appPackageName, params.installLocation, params.sizeBytes); 566e812d9096915ad165de125520ed7371009587d1fRobin Lee } finally { 567e812d9096915ad165de125520ed7371009587d1fRobin Lee Binder.restoreCallingIdentity(ident); 568a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 569a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 570a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 571a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey final int sessionId; 572a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey final PackageInstallerSession session; 5733a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey synchronized (mSessions) { 5741cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey // Sanity check that installer isn't going crazy 575f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey final int activeCount = getSessionCount(mSessions, callingUid); 5761cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (activeCount >= MAX_ACTIVE_SESSIONS) { 577f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey throw new IllegalStateException( 578f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey "Too many active sessions for UID " + callingUid); 579f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey } 580f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey final int historicalCount = getSessionCount(mHistoricalSessions, callingUid); 581f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey if (historicalCount >= MAX_HISTORICAL_SESSIONS) { 582f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey throw new IllegalStateException( 583f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey "Too many historical sessions for UID " + callingUid); 5841cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 5851cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 586742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey final long createdMillis = System.currentTimeMillis(); 587a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey sessionId = allocateSessionIdLocked(); 588a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 589742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey // We're staging to exactly one location 590742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey File stageDir = null; 591742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey String stageCid = null; 59277d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) { 593b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey stageDir = buildStageDir(params.volumeUuid, sessionId); 594742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } else { 59577d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey stageCid = buildExternalStageCid(sessionId); 596742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 5973a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 598a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey session = new PackageInstallerSession(mInternalCallback, mContext, mPm, 599e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey mInstallThread.getLooper(), sessionId, userId, installerPackageName, callingUid, 600e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey params, createdMillis, stageDir, stageCid, false, false); 6013a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey mSessions.put(sessionId, session); 6023a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 603a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 6041cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mCallbacks.notifySessionCreated(session.sessionId, session.userId); 605a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey writeSessionsAsync(); 606a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey return sessionId; 6073a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 6083a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 609381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey @Override 610ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey public void updateSessionAppIcon(int sessionId, Bitmap appIcon) { 611ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey synchronized (mSessions) { 612ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey final PackageInstallerSession session = mSessions.get(sessionId); 613ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey if (session == null || !isCallingUidOwner(session)) { 614ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey throw new SecurityException("Caller has no access to session " + sessionId); 615ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey } 61602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey 61702bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey // Defensively resize giant app icons 61802bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey if (appIcon != null) { 61902bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey final ActivityManager am = (ActivityManager) mContext.getSystemService( 62002bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey Context.ACTIVITY_SERVICE); 62102bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey final int iconSize = am.getLauncherLargeIconSize(); 62202bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey if ((appIcon.getWidth() > iconSize * 2) 62302bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey || (appIcon.getHeight() > iconSize * 2)) { 62402bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey appIcon = Bitmap.createScaledBitmap(appIcon, iconSize, iconSize, true); 62502bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey } 62602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey } 62702bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey 628ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey session.params.appIcon = appIcon; 62902bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey session.params.appIconLastModified = -1; 63002bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey 631ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey mInternalCallback.onSessionBadgingChanged(session); 632ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey } 633ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey } 634ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey 635ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey @Override 636ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey public void updateSessionAppLabel(int sessionId, String appLabel) { 637ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey synchronized (mSessions) { 638ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey final PackageInstallerSession session = mSessions.get(sessionId); 639ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey if (session == null || !isCallingUidOwner(session)) { 640ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey throw new SecurityException("Caller has no access to session " + sessionId); 641ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey } 642ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey session.params.appLabel = appLabel; 643ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey mInternalCallback.onSessionBadgingChanged(session); 644ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey } 645ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey } 646ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey 647ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey @Override 648381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey public void abandonSession(int sessionId) { 649381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey synchronized (mSessions) { 650381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey final PackageInstallerSession session = mSessions.get(sessionId); 651381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey if (session == null || !isCallingUidOwner(session)) { 652381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey throw new SecurityException("Caller has no access to session " + sessionId); 653381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey } 654381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey session.abandon(); 655381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey } 656381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey } 657381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey 65877d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey @Override 65977d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey public IPackageInstallerSession openSession(int sessionId) { 66077d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey try { 66177d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey return openSessionInternal(sessionId); 66277d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey } catch (IOException e) { 66377d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey throw ExceptionUtils.wrap(e); 664742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 665742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 666742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 66777d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey private IPackageInstallerSession openSessionInternal(int sessionId) throws IOException { 6683a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey synchronized (mSessions) { 6693a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey final PackageInstallerSession session = mSessions.get(sessionId); 670381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey if (session == null || !isCallingUidOwner(session)) { 6713a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey throw new SecurityException("Caller has no access to session " + sessionId); 6723a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 673742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey session.open(); 6743a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey return session; 6753a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 6763a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 6773a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 6783a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private int allocateSessionIdLocked() { 6791cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey int n = 0; 6801cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey int sessionId; 6811cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey do { 682f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey sessionId = mRandom.nextInt(Integer.MAX_VALUE - 1) + 1; 683742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey if (mSessions.get(sessionId) == null && mHistoricalSessions.get(sessionId) == null 684742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey && !mLegacySessions.get(sessionId, false)) { 6851cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey return sessionId; 6861cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 6871cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } while (n++ < 32); 6881cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 6891cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey throw new IllegalStateException("Failed to allocate session ID"); 6903a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 6913a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 692b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey private File buildInternalStagingDir() { 693b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey return new File(Environment.getDataDirectory(), "app"); 694b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey } 695b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey 696b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey private File buildStagingDir(String volumeUuid) throws FileNotFoundException { 697b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey if (volumeUuid == null) { 698b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey return buildInternalStagingDir(); 699b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey } else { 700b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey final VolumeInfo vol = mStorage.findVolumeByUuid(volumeUuid); 701b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey if (vol != null && vol.type == VolumeInfo.TYPE_PRIVATE 702b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey && vol.state == VolumeInfo.STATE_MOUNTED) { 703b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey return new File(vol.path, "app"); 704b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey } else { 705b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey throw new FileNotFoundException("Failed to find volume for UUID " + volumeUuid); 706b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey } 707b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey } 708b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey } 709b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey 710b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey private File buildStageDir(String volumeUuid, int sessionId) throws FileNotFoundException { 711b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey final File stagingDir = buildStagingDir(volumeUuid); 712b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey return new File(stagingDir, "vmdl" + sessionId + ".tmp"); 71377d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey } 714ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 715b2b9ab8354da1485178cd8d8e9d89ac915b3f269Jeff Sharkey static void prepareStageDir(File stageDir) throws IOException { 71677d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey if (stageDir.exists()) { 71777d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey throw new IOException("Session dir already exists: " + stageDir); 718ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 719ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 720ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey try { 72177d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey Os.mkdir(stageDir.getAbsolutePath(), 0755); 72277d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey Os.chmod(stageDir.getAbsolutePath(), 0755); 723ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } catch (ErrnoException e) { 724ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey // This purposefully throws if directory already exists 72577d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey throw new IOException("Failed to prepare session dir: " + stageDir, e); 726ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 727ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 72877d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey if (!SELinux.restorecon(stageDir)) { 72977d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey throw new IOException("Failed to restorecon session dir: " + stageDir); 730ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 731ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 732ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 73377d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey private String buildExternalStageCid(int sessionId) { 73477d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey return "smdl" + sessionId + ".tmp"; 73577d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey } 736742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 73777d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey static void prepareExternalStageCid(String stageCid, long sizeBytes) throws IOException { 73877d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey if (PackageHelper.createSdDir(sizeBytes, stageCid, PackageManagerService.getEncryptKey(), 739742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey Process.SYSTEM_UID, true) == null) { 74077d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey throw new IOException("Failed to create session cid: " + stageCid); 741742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 742742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 743742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 7443a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey @Override 745a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey public SessionInfo getSessionInfo(int sessionId) { 74616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey synchronized (mSessions) { 74716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey final PackageInstallerSession session = mSessions.get(sessionId); 74816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey return session != null ? session.generateInfo() : null; 74916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 75016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 75116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey 75216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey @Override 75397d47ed036ff7bd3d7d2ddc1c6df1104ec237559Jeff Sharkey public ParceledListSlice<SessionInfo> getAllSessions(int userId) { 7548cd28b57ed732656d002d97879e15c5695b54fffAmith Yamasani mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, "getAllSessions"); 7553a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 756a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey final List<SessionInfo> result = new ArrayList<>(); 7573a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey synchronized (mSessions) { 7583a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey for (int i = 0; i < mSessions.size(); i++) { 7593a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey final PackageInstallerSession session = mSessions.valueAt(i); 760bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey if (session.userId == userId) { 761bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey result.add(session.generateInfo()); 7623a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 7633a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 7643a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 76597d47ed036ff7bd3d7d2ddc1c6df1104ec237559Jeff Sharkey return new ParceledListSlice<>(result); 7663a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 7673a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 7683a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey @Override 76997d47ed036ff7bd3d7d2ddc1c6df1104ec237559Jeff Sharkey public ParceledListSlice<SessionInfo> getMySessions(String installerPackageName, int userId) { 7708cd28b57ed732656d002d97879e15c5695b54fffAmith Yamasani mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, "getMySessions"); 77116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey mAppOps.checkPackage(Binder.getCallingUid(), installerPackageName); 77216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey 773a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey final List<SessionInfo> result = new ArrayList<>(); 77416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey synchronized (mSessions) { 77516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey for (int i = 0; i < mSessions.size(); i++) { 77616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey final PackageInstallerSession session = mSessions.valueAt(i); 77716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey if (Objects.equals(session.installerPackageName, installerPackageName) 77816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey && session.userId == userId) { 77916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey result.add(session.generateInfo()); 78016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 78116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 78216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 78397d47ed036ff7bd3d7d2ddc1c6df1104ec237559Jeff Sharkey return new ParceledListSlice<>(result); 78416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 78516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey 78616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey @Override 787a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey public void uninstall(String packageName, int flags, IntentSender statusReceiver, int userId) { 788e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, true, "uninstall"); 78916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey 790a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext, 791bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey statusReceiver, packageName); 792f06009542390472872da986486d385001e91a2a7Jeff Sharkey if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES) 793f06009542390472872da986486d385001e91a2a7Jeff Sharkey == PackageManager.PERMISSION_GRANTED) { 794f06009542390472872da986486d385001e91a2a7Jeff Sharkey // Sweet, call straight through! 795a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey mPm.deletePackage(packageName, adapter.getBinder(), userId, flags); 796f06009542390472872da986486d385001e91a2a7Jeff Sharkey 797f06009542390472872da986486d385001e91a2a7Jeff Sharkey } else { 798f06009542390472872da986486d385001e91a2a7Jeff Sharkey // Take a short detour to confirm with user 799f06009542390472872da986486d385001e91a2a7Jeff Sharkey final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE); 800f06009542390472872da986486d385001e91a2a7Jeff Sharkey intent.setData(Uri.fromParts("package", packageName, null)); 801a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey intent.putExtra(PackageInstaller.EXTRA_CALLBACK, adapter.getBinder().asBinder()); 802a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey adapter.onUserActionRequired(intent); 803f06009542390472872da986486d385001e91a2a7Jeff Sharkey } 8043a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 8053a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 8063a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey @Override 8077328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey public void setPermissionsResult(int sessionId, boolean accepted) { 8087328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, TAG); 8097328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey 8107328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey synchronized (mSessions) { 8117328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey mSessions.get(sessionId).setPermissionsResult(accepted); 8127328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey } 8137328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey } 8147328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey 8157328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey @Override 81616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public void registerCallback(IPackageInstallerCallback callback, int userId) { 8178cd28b57ed732656d002d97879e15c5695b54fffAmith Yamasani mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, "registerCallback"); 8181cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mCallbacks.register(callback, userId); 819bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey } 820bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey 821bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey @Override 82216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public void unregisterCallback(IPackageInstallerCallback callback) { 82316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey mCallbacks.unregister(callback); 824a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 825a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 826f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey private static int getSessionCount(SparseArray<PackageInstallerSession> sessions, 827f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey int installerUid) { 8281cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey int count = 0; 829f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey final int size = sessions.size(); 8301cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey for (int i = 0; i < size; i++) { 831f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey final PackageInstallerSession session = sessions.valueAt(i); 8321cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (session.installerUid == installerUid) { 8331cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey count++; 8341cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 8351cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 8361cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey return count; 8371cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 8381cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 8391cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private boolean isCallingUidOwner(PackageInstallerSession session) { 8401cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final int callingUid = Binder.getCallingUid(); 8411cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (callingUid == Process.ROOT_UID) { 8421cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey return true; 8431cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } else { 8441cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey return (session != null) && (callingUid == session.installerUid); 845a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 846a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 847a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 848a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey static class PackageDeleteObserverAdapter extends PackageDeleteObserver { 849a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey private final Context mContext; 850a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey private final IntentSender mTarget; 851bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey private final String mPackageName; 852a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey 853bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey public PackageDeleteObserverAdapter(Context context, IntentSender target, 854bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey String packageName) { 855a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey mContext = context; 856a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey mTarget = target; 857bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey mPackageName = packageName; 858a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 859a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey 860a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey @Override 861a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey public void onUserActionRequired(Intent intent) { 862a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey final Intent fillIn = new Intent(); 863bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName); 864a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_STATUS, 865742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey PackageInstaller.STATUS_PENDING_USER_ACTION); 866a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey fillIn.putExtra(Intent.EXTRA_INTENT, intent); 867a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey try { 868a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey mTarget.sendIntent(mContext, 0, fillIn, null, null); 869a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } catch (SendIntentException ignored) { 870a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 871a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 872a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey 873a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey @Override 874a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey public void onPackageDeleted(String basePackageName, int returnCode, String msg) { 875a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey final Intent fillIn = new Intent(); 876bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName); 877a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_STATUS, 878a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey PackageManager.deleteStatusToPublicStatus(returnCode)); 879a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, 880a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey PackageManager.deleteStatusToString(returnCode, msg)); 881a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode); 882a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey try { 883a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey mTarget.sendIntent(mContext, 0, fillIn, null, null); 884a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } catch (SendIntentException ignored) { 885a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 886a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 887a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 888a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey 889a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey static class PackageInstallObserverAdapter extends PackageInstallObserver { 890a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey private final Context mContext; 891a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey private final IntentSender mTarget; 892bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey private final int mSessionId; 893a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey 894bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey public PackageInstallObserverAdapter(Context context, IntentSender target, int sessionId) { 895a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey mContext = context; 896a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey mTarget = target; 897bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey mSessionId = sessionId; 898a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 899a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey 900a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey @Override 901a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey public void onUserActionRequired(Intent intent) { 902a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey final Intent fillIn = new Intent(); 903bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId); 904a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_STATUS, 905742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey PackageInstaller.STATUS_PENDING_USER_ACTION); 906a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey fillIn.putExtra(Intent.EXTRA_INTENT, intent); 907a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey try { 908a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey mTarget.sendIntent(mContext, 0, fillIn, null, null); 909a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } catch (SendIntentException ignored) { 910a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 911a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 912a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey 913a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey @Override 914a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey public void onPackageInstalled(String basePackageName, int returnCode, String msg, 915a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey Bundle extras) { 916a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey final Intent fillIn = new Intent(); 917bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId); 918a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_STATUS, 919a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey PackageManager.installStatusToPublicStatus(returnCode)); 920a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, 921a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey PackageManager.installStatusToString(returnCode, msg)); 922a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode); 923a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey if (extras != null) { 924a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey final String existing = extras.getString( 925a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE); 926a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey if (!TextUtils.isEmpty(existing)) { 927941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey fillIn.putExtra(PackageInstaller.EXTRA_OTHER_PACKAGE_NAME, existing); 928a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 929a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 930a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey try { 931a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey mTarget.sendIntent(mContext, 0, fillIn, null, null); 932a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } catch (SendIntentException ignored) { 933a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 934a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 935a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey } 936a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey 9371cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static class Callbacks extends Handler { 9381cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final int MSG_SESSION_CREATED = 1; 939ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey private static final int MSG_SESSION_BADGING_CHANGED = 2; 940bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey private static final int MSG_SESSION_ACTIVE_CHANGED = 3; 941ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey private static final int MSG_SESSION_PROGRESS_CHANGED = 4; 942bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey private static final int MSG_SESSION_FINISHED = 5; 9431cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 9441cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private final RemoteCallbackList<IPackageInstallerCallback> 9451cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mCallbacks = new RemoteCallbackList<>(); 9461cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 9471cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey public Callbacks(Looper looper) { 9481cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey super(looper); 949a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 950a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 9511cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey public void register(IPackageInstallerCallback callback, int userId) { 9521cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mCallbacks.register(callback, new UserHandle(userId)); 9531cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 9541cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 9551cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey public void unregister(IPackageInstallerCallback callback) { 9561cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mCallbacks.unregister(callback); 9571cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 9581cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 9591cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey @Override 9601cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey public void handleMessage(Message msg) { 9611cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final int userId = msg.arg2; 9621cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final int n = mCallbacks.beginBroadcast(); 9631cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey for (int i = 0; i < n; i++) { 9641cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final IPackageInstallerCallback callback = mCallbacks.getBroadcastItem(i); 9651cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final UserHandle user = (UserHandle) mCallbacks.getBroadcastCookie(i); 9661cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey // TODO: dispatch notifications for slave profiles 9671cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey if (userId == user.getIdentifier()) { 9681cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey try { 9691cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey invokeCallback(callback, msg); 9701cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } catch (RemoteException ignored) { 9711cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 972a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 973a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 9741cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mCallbacks.finishBroadcast(); 975a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 976a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 9771cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private void invokeCallback(IPackageInstallerCallback callback, Message msg) 9781cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey throws RemoteException { 9791cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final int sessionId = msg.arg1; 9801cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey switch (msg.what) { 9811cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey case MSG_SESSION_CREATED: 9821cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey callback.onSessionCreated(sessionId); 9831cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey break; 984ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey case MSG_SESSION_BADGING_CHANGED: 985ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey callback.onSessionBadgingChanged(sessionId); 986ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey break; 987bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey case MSG_SESSION_ACTIVE_CHANGED: 988bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey callback.onSessionActiveChanged(sessionId, (boolean) msg.obj); 9891cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey break; 9901cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey case MSG_SESSION_PROGRESS_CHANGED: 9911cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey callback.onSessionProgressChanged(sessionId, (float) msg.obj); 9921cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey break; 9931cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey case MSG_SESSION_FINISHED: 9941cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey callback.onSessionFinished(sessionId, (boolean) msg.obj); 9951cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey break; 996a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 997a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 9981cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 9991cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private void notifySessionCreated(int sessionId, int userId) { 10001cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey obtainMessage(MSG_SESSION_CREATED, sessionId, userId).sendToTarget(); 10011cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 10021cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 1003ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey private void notifySessionBadgingChanged(int sessionId, int userId) { 1004ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey obtainMessage(MSG_SESSION_BADGING_CHANGED, sessionId, userId).sendToTarget(); 1005ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey } 1006ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey 1007bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey private void notifySessionActiveChanged(int sessionId, int userId, boolean active) { 1008bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey obtainMessage(MSG_SESSION_ACTIVE_CHANGED, sessionId, userId, active).sendToTarget(); 10091cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 10101cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 10111cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private void notifySessionProgressChanged(int sessionId, int userId, float progress) { 10121cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey obtainMessage(MSG_SESSION_PROGRESS_CHANGED, sessionId, userId, progress).sendToTarget(); 10131cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 10141cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 10151cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey public void notifySessionFinished(int sessionId, int userId, boolean success) { 10161cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey obtainMessage(MSG_SESSION_FINISHED, sessionId, userId, success).sendToTarget(); 10171cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 1018a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 1019a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 1020a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey void dump(IndentingPrintWriter pw) { 1021a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey synchronized (mSessions) { 10229a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.println("Active install sessions:"); 10239a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.increaseIndent(); 10249a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey int N = mSessions.size(); 1025a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey for (int i = 0; i < N; i++) { 1026a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey final PackageInstallerSession session = mSessions.valueAt(i); 1027a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey session.dump(pw); 1028a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey pw.println(); 1029a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 10309a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.println(); 10319a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.decreaseIndent(); 10329a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey 10339a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.println("Historical install sessions:"); 10349a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.increaseIndent(); 10359a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey N = mHistoricalSessions.size(); 10369a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey for (int i = 0; i < N; i++) { 10379a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey final PackageInstallerSession session = mHistoricalSessions.valueAt(i); 10389a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey session.dump(pw); 10399a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.println(); 10409a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey } 10419a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.println(); 10429a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.decreaseIndent(); 1043742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 1044742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey pw.println("Legacy install sessions:"); 1045742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey pw.increaseIndent(); 1046742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey pw.println(mLegacySessions.toString()); 1047742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey pw.decreaseIndent(); 1048a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 1049bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey } 1050bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey 10511cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey class InternalCallback { 1052ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey public void onSessionBadgingChanged(PackageInstallerSession session) { 1053ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey mCallbacks.notifySessionBadgingChanged(session.sessionId, session.userId); 1054ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey writeSessionsAsync(); 10551cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 10561cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 1057bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey public void onSessionActiveChanged(PackageInstallerSession session, boolean active) { 1058bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey mCallbacks.notifySessionActiveChanged(session.sessionId, session.userId, active); 1059742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 1060742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 1061ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey public void onSessionProgressChanged(PackageInstallerSession session, float progress) { 1062ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey mCallbacks.notifySessionProgressChanged(session.sessionId, session.userId, progress); 1063ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey } 1064ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey 1065cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey public void onSessionFinished(final PackageInstallerSession session, boolean success) { 10661cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mCallbacks.notifySessionFinished(session.sessionId, session.userId, success); 1067cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey 1068cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey mInstallHandler.post(new Runnable() { 1069cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey @Override 1070cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey public void run() { 1071cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey synchronized (mSessions) { 1072cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey mSessions.remove(session.sessionId); 1073cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey mHistoricalSessions.put(session.sessionId, session); 107402bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey 107502bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey final File appIconFile = buildAppIconFile(session.sessionId); 107602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey if (appIconFile.exists()) { 107702bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey appIconFile.delete(); 107802bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey } 107902bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey 1080cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey writeSessionsLocked(); 1081cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey } 1082cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey } 1083cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey }); 10843a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 1085bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey 108677d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey public void onSessionPrepared(PackageInstallerSession session) { 108777d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey // We prepared the destination to write into; we want to persist 108877d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey // this, but it's not critical enough to block for. 108977d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey writeSessionsAsync(); 109077d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey } 109177d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey 1092cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey public void onSessionSealedBlocking(PackageInstallerSession session) { 1093bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey // It's very important that we block until we've recorded the 1094bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey // session as being sealed, since we never want to allow mutation 1095bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey // after sealing. 1096cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey synchronized (mSessions) { 1097cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey writeSessionsLocked(); 1098cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey } 1099bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey } 11003a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 11013a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey} 1102