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