PackageInstallerService.java revision 16c8e3f49497b6046972ae650772f65768366be8
13a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey/* 23a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * Copyright (C) 2014 The Android Open Source Project 33a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * 43a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License"); 53a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * you may not use this file except in compliance with the License. 63a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * You may obtain a copy of the License at 73a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * 83a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * http://www.apache.org/licenses/LICENSE-2.0 93a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * 103a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * Unless required by applicable law or agreed to in writing, software 113a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS, 123a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * See the License for the specific language governing permissions and 143a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * limitations under the License. 153a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey */ 163a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 173a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeypackage com.android.server.pm; 183a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 193a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport static android.content.pm.PackageManager.INSTALL_ALL_USERS; 203a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport static android.content.pm.PackageManager.INSTALL_FROM_ADB; 213a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport static android.content.pm.PackageManager.INSTALL_REPLACE_EXISTING; 223a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 233a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.app.AppOpsManager; 243a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.content.Context; 253a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.content.pm.IPackageDeleteObserver; 263a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.content.pm.IPackageInstaller; 2716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkeyimport android.content.pm.IPackageInstallerCallback; 283a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.content.pm.IPackageInstallerSession; 29bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkeyimport android.content.pm.InstallSessionInfo; 30bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkeyimport android.content.pm.InstallSessionParams; 3116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkeyimport android.content.pm.PackageManager; 323a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.Binder; 333a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.FileUtils; 343a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.HandlerThread; 353a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.Process; 36a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkeyimport android.os.RemoteCallbackList; 37a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkeyimport android.os.RemoteException; 38ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport android.os.SELinux; 393a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.UserHandle; 403a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.UserManager; 41ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport android.system.ErrnoException; 42ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport android.system.Os; 433a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.util.ArraySet; 44a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkeyimport android.util.ExceptionUtils; 453a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.util.Slog; 463a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.util.SparseArray; 473a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 483a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport com.android.internal.annotations.GuardedBy; 49a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkeyimport com.android.internal.util.IndentingPrintWriter; 503a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport com.android.server.IoThread; 513a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport com.google.android.collect.Sets; 523a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 533a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport java.io.File; 54ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport java.io.FilenameFilter; 55ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport java.io.IOException; 56bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkeyimport java.util.ArrayList; 57bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkeyimport java.util.List; 5816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkeyimport java.util.Objects; 593a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 603a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeypublic class PackageInstallerService extends IPackageInstaller.Stub { 613a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private static final String TAG = "PackageInstaller"; 623a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 633a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey // TODO: destroy sessions with old timestamps 643a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey // TODO: remove outstanding sessions when installer package goes away 656c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey // TODO: notify listeners in other users when package has been installed there 663a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 673a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private final Context mContext; 683a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private final PackageManagerService mPm; 693a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private final AppOpsManager mAppOps; 703a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 713a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private final File mStagingDir; 72ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey private final HandlerThread mInstallThread; 733a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 743a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private final Callback mCallback = new Callback(); 753a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 763a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey @GuardedBy("mSessions") 773a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private int mNextSessionId; 783a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey @GuardedBy("mSessions") 793a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>(); 803a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 819a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey /** Historical sessions kept around for debugging purposes */ 829a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey @GuardedBy("mSessions") 839a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey private final SparseArray<PackageInstallerSession> mHistoricalSessions = new SparseArray<>(); 849a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey 8516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey private RemoteCallbackList<IPackageInstallerCallback> mCallbacks = new RemoteCallbackList<>(); 86a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 87ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey private static final FilenameFilter sStageFilter = new FilenameFilter() { 88ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey @Override 89ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey public boolean accept(File dir, String name) { 90ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey return name.startsWith("vmdl") && name.endsWith(".tmp"); 91ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 92ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey }; 93ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 943a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey public PackageInstallerService(Context context, PackageManagerService pm, File stagingDir) { 953a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey mContext = context; 963a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey mPm = pm; 973a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); 983a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 993a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey mStagingDir = stagingDir; 100ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 101ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey mInstallThread = new HandlerThread(TAG); 102ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey mInstallThread.start(); 1033a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1043a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey synchronized (mSessions) { 1053a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey readSessionsLocked(); 1063a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1073a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey // Clean up orphaned staging directories 108ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey final ArraySet<File> stages = Sets.newArraySet(mStagingDir.listFiles(sStageFilter)); 1093a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey for (int i = 0; i < mSessions.size(); i++) { 110ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey final PackageInstallerSession session = mSessions.valueAt(i); 111ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey stages.remove(session.sessionStageDir); 112ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 113ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey for (File stage : stages) { 114ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey Slog.w(TAG, "Deleting orphan stage " + stage); 115ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey if (stage.isDirectory()) { 116ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey FileUtils.deleteContents(stage); 117ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 118ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey stage.delete(); 1193a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 120ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 121ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 122ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 123ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey @Deprecated 124ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey public File allocateSessionDir() throws IOException { 125ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey synchronized (mSessions) { 126ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey try { 127ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey final int sessionId = allocateSessionIdLocked(); 128ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey return prepareSessionStageDir(sessionId); 129ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } catch (IllegalStateException e) { 130ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey throw new IOException(e); 1313a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 1323a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 1333a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 1343a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1353a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private void readSessionsLocked() { 1363a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey // TODO: implement persisting 1373a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey mSessions.clear(); 1383a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey mNextSessionId = 1; 1393a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 1403a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1413a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private void writeSessionsLocked() { 1423a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey // TODO: implement persisting 1433a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 1443a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1453a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private void writeSessionsAsync() { 1463a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey IoThread.getHandler().post(new Runnable() { 1473a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey @Override 1483a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey public void run() { 1493a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey synchronized (mSessions) { 1503a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey writeSessionsLocked(); 1513a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 1523a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 1533a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey }); 1543a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 1553a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1563a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey @Override 15716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public int createSession(InstallSessionParams params, String installerPackageName, int userId) { 1583a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey final int callingUid = Binder.getCallingUid(); 159a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey mPm.enforceCrossUserPermission(callingUid, userId, true, "createSession"); 1603a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1613a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey if (mPm.isUserRestricted(UserHandle.getUserId(callingUid), 1623a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey UserManager.DISALLOW_INSTALL_APPS)) { 1633a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey throw new SecurityException("User restriction prevents installing"); 1643a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 1653a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1663a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey if ((callingUid == Process.SHELL_UID) || (callingUid == 0)) { 1673a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey params.installFlags |= INSTALL_FROM_ADB; 1683a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } else { 169ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey mAppOps.checkPackage(callingUid, installerPackageName); 170ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 1713a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey params.installFlags &= ~INSTALL_FROM_ADB; 1723a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey params.installFlags &= ~INSTALL_ALL_USERS; 1733a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey params.installFlags |= INSTALL_REPLACE_EXISTING; 1743a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 1753a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 17616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey switch (params.mode) { 17716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey case InstallSessionParams.MODE_FULL_INSTALL: 17816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey case InstallSessionParams.MODE_INHERIT_EXISTING: 17916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey break; 18016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey default: 18116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey throw new IllegalArgumentException("Params must have valid mode set"); 1826c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey } 1836c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey 184a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey // Sanity check that install could fit 18516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey if (params.sizeBytes > 0) { 186a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey try { 18716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey mPm.freeStorage(params.sizeBytes); 188a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } catch (IOException e) { 189a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey throw ExceptionUtils.wrap(e); 190a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 191a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 192a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 193a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey final int sessionId; 194a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey final PackageInstallerSession session; 1953a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey synchronized (mSessions) { 196a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey sessionId = allocateSessionIdLocked(); 197a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 1983a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey final long createdMillis = System.currentTimeMillis(); 199ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey final File sessionStageDir = prepareSessionStageDir(sessionId); 2003a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 201a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey session = new PackageInstallerSession(mCallback, mPm, sessionId, userId, 202a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey installerPackageName, callingUid, params, createdMillis, sessionStageDir, 203a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey mInstallThread.getLooper()); 2043a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey mSessions.put(sessionId, session); 2053a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 206a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 207a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey notifySessionCreated(session.generateInfo()); 208a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey writeSessionsAsync(); 209a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey return sessionId; 2103a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 2113a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 2123a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey @Override 2133a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey public IPackageInstallerSession openSession(int sessionId) { 2143a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey synchronized (mSessions) { 2153a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey final PackageInstallerSession session = mSessions.get(sessionId); 2163a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey if (session == null) { 2173a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey throw new IllegalStateException("Missing session " + sessionId); 2183a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 2193a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey if (Binder.getCallingUid() != session.installerUid) { 2203a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey throw new SecurityException("Caller has no access to session " + sessionId); 2213a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 2223a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey return session; 2233a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 2243a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 2253a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 2263a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private int allocateSessionIdLocked() { 2273a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey if (mSessions.get(mNextSessionId) != null) { 2283a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey throw new IllegalStateException("Next session already allocated"); 2293a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 2303a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey return mNextSessionId++; 2313a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 2323a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 233ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey private File prepareSessionStageDir(int sessionId) { 234ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey final File file = new File(mStagingDir, "vmdl" + sessionId + ".tmp"); 235ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 236ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey if (file.exists()) { 237ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey throw new IllegalStateException(); 238ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 239ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 240ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey try { 241ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey Os.mkdir(file.getAbsolutePath(), 0755); 242ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey Os.chmod(file.getAbsolutePath(), 0755); 243ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } catch (ErrnoException e) { 244ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey // This purposefully throws if directory already exists 245ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey throw new IllegalStateException("Failed to prepare session dir", e); 246ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 247ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 248ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey if (!SELinux.restorecon(file)) { 249ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey throw new IllegalStateException("Failed to prepare session dir"); 250ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 251ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 252ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey return file; 253ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey } 254ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey 2553a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey @Override 25616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public InstallSessionInfo getSessionInfo(int sessionId) { 25716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey synchronized (mSessions) { 25816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey final PackageInstallerSession session = mSessions.get(sessionId); 25916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey final boolean isOwner = (session != null) 26016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey && (session.installerUid == Binder.getCallingUid()); 26116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey if (!isOwner) { 26216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey enforceCallerCanReadSessions(); 26316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 26416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey return session != null ? session.generateInfo() : null; 26516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 26616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 26716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey 26816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey @Override 26916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public List<InstallSessionInfo> getAllSessions(int userId) { 27016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "getAllSessions"); 27116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey enforceCallerCanReadSessions(); 2723a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 273bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey final List<InstallSessionInfo> result = new ArrayList<>(); 2743a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey synchronized (mSessions) { 2753a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey for (int i = 0; i < mSessions.size(); i++) { 2763a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey final PackageInstallerSession session = mSessions.valueAt(i); 277bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey if (session.userId == userId) { 278bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey result.add(session.generateInfo()); 2793a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 2803a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 2813a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 282bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey return result; 2833a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 2843a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 2853a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey @Override 28616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public List<InstallSessionInfo> getMySessions(String installerPackageName, int userId) { 28716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "getMySessions"); 28816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey mAppOps.checkPackage(Binder.getCallingUid(), installerPackageName); 28916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey 29016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey final List<InstallSessionInfo> result = new ArrayList<>(); 29116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey synchronized (mSessions) { 29216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey for (int i = 0; i < mSessions.size(); i++) { 29316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey final PackageInstallerSession session = mSessions.valueAt(i); 29416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey if (Objects.equals(session.installerPackageName, installerPackageName) 29516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey && session.userId == userId) { 29616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey result.add(session.generateInfo()); 29716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 29816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 29916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 30016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey return result; 30116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 30216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey 30316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey @Override 304bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey public void uninstall(String packageName, int flags, IPackageDeleteObserver observer, 305ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey int userId) { 306a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "uninstall"); 30716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey 30816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey // TODO: enforce installer of record or permission 309bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey mPm.deletePackageAsUser(packageName, observer, userId, flags); 3103a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 3113a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 3123a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey @Override 313ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey public void uninstallSplit(String basePackageName, String overlayName, int flags, 314ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey IPackageDeleteObserver observer, int userId) { 315a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "uninstallSplit"); 316a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 3173a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey // TODO: flesh out once PM has split support 3183a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey throw new UnsupportedOperationException(); 3193a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 3203a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 321bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey @Override 32216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public void registerCallback(IPackageInstallerCallback callback, int userId) { 32316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "registerCallback"); 32416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey enforceCallerCanReadSessions(); 325a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 32616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey mCallbacks.register(callback, new UserHandle(userId)); 327bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey } 328bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey 329bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey @Override 33016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public void unregisterCallback(IPackageInstallerCallback callback) { 33116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey mCallbacks.unregister(callback); 332a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 333a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 334a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey private int getSessionUserId(int sessionId) { 335a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey synchronized (mSessions) { 336a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey return UserHandle.getUserId(mSessions.get(sessionId).installerUid); 337a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 338a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 339a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 34016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey /** 34116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * We allow those with permission, or the current home app. 34216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey */ 34316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey private void enforceCallerCanReadSessions() { 34416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey final boolean hasPermission = (mContext.checkCallingOrSelfPermission( 34516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey android.Manifest.permission.READ_INSTALL_SESSIONS) 34616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey == PackageManager.PERMISSION_GRANTED); 34716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey final boolean isHomeApp = mPm.checkCallerIsHomeApp(); 34816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey if (hasPermission || isHomeApp) { 34916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey return; 35016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } else { 35116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey throw new SecurityException("Caller must be current home app to read install sessions"); 35216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 35316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 35416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey 355a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey private void notifySessionCreated(InstallSessionInfo info) { 356a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey final int userId = getSessionUserId(info.sessionId); 35716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey final int n = mCallbacks.beginBroadcast(); 358a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey for (int i = 0; i < n; i++) { 35916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey final IPackageInstallerCallback callback = mCallbacks.getBroadcastItem(i); 36016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey final UserHandle user = (UserHandle) mCallbacks.getBroadcastCookie(i); 36116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey // TODO: dispatch notifications for slave profiles 362a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey if (userId == user.getIdentifier()) { 363a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey try { 36416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey callback.onSessionCreated(info.sessionId); 365a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } catch (RemoteException ignored) { 366a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 367a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 368a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 36916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey mCallbacks.finishBroadcast(); 370a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 371a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 37216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey private void notifySessionProgressChanged(int sessionId, float progress) { 373a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey final int userId = getSessionUserId(sessionId); 37416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey final int n = mCallbacks.beginBroadcast(); 375a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey for (int i = 0; i < n; i++) { 37616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey final IPackageInstallerCallback callback = mCallbacks.getBroadcastItem(i); 37716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey final UserHandle user = (UserHandle) mCallbacks.getBroadcastCookie(i); 378a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey if (userId == user.getIdentifier()) { 379a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey try { 38016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey callback.onSessionProgressChanged(sessionId, progress); 381a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } catch (RemoteException ignored) { 382a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 383a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 384a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 38516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey mCallbacks.finishBroadcast(); 386a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 387a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 388a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey private void notifySessionFinished(int sessionId, boolean success) { 389a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey final int userId = getSessionUserId(sessionId); 39016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey final int n = mCallbacks.beginBroadcast(); 391a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey for (int i = 0; i < n; i++) { 39216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey final IPackageInstallerCallback callback = mCallbacks.getBroadcastItem(i); 39316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey final UserHandle user = (UserHandle) mCallbacks.getBroadcastCookie(i); 394a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey if (userId == user.getIdentifier()) { 395a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey try { 39616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey callback.onSessionFinished(sessionId, success); 397a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } catch (RemoteException ignored) { 398a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 399a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 400a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 40116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey mCallbacks.finishBroadcast(); 402a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 403a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 404a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey void dump(IndentingPrintWriter pw) { 405a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey synchronized (mSessions) { 4069a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.println("Active install sessions:"); 4079a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.increaseIndent(); 4089a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey int N = mSessions.size(); 409a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey for (int i = 0; i < N; i++) { 410a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey final PackageInstallerSession session = mSessions.valueAt(i); 411a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey session.dump(pw); 412a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey pw.println(); 413a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 4149a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.println(); 4159a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.decreaseIndent(); 4169a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey 4179a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.println("Historical install sessions:"); 4189a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.increaseIndent(); 4199a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey N = mHistoricalSessions.size(); 4209a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey for (int i = 0; i < N; i++) { 4219a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey final PackageInstallerSession session = mHistoricalSessions.valueAt(i); 4229a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey session.dump(pw); 4239a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.println(); 4249a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey } 4259a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.println(); 4269a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey pw.decreaseIndent(); 427a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 428bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey } 429bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey 4303a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey class Callback { 43116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public void onSessionProgressChanged(PackageInstallerSession session, float progress) { 43216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey notifySessionProgressChanged(session.sessionId, progress); 4333a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 4343a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 435a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey public void onSessionFinished(PackageInstallerSession session, boolean success) { 436a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey notifySessionFinished(session.sessionId, success); 437a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey synchronized (mSessions) { 438a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey mSessions.remove(session.sessionId); 4399a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey mHistoricalSessions.put(session.sessionId, session); 440a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 4413a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey writeSessionsAsync(); 4423a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 4433a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 4443a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey} 445