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