13a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey/*
23a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * Copyright (C) 2014 The Android Open Source Project
33a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey *
43a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License");
53a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * you may not use this file except in compliance with the License.
63a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * You may obtain a copy of the License at
73a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey *
83a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey *      http://www.apache.org/licenses/LICENSE-2.0
93a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey *
103a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * Unless required by applicable law or agreed to in writing, software
113a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS,
123a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * See the License for the specific language governing permissions and
143a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * limitations under the License.
153a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey */
163a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
173a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeypackage com.android.server.pm;
183a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
191cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.readBitmapAttribute;
201cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.readBooleanAttribute;
211cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.readIntAttribute;
221cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.readLongAttribute;
231cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.readStringAttribute;
241cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.readUriAttribute;
251cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.writeBooleanAttribute;
261cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.writeIntAttribute;
271cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.writeLongAttribute;
281cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.writeStringAttribute;
291cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static com.android.internal.util.XmlUtils.writeUriAttribute;
301cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
311cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static org.xmlpull.v1.XmlPullParser.START_TAG;
321cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
331cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.app.ActivityManager;
343a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.app.AppOpsManager;
35a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.app.PackageDeleteObserver;
36a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.app.PackageInstallObserver;
373a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.content.Context;
38f06009542390472872da986486d385001e91a2a7Jeff Sharkeyimport android.content.Intent;
39a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.content.IntentSender;
40a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.content.IntentSender.SendIntentException;
413a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.content.pm.IPackageInstaller;
4216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkeyimport android.content.pm.IPackageInstallerCallback;
433a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.content.pm.IPackageInstallerSession;
44f06009542390472872da986486d385001e91a2a7Jeff Sharkeyimport android.content.pm.PackageInstaller;
45a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.content.pm.PackageInstaller.SessionInfo;
46a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.content.pm.PackageInstaller.SessionParams;
47ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkeyimport android.content.pm.PackageManager;
4897d47ed036ff7bd3d7d2ddc1c6df1104ec237559Jeff Sharkeyimport android.content.pm.ParceledListSlice;
491cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.graphics.Bitmap;
5002bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkeyimport android.graphics.Bitmap.CompressFormat;
5102bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkeyimport android.graphics.BitmapFactory;
52f06009542390472872da986486d385001e91a2a7Jeff Sharkeyimport android.net.Uri;
533a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.Binder;
54a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.os.Bundle;
551cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.os.Environment;
563a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.FileUtils;
571cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.os.Handler;
583a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.HandlerThread;
591cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.os.Looper;
601cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.os.Message;
613a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.Process;
62a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkeyimport android.os.RemoteCallbackList;
63a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkeyimport android.os.RemoteException;
64ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport android.os.SELinux;
653a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.UserHandle;
663a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.UserManager;
67ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport android.system.ErrnoException;
68ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport android.system.Os;
69a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.text.TextUtils;
701cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.text.format.DateUtils;
713a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.util.ArraySet;
721cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.util.AtomicFile;
73a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkeyimport android.util.ExceptionUtils;
743a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.util.Slog;
753a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.util.SparseArray;
76742e790294b3441b79f715fe447069b63c6065dbJeff Sharkeyimport android.util.SparseBooleanArray;
771cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.util.Xml;
783a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
793a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport com.android.internal.annotations.GuardedBy;
80742e790294b3441b79f715fe447069b63c6065dbJeff Sharkeyimport com.android.internal.content.PackageHelper;
811cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport com.android.internal.util.FastXmlSerializer;
82a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkeyimport com.android.internal.util.IndentingPrintWriter;
833a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport com.android.server.IoThread;
843a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport com.google.android.collect.Sets;
853a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
861cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport libcore.io.IoUtils;
871cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
881cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport org.xmlpull.v1.XmlPullParser;
891cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport org.xmlpull.v1.XmlPullParserException;
901cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport org.xmlpull.v1.XmlSerializer;
911cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
923a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport java.io.File;
931cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport java.io.FileInputStream;
941cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport java.io.FileNotFoundException;
951cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport java.io.FileOutputStream;
96ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport java.io.FilenameFilter;
97ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport java.io.IOException;
981cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport java.security.SecureRandom;
99bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkeyimport java.util.ArrayList;
100bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkeyimport java.util.List;
10116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkeyimport java.util.Objects;
1021cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport java.util.Random;
1033a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1043a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeypublic class PackageInstallerService extends IPackageInstaller.Stub {
1053a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private static final String TAG = "PackageInstaller";
106e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey    private static final boolean LOGD = false;
1073a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1083a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    // TODO: remove outstanding sessions when installer package goes away
1096c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey    // TODO: notify listeners in other users when package has been installed there
110742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    // TODO: purge expired sessions periodically in addition to at reboot
1113a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1121cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    /** XML constants used in {@link #mSessionsFile} */
1131cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String TAG_SESSIONS = "sessions";
1141cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String TAG_SESSION = "session";
1151cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_SESSION_ID = "sessionId";
1161cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_USER_ID = "userId";
1171cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_INSTALLER_PACKAGE_NAME = "installerPackageName";
118e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey    private static final String ATTR_INSTALLER_UID = "installerUid";
1191cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_CREATED_MILLIS = "createdMillis";
1201cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_SESSION_STAGE_DIR = "sessionStageDir";
121742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    private static final String ATTR_SESSION_STAGE_CID = "sessionStageCid";
12277d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey    private static final String ATTR_PREPARED = "prepared";
1231cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_SEALED = "sealed";
1241cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_MODE = "mode";
1251cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_INSTALL_FLAGS = "installFlags";
1261cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_INSTALL_LOCATION = "installLocation";
1271cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_SIZE_BYTES = "sizeBytes";
1281cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_APP_PACKAGE_NAME = "appPackageName";
12902bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey    @Deprecated
1301cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_APP_ICON = "appIcon";
1311cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_APP_LABEL = "appLabel";
1321cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_ORIGINATING_URI = "originatingUri";
1331cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_REFERRER_URI = "referrerUri";
1341cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final String ATTR_ABI_OVERRIDE = "abiOverride";
1351cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
136f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey    /** Automatically destroy sessions older than this */
1371cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final long MAX_AGE_MILLIS = 3 * DateUtils.DAY_IN_MILLIS;
138f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey    /** Upper bound on number of active sessions for a UID */
1391cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final long MAX_ACTIVE_SESSIONS = 1024;
140f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey    /** Upper bound on number of historical sessions for a UID */
141f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey    private static final long MAX_HISTORICAL_SESSIONS = 1048576;
1421cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
1433a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private final Context mContext;
1443a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private final PackageManagerService mPm;
1453a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private final AppOpsManager mAppOps;
1463a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1473a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private final File mStagingDir;
148ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey    private final HandlerThread mInstallThread;
149cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey    private final Handler mInstallHandler;
1503a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1511cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private final Callbacks mCallbacks;
1521cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
1531cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    /**
15402bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey     * File storing persisted {@link #mSessions} metadata.
1551cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey     */
1561cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private final AtomicFile mSessionsFile;
1571cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
15802bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey    /**
15902bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey     * Directory storing persisted {@link #mSessions} metadata which is too
16002bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey     * heavy to store directly in {@link #mSessionsFile}.
16102bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey     */
16202bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey    private final File mSessionsDir;
16302bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey
1641cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private final InternalCallback mInternalCallback = new InternalCallback();
1651cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
1661cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    /**
1671cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey     * Used for generating session IDs. Since this is created at boot time,
1681cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey     * normal random might be predictable.
1691cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey     */
1701cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private final Random mRandom = new SecureRandom();
1713a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1723a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    @GuardedBy("mSessions")
1733a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>();
1743a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1759a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey    /** Historical sessions kept around for debugging purposes */
1769a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey    @GuardedBy("mSessions")
1779a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey    private final SparseArray<PackageInstallerSession> mHistoricalSessions = new SparseArray<>();
1789a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey
179742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    /** Sessions allocated to legacy users */
180742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    @GuardedBy("mSessions")
181742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    private final SparseBooleanArray mLegacySessions = new SparseBooleanArray();
182742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
183ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey    private static final FilenameFilter sStageFilter = new FilenameFilter() {
184ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        @Override
185ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        public boolean accept(File dir, String name) {
186742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            return isStageName(name);
187ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        }
188ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey    };
189ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey
1903a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    public PackageInstallerService(Context context, PackageManagerService pm, File stagingDir) {
1913a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        mContext = context;
1923a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        mPm = pm;
1933a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
1943a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1953a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        mStagingDir = stagingDir;
196ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey
197ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        mInstallThread = new HandlerThread(TAG);
198ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        mInstallThread.start();
1993a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
200cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey        mInstallHandler = new Handler(mInstallThread.getLooper());
201cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey
2021cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        mCallbacks = new Callbacks(mInstallThread.getLooper());
2031cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
2041cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        mSessionsFile = new AtomicFile(
2051cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                new File(Environment.getSystemSecureDirectory(), "install_sessions.xml"));
20602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey        mSessionsDir = new File(Environment.getSystemSecureDirectory(), "install_sessions");
20702bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey        mSessionsDir.mkdirs();
2081cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
2093a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        synchronized (mSessions) {
2103a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            readSessionsLocked();
2113a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
21202bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            final ArraySet<File> unclaimedStages = Sets.newArraySet(
21302bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                    mStagingDir.listFiles(sStageFilter));
21402bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            final ArraySet<File> unclaimedIcons = Sets.newArraySet(
21502bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                    mSessionsDir.listFiles());
216742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
21702bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            // Ignore stages and icons claimed by active sessions
2183a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            for (int i = 0; i < mSessions.size(); i++) {
219ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey                final PackageInstallerSession session = mSessions.valueAt(i);
22002bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                unclaimedStages.remove(session.stageDir);
22102bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                unclaimedIcons.remove(buildAppIconFile(session.sessionId));
222ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey            }
223742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
224742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            // Clean up orphaned staging directories
22502bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            for (File stage : unclaimedStages) {
226ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey                Slog.w(TAG, "Deleting orphan stage " + stage);
227ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey                if (stage.isDirectory()) {
228ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey                    FileUtils.deleteContents(stage);
229ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey                }
230ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey                stage.delete();
2313a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
23202bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey
23302bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            // Clean up orphaned icons
23402bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            for (File icon : unclaimedIcons) {
23502bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                Slog.w(TAG, "Deleting orphan icon " + icon);
23602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                icon.delete();
23702bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            }
238ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        }
239ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey    }
240ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey
241742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    public void onSecureContainersAvailable() {
242742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        synchronized (mSessions) {
243742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            final ArraySet<String> unclaimed = new ArraySet<>();
244742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            for (String cid : PackageHelper.getSecureContainerList()) {
245742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                if (isStageName(cid)) {
246742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                    unclaimed.add(cid);
247742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                }
248742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            }
249742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
250742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            // Ignore stages claimed by active sessions
251742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            for (int i = 0; i < mSessions.size(); i++) {
252742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                final PackageInstallerSession session = mSessions.valueAt(i);
253941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                final String cid = session.stageCid;
254742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
255742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                if (unclaimed.remove(cid)) {
256742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                    // Claimed by active session, mount it
257742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                    PackageHelper.mountSdDir(cid, PackageManagerService.getEncryptKey(),
258742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                            Process.SYSTEM_UID);
259742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                }
260742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            }
261742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
262742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            // Clean up orphaned staging containers
263742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            for (String cid : unclaimed) {
264742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                Slog.w(TAG, "Deleting orphan container " + cid);
265742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                PackageHelper.destroySdDir(cid);
266742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            }
267742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        }
268742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    }
269742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
270742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    public static boolean isStageName(String name) {
271742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        final boolean isFile = name.startsWith("vmdl") && name.endsWith(".tmp");
272742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        final boolean isContainer = name.startsWith("smdl") && name.endsWith(".tmp");
273742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        final boolean isLegacyContainer = name.startsWith("smdl2tmp");
274742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        return isFile || isContainer || isLegacyContainer;
2757328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey    }
2767328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey
277ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey    @Deprecated
278742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    public File allocateInternalStageDirLegacy() throws IOException {
279ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        synchronized (mSessions) {
280ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey            try {
281ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey                final int sessionId = allocateSessionIdLocked();
282742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                mLegacySessions.put(sessionId, true);
28377d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey                final File stageDir = buildInternalStageDir(sessionId);
28477d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey                prepareInternalStageDir(stageDir);
28577d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey                return stageDir;
286ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey            } catch (IllegalStateException e) {
287ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey                throw new IOException(e);
2883a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
2893a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
2903a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
2913a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
292742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    @Deprecated
293742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    public String allocateExternalStageCidLegacy() {
294742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        synchronized (mSessions) {
295742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            final int sessionId = allocateSessionIdLocked();
296742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            mLegacySessions.put(sessionId, true);
297742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            return "smdl" + sessionId + ".tmp";
298742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        }
299742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    }
300742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
3013a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private void readSessionsLocked() {
3021cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        if (LOGD) Slog.v(TAG, "readSessionsLocked()");
3031cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
3043a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        mSessions.clear();
3051cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
3061cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        FileInputStream fis = null;
3071cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        try {
3081cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            fis = mSessionsFile.openRead();
3091cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            final XmlPullParser in = Xml.newPullParser();
3101cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            in.setInput(fis, null);
3111cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
3121cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            int type;
3131cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            while ((type = in.next()) != END_DOCUMENT) {
3141cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                if (type == START_TAG) {
3151cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    final String tag = in.getName();
3161cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    if (TAG_SESSION.equals(tag)) {
3171cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                        final PackageInstallerSession session = readSessionLocked(in);
3181cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                        final long age = System.currentTimeMillis() - session.createdMillis;
3191cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
3201cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                        final boolean valid;
3211cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                        if (age >= MAX_AGE_MILLIS) {
3221cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                            Slog.w(TAG, "Abandoning old session first created at "
3231cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                                    + session.createdMillis);
3241cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                            valid = false;
325941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                        } else if (session.stageDir != null
326941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                                && !session.stageDir.exists()) {
327742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                            Slog.w(TAG, "Abandoning internal session with missing stage "
328941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                                    + session.stageDir);
3291cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                            valid = false;
3301cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                        } else {
3311cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                            valid = true;
3321cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                        }
3331cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
3341cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                        if (valid) {
3351cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                            mSessions.put(session.sessionId, session);
3361cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                        } else {
3371cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                            // Since this is early during boot we don't send
3381cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                            // any observer events about the session, but we
3391cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                            // keep details around for dumpsys.
3401cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                            mHistoricalSessions.put(session.sessionId, session);
3411cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                        }
3421cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    }
3431cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                }
3441cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            }
3451cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        } catch (FileNotFoundException e) {
3461cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            // Missing sessions are okay, probably first boot
3471cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        } catch (IOException e) {
3488d05172112436a81bed6e4a0810f8914509d8a4dDianne Hackborn            Slog.wtf(TAG, "Failed reading install sessions", e);
3491cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        } catch (XmlPullParserException e) {
3508d05172112436a81bed6e4a0810f8914509d8a4dDianne Hackborn            Slog.wtf(TAG, "Failed reading install sessions", e);
3511cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        } finally {
3521cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            IoUtils.closeQuietly(fis);
3531cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        }
3541cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    }
3551cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
3561cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private PackageInstallerSession readSessionLocked(XmlPullParser in) throws IOException {
3571cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        final int sessionId = readIntAttribute(in, ATTR_SESSION_ID);
3581cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        final int userId = readIntAttribute(in, ATTR_USER_ID);
3591cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        final String installerPackageName = readStringAttribute(in, ATTR_INSTALLER_PACKAGE_NAME);
360e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey        final int installerUid = readIntAttribute(in, ATTR_INSTALLER_UID,
361e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey                mPm.getPackageUid(installerPackageName, userId));
3621cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        final long createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS);
363742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        final String stageDirRaw = readStringAttribute(in, ATTR_SESSION_STAGE_DIR);
364742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        final File stageDir = (stageDirRaw != null) ? new File(stageDirRaw) : null;
365742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        final String stageCid = readStringAttribute(in, ATTR_SESSION_STAGE_CID);
36677d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        final boolean prepared = readBooleanAttribute(in, ATTR_PREPARED, true);
3671cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        final boolean sealed = readBooleanAttribute(in, ATTR_SEALED);
3681cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
369a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        final SessionParams params = new SessionParams(
370a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                SessionParams.MODE_INVALID);
3711cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        params.mode = readIntAttribute(in, ATTR_MODE);
3721cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        params.installFlags = readIntAttribute(in, ATTR_INSTALL_FLAGS);
3731cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        params.installLocation = readIntAttribute(in, ATTR_INSTALL_LOCATION);
3741cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        params.sizeBytes = readLongAttribute(in, ATTR_SIZE_BYTES);
3751cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        params.appPackageName = readStringAttribute(in, ATTR_APP_PACKAGE_NAME);
3761cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        params.appIcon = readBitmapAttribute(in, ATTR_APP_ICON);
3771cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        params.appLabel = readStringAttribute(in, ATTR_APP_LABEL);
3781cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        params.originatingUri = readUriAttribute(in, ATTR_ORIGINATING_URI);
3791cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        params.referrerUri = readUriAttribute(in, ATTR_REFERRER_URI);
3801cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        params.abiOverride = readStringAttribute(in, ATTR_ABI_OVERRIDE);
3811cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
38202bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey        final File appIconFile = buildAppIconFile(sessionId);
38302bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey        if (appIconFile.exists()) {
38402bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            params.appIcon = BitmapFactory.decodeFile(appIconFile.getAbsolutePath());
38502bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            params.appIconLastModified = appIconFile.lastModified();
38602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey        }
38702bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey
388a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        return new PackageInstallerSession(mInternalCallback, mContext, mPm,
389e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey                mInstallThread.getLooper(), sessionId, userId, installerPackageName, installerUid,
390e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey                params, createdMillis, stageDir, stageCid, prepared, sealed);
3913a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
3923a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
3933a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private void writeSessionsLocked() {
3941cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        if (LOGD) Slog.v(TAG, "writeSessionsLocked()");
3951cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
3961cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        FileOutputStream fos = null;
3971cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        try {
3981cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            fos = mSessionsFile.startWrite();
3991cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
4001cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            XmlSerializer out = new FastXmlSerializer();
4011cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            out.setOutput(fos, "utf-8");
4021cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            out.startDocument(null, true);
4031cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            out.startTag(null, TAG_SESSIONS);
4041cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            final int size = mSessions.size();
4051cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            for (int i = 0; i < size; i++) {
4061cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                final PackageInstallerSession session = mSessions.valueAt(i);
4071cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                writeSessionLocked(out, session);
4081cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            }
4091cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            out.endTag(null, TAG_SESSIONS);
4101cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            out.endDocument();
4111cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
4121cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            mSessionsFile.finishWrite(fos);
4131cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        } catch (IOException e) {
4141cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            if (fos != null) {
4151cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                mSessionsFile.failWrite(fos);
4161cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            }
4171cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        }
4181cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    }
4191cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
4201cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private void writeSessionLocked(XmlSerializer out, PackageInstallerSession session)
4211cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            throws IOException {
422a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        final SessionParams params = session.params;
4231cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
4241cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        out.startTag(null, TAG_SESSION);
4251cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
4261cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        writeIntAttribute(out, ATTR_SESSION_ID, session.sessionId);
4271cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        writeIntAttribute(out, ATTR_USER_ID, session.userId);
4281cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        writeStringAttribute(out, ATTR_INSTALLER_PACKAGE_NAME,
4291cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                session.installerPackageName);
430e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey        writeIntAttribute(out, ATTR_INSTALLER_UID, session.installerUid);
4311cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        writeLongAttribute(out, ATTR_CREATED_MILLIS, session.createdMillis);
432941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        if (session.stageDir != null) {
433742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            writeStringAttribute(out, ATTR_SESSION_STAGE_DIR,
434941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                    session.stageDir.getAbsolutePath());
435742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        }
436941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        if (session.stageCid != null) {
437941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            writeStringAttribute(out, ATTR_SESSION_STAGE_CID, session.stageCid);
438742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        }
43977d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        writeBooleanAttribute(out, ATTR_PREPARED, session.isPrepared());
440742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        writeBooleanAttribute(out, ATTR_SEALED, session.isSealed());
4411cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
4421cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        writeIntAttribute(out, ATTR_MODE, params.mode);
4431cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        writeIntAttribute(out, ATTR_INSTALL_FLAGS, params.installFlags);
4441cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        writeIntAttribute(out, ATTR_INSTALL_LOCATION, params.installLocation);
4451cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        writeLongAttribute(out, ATTR_SIZE_BYTES, params.sizeBytes);
4461cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        writeStringAttribute(out, ATTR_APP_PACKAGE_NAME, params.appPackageName);
4471cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        writeStringAttribute(out, ATTR_APP_LABEL, params.appLabel);
4481cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        writeUriAttribute(out, ATTR_ORIGINATING_URI, params.originatingUri);
4491cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        writeUriAttribute(out, ATTR_REFERRER_URI, params.referrerUri);
4501cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        writeStringAttribute(out, ATTR_ABI_OVERRIDE, params.abiOverride);
4511cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
45202bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey        // Persist app icon if changed since last written
45302bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey        final File appIconFile = buildAppIconFile(session.sessionId);
45402bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey        if (params.appIcon == null && appIconFile.exists()) {
45502bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            appIconFile.delete();
45602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey        } else if (params.appIcon != null
45702bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                && appIconFile.lastModified() != params.appIconLastModified) {
45802bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            if (LOGD) Slog.w(TAG, "Writing changed icon " + appIconFile);
45902bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            FileOutputStream os = null;
46002bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            try {
46102bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                os = new FileOutputStream(appIconFile);
46202bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                params.appIcon.compress(CompressFormat.PNG, 90, os);
46302bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            } catch (IOException e) {
46402bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                Slog.w(TAG, "Failed to write icon " + appIconFile + ": " + e.getMessage());
46502bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            } finally {
46602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                IoUtils.closeQuietly(os);
46702bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            }
46802bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey
46902bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            params.appIconLastModified = appIconFile.lastModified();
47002bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey        }
47102bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey
4721cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        out.endTag(null, TAG_SESSION);
4733a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
4743a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
47502bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey    private File buildAppIconFile(int sessionId) {
47602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey        return new File(mSessionsDir, "app_icon." + sessionId + ".png");
47702bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey    }
47802bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey
4793a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private void writeSessionsAsync() {
4803a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        IoThread.getHandler().post(new Runnable() {
4813a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            @Override
4823a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            public void run() {
4833a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                synchronized (mSessions) {
4843a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                    writeSessionsLocked();
4853a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                }
4863a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
4873a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        });
4883a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
4893a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
4903a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    @Override
491a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey    public int createSession(SessionParams params, String installerPackageName, int userId) {
492742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        try {
493742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            return createSessionInternal(params, installerPackageName, userId);
494742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        } catch (IOException e) {
495742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            throw ExceptionUtils.wrap(e);
496742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        }
497742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    }
498742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
499742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    private int createSessionInternal(SessionParams params, String installerPackageName, int userId)
500742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            throws IOException {
5013a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        final int callingUid = Binder.getCallingUid();
502e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey        mPm.enforceCrossUserPermission(callingUid, userId, true, true, "createSession");
5033a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
504e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey        if (mPm.isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
5053a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            throw new SecurityException("User restriction prevents installing");
5063a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
5073a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
5081cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {
509e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey            params.installFlags |= PackageManager.INSTALL_FROM_ADB;
5101cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
5113a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        } else {
512ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey            mAppOps.checkPackage(callingUid, installerPackageName);
513ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey
514e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey            params.installFlags &= ~PackageManager.INSTALL_FROM_ADB;
515e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey            params.installFlags &= ~PackageManager.INSTALL_ALL_USERS;
516e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey            params.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
5173a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
5183a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
5191cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        // Defensively resize giant app icons
5201cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        if (params.appIcon != null) {
5211cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            final ActivityManager am = (ActivityManager) mContext.getSystemService(
5221cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    Context.ACTIVITY_SERVICE);
5231cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            final int iconSize = am.getLauncherLargeIconSize();
5241cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            if ((params.appIcon.getWidth() > iconSize * 2)
5251cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    || (params.appIcon.getHeight() > iconSize * 2)) {
5261cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                params.appIcon = Bitmap.createScaledBitmap(params.appIcon, iconSize, iconSize,
5271cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                        true);
5281cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            }
5291cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        }
5301cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
53177d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        if (params.mode == SessionParams.MODE_FULL_INSTALL
53277d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey                || params.mode == SessionParams.MODE_INHERIT_EXISTING) {
53377d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            // Resolve best location for install, based on combination of
53477d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            // requested install flags, delta size, and manifest settings.
535e812d9096915ad165de125520ed7371009587d1fRobin Lee            final long ident = Binder.clearCallingIdentity();
536e812d9096915ad165de125520ed7371009587d1fRobin Lee            try {
537e812d9096915ad165de125520ed7371009587d1fRobin Lee                final int resolved = PackageHelper.resolveInstallLocation(mContext,
538e812d9096915ad165de125520ed7371009587d1fRobin Lee                        params.appPackageName, params.installLocation, params.sizeBytes,
539e812d9096915ad165de125520ed7371009587d1fRobin Lee                        params.installFlags);
540e812d9096915ad165de125520ed7371009587d1fRobin Lee
541e812d9096915ad165de125520ed7371009587d1fRobin Lee                if (resolved == PackageHelper.RECOMMEND_INSTALL_INTERNAL) {
54277d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey                    params.setInstallFlagsInternal();
543e812d9096915ad165de125520ed7371009587d1fRobin Lee                } else if (resolved == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
54477d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey                    params.setInstallFlagsExternal();
545e812d9096915ad165de125520ed7371009587d1fRobin Lee                } else {
546e812d9096915ad165de125520ed7371009587d1fRobin Lee                    throw new IOException("No storage with enough free space; res=" + resolved);
547e812d9096915ad165de125520ed7371009587d1fRobin Lee                }
548e812d9096915ad165de125520ed7371009587d1fRobin Lee            } finally {
549e812d9096915ad165de125520ed7371009587d1fRobin Lee                Binder.restoreCallingIdentity(ident);
550a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            }
551742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        } else {
552742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            throw new IllegalArgumentException("Invalid install mode: " + params.mode);
553a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        }
554a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
555a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        final int sessionId;
556a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        final PackageInstallerSession session;
5573a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        synchronized (mSessions) {
5581cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            // Sanity check that installer isn't going crazy
559f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey            final int activeCount = getSessionCount(mSessions, callingUid);
5601cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            if (activeCount >= MAX_ACTIVE_SESSIONS) {
561f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey                throw new IllegalStateException(
562f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey                        "Too many active sessions for UID " + callingUid);
563f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey            }
564f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey            final int historicalCount = getSessionCount(mHistoricalSessions, callingUid);
565f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey            if (historicalCount >= MAX_HISTORICAL_SESSIONS) {
566f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey                throw new IllegalStateException(
567f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey                        "Too many historical sessions for UID " + callingUid);
5681cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            }
5691cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
570742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            final long createdMillis = System.currentTimeMillis();
571a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            sessionId = allocateSessionIdLocked();
572a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
573742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            // We're staging to exactly one location
574742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            File stageDir = null;
575742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            String stageCid = null;
57677d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
57777d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey                stageDir = buildInternalStageDir(sessionId);
578742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            } else {
57977d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey                stageCid = buildExternalStageCid(sessionId);
580742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            }
5813a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
582a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            session = new PackageInstallerSession(mInternalCallback, mContext, mPm,
583e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey                    mInstallThread.getLooper(), sessionId, userId, installerPackageName, callingUid,
584e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey                    params, createdMillis, stageDir, stageCid, false, false);
5853a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            mSessions.put(sessionId, session);
5863a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
587a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
5881cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        mCallbacks.notifySessionCreated(session.sessionId, session.userId);
589a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        writeSessionsAsync();
590a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        return sessionId;
5913a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
5923a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
593381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey    @Override
594ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey    public void updateSessionAppIcon(int sessionId, Bitmap appIcon) {
595ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey        synchronized (mSessions) {
596ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            final PackageInstallerSession session = mSessions.get(sessionId);
597ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            if (session == null || !isCallingUidOwner(session)) {
598ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey                throw new SecurityException("Caller has no access to session " + sessionId);
599ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            }
60002bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey
60102bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            // Defensively resize giant app icons
60202bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            if (appIcon != null) {
60302bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                final ActivityManager am = (ActivityManager) mContext.getSystemService(
60402bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                        Context.ACTIVITY_SERVICE);
60502bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                final int iconSize = am.getLauncherLargeIconSize();
60602bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                if ((appIcon.getWidth() > iconSize * 2)
60702bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                        || (appIcon.getHeight() > iconSize * 2)) {
60802bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                    appIcon = Bitmap.createScaledBitmap(appIcon, iconSize, iconSize, true);
60902bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                }
61002bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            }
61102bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey
612ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            session.params.appIcon = appIcon;
61302bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey            session.params.appIconLastModified = -1;
61402bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey
615ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            mInternalCallback.onSessionBadgingChanged(session);
616ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey        }
617ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey    }
618ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey
619ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey    @Override
620ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey    public void updateSessionAppLabel(int sessionId, String appLabel) {
621ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey        synchronized (mSessions) {
622ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            final PackageInstallerSession session = mSessions.get(sessionId);
623ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            if (session == null || !isCallingUidOwner(session)) {
624ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey                throw new SecurityException("Caller has no access to session " + sessionId);
625ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            }
626ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            session.params.appLabel = appLabel;
627ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            mInternalCallback.onSessionBadgingChanged(session);
628ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey        }
629ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey    }
630ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey
631ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey    @Override
632381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey    public void abandonSession(int sessionId) {
633381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey        synchronized (mSessions) {
634381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey            final PackageInstallerSession session = mSessions.get(sessionId);
635381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey            if (session == null || !isCallingUidOwner(session)) {
636381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey                throw new SecurityException("Caller has no access to session " + sessionId);
637381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey            }
638381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey            session.abandon();
639381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey        }
640381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey    }
641381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey
64277d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey    @Override
64377d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey    public IPackageInstallerSession openSession(int sessionId) {
64477d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        try {
64577d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            return openSessionInternal(sessionId);
64677d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        } catch (IOException e) {
64777d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            throw ExceptionUtils.wrap(e);
648742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        }
649742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    }
650742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
65177d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey    private IPackageInstallerSession openSessionInternal(int sessionId) throws IOException {
6523a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        synchronized (mSessions) {
6533a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            final PackageInstallerSession session = mSessions.get(sessionId);
654381d94b712605112b35d7f70064b0d18bd877877Jeff Sharkey            if (session == null || !isCallingUidOwner(session)) {
6553a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                throw new SecurityException("Caller has no access to session " + sessionId);
6563a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
657742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            session.open();
6583a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            return session;
6593a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
6603a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
6613a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
6623a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private int allocateSessionIdLocked() {
6631cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        int n = 0;
6641cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        int sessionId;
6651cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        do {
666f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey            sessionId = mRandom.nextInt(Integer.MAX_VALUE - 1) + 1;
667742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            if (mSessions.get(sessionId) == null && mHistoricalSessions.get(sessionId) == null
668742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                    && !mLegacySessions.get(sessionId, false)) {
6691cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                return sessionId;
6701cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            }
6711cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        } while (n++ < 32);
6721cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
6731cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        throw new IllegalStateException("Failed to allocate session ID");
6743a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
6753a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
67677d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey    private File buildInternalStageDir(int sessionId) {
67777d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        return new File(mStagingDir, "vmdl" + sessionId + ".tmp");
67877d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey    }
679ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey
68077d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey    static void prepareInternalStageDir(File stageDir) throws IOException {
68177d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        if (stageDir.exists()) {
68277d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            throw new IOException("Session dir already exists: " + stageDir);
683ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        }
684ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey
685ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        try {
68677d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            Os.mkdir(stageDir.getAbsolutePath(), 0755);
68777d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            Os.chmod(stageDir.getAbsolutePath(), 0755);
688ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        } catch (ErrnoException e) {
689ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey            // This purposefully throws if directory already exists
69077d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            throw new IOException("Failed to prepare session dir: " + stageDir, e);
691ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        }
692ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey
69377d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        if (!SELinux.restorecon(stageDir)) {
69477d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            throw new IOException("Failed to restorecon session dir: " + stageDir);
695ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        }
696ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey    }
697ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey
69877d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey    private String buildExternalStageCid(int sessionId) {
69977d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        return "smdl" + sessionId + ".tmp";
70077d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey    }
701742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
70277d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey    static void prepareExternalStageCid(String stageCid, long sizeBytes) throws IOException {
70377d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        if (PackageHelper.createSdDir(sizeBytes, stageCid, PackageManagerService.getEncryptKey(),
704742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                Process.SYSTEM_UID, true) == null) {
70577d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            throw new IOException("Failed to create session cid: " + stageCid);
706742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        }
707742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    }
708742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
7093a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    @Override
710a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey    public SessionInfo getSessionInfo(int sessionId) {
71116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey        synchronized (mSessions) {
71216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey            final PackageInstallerSession session = mSessions.get(sessionId);
71316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey            return session != null ? session.generateInfo() : null;
71416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey        }
71516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey    }
71616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey
71716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey    @Override
71897d47ed036ff7bd3d7d2ddc1c6df1104ec237559Jeff Sharkey    public ParceledListSlice<SessionInfo> getAllSessions(int userId) {
7198cd28b57ed732656d002d97879e15c5695b54fffAmith Yamasani        mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, "getAllSessions");
7203a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
721a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        final List<SessionInfo> result = new ArrayList<>();
7223a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        synchronized (mSessions) {
7233a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            for (int i = 0; i < mSessions.size(); i++) {
7243a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                final PackageInstallerSession session = mSessions.valueAt(i);
725bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey                if (session.userId == userId) {
726bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey                    result.add(session.generateInfo());
7273a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                }
7283a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
7293a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
73097d47ed036ff7bd3d7d2ddc1c6df1104ec237559Jeff Sharkey        return new ParceledListSlice<>(result);
7313a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
7323a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
7333a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    @Override
73497d47ed036ff7bd3d7d2ddc1c6df1104ec237559Jeff Sharkey    public ParceledListSlice<SessionInfo> getMySessions(String installerPackageName, int userId) {
7358cd28b57ed732656d002d97879e15c5695b54fffAmith Yamasani        mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, "getMySessions");
73616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey        mAppOps.checkPackage(Binder.getCallingUid(), installerPackageName);
73716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey
738a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        final List<SessionInfo> result = new ArrayList<>();
73916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey        synchronized (mSessions) {
74016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey            for (int i = 0; i < mSessions.size(); i++) {
74116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey                final PackageInstallerSession session = mSessions.valueAt(i);
74216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey                if (Objects.equals(session.installerPackageName, installerPackageName)
74316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey                        && session.userId == userId) {
74416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey                    result.add(session.generateInfo());
74516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey                }
74616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey            }
74716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey        }
74897d47ed036ff7bd3d7d2ddc1c6df1104ec237559Jeff Sharkey        return new ParceledListSlice<>(result);
74916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey    }
75016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey
75116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey    @Override
752a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey    public void uninstall(String packageName, int flags, IntentSender statusReceiver, int userId) {
753e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey        mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, true, "uninstall");
75416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey
755a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext,
756bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                statusReceiver, packageName);
757f06009542390472872da986486d385001e91a2a7Jeff Sharkey        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES)
758f06009542390472872da986486d385001e91a2a7Jeff Sharkey                == PackageManager.PERMISSION_GRANTED) {
759f06009542390472872da986486d385001e91a2a7Jeff Sharkey            // Sweet, call straight through!
760a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            mPm.deletePackage(packageName, adapter.getBinder(), userId, flags);
761f06009542390472872da986486d385001e91a2a7Jeff Sharkey
762f06009542390472872da986486d385001e91a2a7Jeff Sharkey        } else {
763f06009542390472872da986486d385001e91a2a7Jeff Sharkey            // Take a short detour to confirm with user
764f06009542390472872da986486d385001e91a2a7Jeff Sharkey            final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
765f06009542390472872da986486d385001e91a2a7Jeff Sharkey            intent.setData(Uri.fromParts("package", packageName, null));
766a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            intent.putExtra(PackageInstaller.EXTRA_CALLBACK, adapter.getBinder().asBinder());
767a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            adapter.onUserActionRequired(intent);
768f06009542390472872da986486d385001e91a2a7Jeff Sharkey        }
7693a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
7703a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
7713a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    @Override
7727328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey    public void setPermissionsResult(int sessionId, boolean accepted) {
7737328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, TAG);
7747328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey
7757328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey        synchronized (mSessions) {
7767328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey            mSessions.get(sessionId).setPermissionsResult(accepted);
7777328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey        }
7787328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey    }
7797328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey
7807328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey    @Override
78116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey    public void registerCallback(IPackageInstallerCallback callback, int userId) {
7828cd28b57ed732656d002d97879e15c5695b54fffAmith Yamasani        mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, "registerCallback");
7831cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        mCallbacks.register(callback, userId);
784bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey    }
785bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey
786bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey    @Override
78716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey    public void unregisterCallback(IPackageInstallerCallback callback) {
78816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey        mCallbacks.unregister(callback);
789a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey    }
790a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
791f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey    private static int getSessionCount(SparseArray<PackageInstallerSession> sessions,
792f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey            int installerUid) {
7931cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        int count = 0;
794f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey        final int size = sessions.size();
7951cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        for (int i = 0; i < size; i++) {
796f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey            final PackageInstallerSession session = sessions.valueAt(i);
7971cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            if (session.installerUid == installerUid) {
7981cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                count++;
7991cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            }
8001cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        }
8011cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        return count;
8021cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    }
8031cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
8041cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private boolean isCallingUidOwner(PackageInstallerSession session) {
8051cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        final int callingUid = Binder.getCallingUid();
8061cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        if (callingUid == Process.ROOT_UID) {
8071cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            return true;
8081cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        } else {
8091cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            return (session != null) && (callingUid == session.installerUid);
810a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        }
811a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey    }
812a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
813a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey    static class PackageDeleteObserverAdapter extends PackageDeleteObserver {
814a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        private final Context mContext;
815a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        private final IntentSender mTarget;
816bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey        private final String mPackageName;
817a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey
818bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey        public PackageDeleteObserverAdapter(Context context, IntentSender target,
819bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                String packageName) {
820a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            mContext = context;
821a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            mTarget = target;
822bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            mPackageName = packageName;
823a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        }
824a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey
825a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        @Override
826a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        public void onUserActionRequired(Intent intent) {
827a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            final Intent fillIn = new Intent();
828bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName);
829a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
830742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                    PackageInstaller.STATUS_PENDING_USER_ACTION);
831a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            fillIn.putExtra(Intent.EXTRA_INTENT, intent);
832a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            try {
833a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                mTarget.sendIntent(mContext, 0, fillIn, null, null);
834a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            } catch (SendIntentException ignored) {
835a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            }
836a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        }
837a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey
838a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        @Override
839a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        public void onPackageDeleted(String basePackageName, int returnCode, String msg) {
840a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            final Intent fillIn = new Intent();
841bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName);
842a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
843a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                    PackageManager.deleteStatusToPublicStatus(returnCode));
844a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
845a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                    PackageManager.deleteStatusToString(returnCode, msg));
846a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode);
847a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            try {
848a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                mTarget.sendIntent(mContext, 0, fillIn, null, null);
849a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            } catch (SendIntentException ignored) {
850a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            }
851a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        }
852a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey    }
853a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey
854a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey    static class PackageInstallObserverAdapter extends PackageInstallObserver {
855a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        private final Context mContext;
856a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        private final IntentSender mTarget;
857bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey        private final int mSessionId;
858a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey
859bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey        public PackageInstallObserverAdapter(Context context, IntentSender target, int sessionId) {
860a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            mContext = context;
861a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            mTarget = target;
862bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            mSessionId = sessionId;
863a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        }
864a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey
865a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        @Override
866a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        public void onUserActionRequired(Intent intent) {
867a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            final Intent fillIn = new Intent();
868bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId);
869a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
870742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                    PackageInstaller.STATUS_PENDING_USER_ACTION);
871a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            fillIn.putExtra(Intent.EXTRA_INTENT, intent);
872a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            try {
873a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                mTarget.sendIntent(mContext, 0, fillIn, null, null);
874a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            } catch (SendIntentException ignored) {
875a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            }
876a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        }
877a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey
878a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        @Override
879a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        public void onPackageInstalled(String basePackageName, int returnCode, String msg,
880a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                Bundle extras) {
881a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            final Intent fillIn = new Intent();
882bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId);
883a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
884a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                    PackageManager.installStatusToPublicStatus(returnCode));
885a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
886a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                    PackageManager.installStatusToString(returnCode, msg));
887a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode);
888a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            if (extras != null) {
889a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                final String existing = extras.getString(
890a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                        PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE);
891a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                if (!TextUtils.isEmpty(existing)) {
892941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                    fillIn.putExtra(PackageInstaller.EXTRA_OTHER_PACKAGE_NAME, existing);
893a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                }
894a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            }
895a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            try {
896a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey                mTarget.sendIntent(mContext, 0, fillIn, null, null);
897a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            } catch (SendIntentException ignored) {
898a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            }
899a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        }
900a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey    }
901a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey
9021cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static class Callbacks extends Handler {
9031cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        private static final int MSG_SESSION_CREATED = 1;
904ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey        private static final int MSG_SESSION_BADGING_CHANGED = 2;
905bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey        private static final int MSG_SESSION_ACTIVE_CHANGED = 3;
906ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey        private static final int MSG_SESSION_PROGRESS_CHANGED = 4;
907bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey        private static final int MSG_SESSION_FINISHED = 5;
9081cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
9091cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        private final RemoteCallbackList<IPackageInstallerCallback>
9101cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                mCallbacks = new RemoteCallbackList<>();
9111cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
9121cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        public Callbacks(Looper looper) {
9131cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            super(looper);
914a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        }
915a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
9161cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        public void register(IPackageInstallerCallback callback, int userId) {
9171cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            mCallbacks.register(callback, new UserHandle(userId));
9181cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        }
9191cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
9201cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        public void unregister(IPackageInstallerCallback callback) {
9211cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            mCallbacks.unregister(callback);
9221cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        }
9231cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
9241cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        @Override
9251cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        public void handleMessage(Message msg) {
9261cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            final int userId = msg.arg2;
9271cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            final int n = mCallbacks.beginBroadcast();
9281cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            for (int i = 0; i < n; i++) {
9291cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                final IPackageInstallerCallback callback = mCallbacks.getBroadcastItem(i);
9301cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                final UserHandle user = (UserHandle) mCallbacks.getBroadcastCookie(i);
9311cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                // TODO: dispatch notifications for slave profiles
9321cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                if (userId == user.getIdentifier()) {
9331cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    try {
9341cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                        invokeCallback(callback, msg);
9351cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    } catch (RemoteException ignored) {
9361cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    }
937a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey                }
938a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            }
9391cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            mCallbacks.finishBroadcast();
940a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        }
941a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
9421cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        private void invokeCallback(IPackageInstallerCallback callback, Message msg)
9431cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                throws RemoteException {
9441cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            final int sessionId = msg.arg1;
9451cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            switch (msg.what) {
9461cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                case MSG_SESSION_CREATED:
9471cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    callback.onSessionCreated(sessionId);
9481cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    break;
949ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey                case MSG_SESSION_BADGING_CHANGED:
950ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey                    callback.onSessionBadgingChanged(sessionId);
951ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey                    break;
952bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey                case MSG_SESSION_ACTIVE_CHANGED:
953bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey                    callback.onSessionActiveChanged(sessionId, (boolean) msg.obj);
9541cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    break;
9551cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                case MSG_SESSION_PROGRESS_CHANGED:
9561cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    callback.onSessionProgressChanged(sessionId, (float) msg.obj);
9571cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    break;
9581cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                case MSG_SESSION_FINISHED:
9591cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    callback.onSessionFinished(sessionId, (boolean) msg.obj);
9601cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                    break;
961a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            }
962a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        }
9631cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
9641cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        private void notifySessionCreated(int sessionId, int userId) {
9651cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            obtainMessage(MSG_SESSION_CREATED, sessionId, userId).sendToTarget();
9661cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        }
9671cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
968ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey        private void notifySessionBadgingChanged(int sessionId, int userId) {
969ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            obtainMessage(MSG_SESSION_BADGING_CHANGED, sessionId, userId).sendToTarget();
970ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey        }
971ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey
972bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey        private void notifySessionActiveChanged(int sessionId, int userId, boolean active) {
973bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey            obtainMessage(MSG_SESSION_ACTIVE_CHANGED, sessionId, userId, active).sendToTarget();
9741cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        }
9751cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
9761cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        private void notifySessionProgressChanged(int sessionId, int userId, float progress) {
9771cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            obtainMessage(MSG_SESSION_PROGRESS_CHANGED, sessionId, userId, progress).sendToTarget();
9781cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        }
9791cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
9801cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        public void notifySessionFinished(int sessionId, int userId, boolean success) {
9811cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            obtainMessage(MSG_SESSION_FINISHED, sessionId, userId, success).sendToTarget();
9821cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        }
983a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey    }
984a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
985a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey    void dump(IndentingPrintWriter pw) {
986a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        synchronized (mSessions) {
9879a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey            pw.println("Active install sessions:");
9889a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey            pw.increaseIndent();
9899a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey            int N = mSessions.size();
990a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            for (int i = 0; i < N; i++) {
991a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey                final PackageInstallerSession session = mSessions.valueAt(i);
992a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey                session.dump(pw);
993a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey                pw.println();
994a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            }
9959a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey            pw.println();
9969a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey            pw.decreaseIndent();
9979a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey
9989a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey            pw.println("Historical install sessions:");
9999a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey            pw.increaseIndent();
10009a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey            N = mHistoricalSessions.size();
10019a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey            for (int i = 0; i < N; i++) {
10029a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey                final PackageInstallerSession session = mHistoricalSessions.valueAt(i);
10039a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey                session.dump(pw);
10049a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey                pw.println();
10059a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey            }
10069a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey            pw.println();
10079a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey            pw.decreaseIndent();
1008742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
1009742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            pw.println("Legacy install sessions:");
1010742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            pw.increaseIndent();
1011742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            pw.println(mLegacySessions.toString());
1012742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            pw.decreaseIndent();
1013a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        }
1014bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey    }
1015bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey
10161cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    class InternalCallback {
1017ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey        public void onSessionBadgingChanged(PackageInstallerSession session) {
1018ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            mCallbacks.notifySessionBadgingChanged(session.sessionId, session.userId);
1019ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            writeSessionsAsync();
10201cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        }
10211cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
1022bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey        public void onSessionActiveChanged(PackageInstallerSession session, boolean active) {
1023bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey            mCallbacks.notifySessionActiveChanged(session.sessionId, session.userId, active);
1024742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        }
1025742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
1026ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey        public void onSessionProgressChanged(PackageInstallerSession session, float progress) {
1027ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey            mCallbacks.notifySessionProgressChanged(session.sessionId, session.userId, progress);
1028ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey        }
1029ec9bad2015c6d3bc91bab66f0824043c1e24d013Jeff Sharkey
1030cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey        public void onSessionFinished(final PackageInstallerSession session, boolean success) {
10311cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            mCallbacks.notifySessionFinished(session.sessionId, session.userId, success);
1032cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey
1033cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey            mInstallHandler.post(new Runnable() {
1034cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey                @Override
1035cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey                public void run() {
1036cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey                    synchronized (mSessions) {
1037cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey                        mSessions.remove(session.sessionId);
1038cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey                        mHistoricalSessions.put(session.sessionId, session);
103902bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey
104002bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                        final File appIconFile = buildAppIconFile(session.sessionId);
104102bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                        if (appIconFile.exists()) {
104202bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                            appIconFile.delete();
104302bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey                        }
104402bd78490d8594d225ecc70a74b2058cb968a657Jeff Sharkey
1045cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey                        writeSessionsLocked();
1046cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey                    }
1047cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey                }
1048cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey            });
10493a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
1050bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey
105177d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        public void onSessionPrepared(PackageInstallerSession session) {
105277d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            // We prepared the destination to write into; we want to persist
105377d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            // this, but it's not critical enough to block for.
105477d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            writeSessionsAsync();
105577d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        }
105677d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey
1057cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey        public void onSessionSealedBlocking(PackageInstallerSession session) {
1058bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            // It's very important that we block until we've recorded the
1059bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            // session as being sealed, since we never want to allow mutation
1060bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            // after sealing.
1061cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey            synchronized (mSessions) {
1062cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey                writeSessionsLocked();
1063cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey            }
1064bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey        }
10653a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
10663a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey}
1067