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
19f06009542390472872da986486d385001e91a2a7Jeff Sharkeyimport static android.content.pm.PackageManager.INSTALL_FAILED_ABORTED;
20742e790294b3441b79f715fe447069b63c6065dbJeff Sharkeyimport static android.content.pm.PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
21941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkeyimport static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
223a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
233a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
24ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport static android.system.OsConstants.O_CREAT;
251cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport static android.system.OsConstants.O_RDONLY;
26ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport static android.system.OsConstants.O_WRONLY;
2777d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkeyimport static com.android.server.pm.PackageInstallerService.prepareExternalStageCid;
2877d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkeyimport static com.android.server.pm.PackageInstallerService.prepareInternalStageDir;
293a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
30a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.content.Context;
31fbd0e9fa37fc17ccd25e4c1f16195bbd27de3c4cJeff Sharkeyimport android.content.Intent;
32a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.content.IntentSender;
333a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.content.pm.ApplicationInfo;
343a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.content.pm.IPackageInstallObserver2;
353a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.content.pm.IPackageInstallerSession;
367328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkeyimport android.content.pm.PackageInstaller;
37a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.content.pm.PackageInstaller.SessionInfo;
38a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport android.content.pm.PackageInstaller.SessionParams;
393a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.content.pm.PackageManager;
403a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.content.pm.PackageParser;
41c4858a2ba972e86436d629c4d3f18eb49116de14Jeff Sharkeyimport android.content.pm.PackageParser.ApkLite;
42941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkeyimport android.content.pm.PackageParser.PackageLite;
43275e085d5a42ced54bb79e40ff76c77539e7d82dJeff Sharkeyimport android.content.pm.PackageParser.PackageParserException;
443a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.content.pm.Signature;
453a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.Bundle;
4678cc340c2de873d6995c283b777476f7237d690fJeff Sharkeyimport android.os.FileBridge;
473a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.FileUtils;
483a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.Handler;
493a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.Looper;
503a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.Message;
513a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.ParcelFileDescriptor;
52941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkeyimport android.os.Process;
533a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.RemoteException;
5457dcf5b177b56195421535938544f32d8b591b42Jeff Sharkeyimport android.os.UserHandle;
553a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.system.ErrnoException;
56ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport android.system.Os;
573a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.system.OsConstants;
583a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.system.StructStat;
593a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.util.ArraySet;
60a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkeyimport android.util.ExceptionUtils;
61a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkeyimport android.util.MathUtils;
623a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.util.Slog;
633a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
641cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport com.android.internal.annotations.GuardedBy;
65941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkeyimport com.android.internal.content.NativeLibraryHelper;
66742e790294b3441b79f715fe447069b63c6065dbJeff Sharkeyimport com.android.internal.content.PackageHelper;
673a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport com.android.internal.util.ArrayUtils;
68a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkeyimport com.android.internal.util.IndentingPrintWriter;
693a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport com.android.internal.util.Preconditions;
70a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkeyimport com.android.server.pm.PackageInstallerService.PackageInstallObserverAdapter;
713a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
72941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkeyimport libcore.io.IoUtils;
733a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport libcore.io.Libcore;
743a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
753a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport java.io.File;
763a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport java.io.FileDescriptor;
773a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport java.io.IOException;
783a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport java.util.ArrayList;
79941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkeyimport java.util.List;
801cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport java.util.concurrent.atomic.AtomicInteger;
813a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
823a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeypublic class PackageInstallerSession extends IPackageInstallerSession.Stub {
833a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private static final String TAG = "PackageInstaller";
849a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey    private static final boolean LOGD = true;
853a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
861cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private static final int MSG_COMMIT = 0;
871cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
88ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey    // TODO: enforce INSTALL_ALLOW_TEST
89ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey    // TODO: enforce INSTALL_ALLOW_DOWNGRADE
90ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey
911cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private final PackageInstallerService.InternalCallback mCallback;
92a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey    private final Context mContext;
933a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private final PackageManagerService mPm;
943a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private final Handler mHandler;
953a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
961cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    final int sessionId;
971cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    final int userId;
981cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    final String installerPackageName;
99e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey    final int installerUid;
100a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey    final SessionParams params;
1011cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    final long createdMillis;
102742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
103941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey    /** Staging location where client data is written. */
104941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey    final File stageDir;
105941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey    final String stageCid;
1063a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
10777d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey    private final AtomicInteger mActiveCount = new AtomicInteger();
1081cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
1091cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private final Object mLock = new Object();
1101cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
1111cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    @GuardedBy("mLock")
1121cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private float mClientProgress = 0;
1131cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    @GuardedBy("mLock")
11477d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey    private float mInternalProgress = 0;
11577d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey
11677d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey    @GuardedBy("mLock")
1171cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private float mProgress = 0;
1181cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    @GuardedBy("mLock")
1191cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private float mReportedProgress = -1;
1201cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
1211cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    @GuardedBy("mLock")
12277d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey    private boolean mPrepared = false;
12377d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey    @GuardedBy("mLock")
1241cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private boolean mSealed = false;
1251cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    @GuardedBy("mLock")
1267328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey    private boolean mPermissionsAccepted = false;
1271cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    @GuardedBy("mLock")
1281cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private boolean mDestroyed = false;
1291cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
1307328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey    private int mFinalStatus;
1317328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey    private String mFinalMessage;
1327328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey
133742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    @GuardedBy("mLock")
134941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey    private ArrayList<FileBridge> mBridges = new ArrayList<>();
135941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey
136941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey    @GuardedBy("mLock")
137941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey    private IPackageInstallObserver2 mRemoteObserver;
138941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey
139941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey    /** Fields derived from commit parsing */
140941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey    private String mPackageName;
141941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey    private int mVersionCode;
142941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey    private Signature[] mSignatures;
143742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
1447328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey    /**
145941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey     * Path to the validated base APK for this session, which may point at an
146941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey     * APK inside the session (when the session defines the base), or it may
147941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey     * point at the existing base APK (when adding splits to an existing app).
1487328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey     * <p>
1497328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey     * This is used when confirming permissions, since we can't fully stage the
1507328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey     * session inside an ASEC before confirming with user.
1517328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey     */
1527328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey    @GuardedBy("mLock")
153941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey    private File mResolvedBaseFile;
1547328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey
1551cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    @GuardedBy("mLock")
156941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey    private File mResolvedStageDir;
1573a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1581cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    @GuardedBy("mLock")
159941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey    private final List<File> mResolvedStagedFiles = new ArrayList<>();
160941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey    @GuardedBy("mLock")
161941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey    private final List<File> mResolvedInheritedFiles = new ArrayList<>();
1621cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
1631cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private final Handler.Callback mHandlerCallback = new Handler.Callback() {
1643a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        @Override
1653a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        public boolean handleMessage(Message msg) {
1663a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            synchronized (mLock) {
1673a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                if (msg.obj != null) {
1683a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                    mRemoteObserver = (IPackageInstallObserver2) msg.obj;
1693a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                }
1703a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1713a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                try {
17216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey                    commitLocked();
173e0b0bef75b66f0a87039c8f58c17b1596a2baebeJeff Sharkey                } catch (PackageManagerException e) {
174941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                    final String completeMsg = ExceptionUtils.getCompleteMessage(e);
175941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                    Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg);
176a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey                    destroyInternal();
177941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                    dispatchSessionFinished(e.error, completeMsg, null);
1783a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                }
1793a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1803a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                return true;
1813a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
1823a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
1833a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    };
1843a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1851cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    public PackageInstallerSession(PackageInstallerService.InternalCallback callback,
186a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey            Context context, PackageManagerService pm, Looper looper, int sessionId, int userId,
187e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey            String installerPackageName, int installerUid, SessionParams params, long createdMillis,
18877d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            File stageDir, String stageCid, boolean prepared, boolean sealed) {
1893a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        mCallback = callback;
190a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        mContext = context;
1913a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        mPm = pm;
1923a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        mHandler = new Handler(looper, mHandlerCallback);
1933a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1943a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        this.sessionId = sessionId;
1953a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        this.userId = userId;
1963a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        this.installerPackageName = installerPackageName;
197e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey        this.installerUid = installerUid;
1983a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        this.params = params;
1993a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        this.createdMillis = createdMillis;
200941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        this.stageDir = stageDir;
201941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        this.stageCid = stageCid;
2023a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
203941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        if ((stageDir == null) == (stageCid == null)) {
204bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            throw new IllegalArgumentException(
205941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                    "Exactly one of stageDir or stageCid stage must be set");
206bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey        }
207bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey
20877d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        mPrepared = prepared;
2091cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        mSealed = sealed;
2103a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
211e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey        if ((mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES, installerUid)
212e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey                == PackageManager.PERMISSION_GRANTED) || (installerUid == Process.ROOT_UID)) {
2137328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey            mPermissionsAccepted = true;
2141cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        } else {
2157328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey            mPermissionsAccepted = false;
216ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        }
2173a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
2183a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
219a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey    public SessionInfo generateInfo() {
220a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        final SessionInfo info = new SessionInfo();
221742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        synchronized (mLock) {
222742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            info.sessionId = sessionId;
223742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            info.installerPackageName = installerPackageName;
224941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            info.resolvedBaseCodePath = (mResolvedBaseFile != null) ?
225941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                    mResolvedBaseFile.getAbsolutePath() : null;
226742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            info.progress = mProgress;
227742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            info.sealed = mSealed;
22877d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            info.active = mActiveCount.get() > 0;
229742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
230742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            info.mode = params.mode;
231742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            info.sizeBytes = params.sizeBytes;
232742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            info.appPackageName = params.appPackageName;
233742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            info.appIcon = params.appIcon;
234742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            info.appLabel = params.appLabel;
235742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        }
236bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey        return info;
237bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey    }
238bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey
23977d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey    public boolean isPrepared() {
24077d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        synchronized (mLock) {
24177d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            return mPrepared;
24277d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        }
24377d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey    }
24477d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey
245742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    public boolean isSealed() {
246742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        synchronized (mLock) {
247742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            return mSealed;
248742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        }
249742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    }
250742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
25177d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey    private void assertPreparedAndNotSealed(String cookie) {
2521cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        synchronized (mLock) {
25377d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            if (!mPrepared) {
25477d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey                throw new IllegalStateException(cookie + " before prepared");
25577d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            }
2561cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            if (mSealed) {
2571cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                throw new SecurityException(cookie + " not allowed after commit");
2581cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            }
2591cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        }
2601cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    }
2611cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
262742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    /**
263742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey     * Resolve the actual location where staged data should be written. This
264742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey     * might point at an ASEC mount point, which is why we delay path resolution
265742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey     * until someone actively works with the session.
266742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey     */
267941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey    private File resolveStageDir() throws IOException {
268742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        synchronized (mLock) {
269742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            if (mResolvedStageDir == null) {
270941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                if (stageDir != null) {
271941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                    mResolvedStageDir = stageDir;
272742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                } else {
273941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                    final String path = PackageHelper.getSdDir(stageCid);
274742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                    if (path != null) {
275742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                        mResolvedStageDir = new File(path);
276742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                    } else {
277941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                        throw new IOException("Failed to resolve path to container " + stageCid);
278742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                    }
279742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                }
280742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            }
281742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            return mResolvedStageDir;
282742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        }
283742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    }
284742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
2853a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    @Override
28616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey    public void setClientProgress(float progress) {
2871cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        synchronized (mLock) {
28877d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            // Always publish first staging movement
28977d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            final boolean forcePublish = (mClientProgress == 0);
2901cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            mClientProgress = progress;
29177d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            computeProgressLocked(forcePublish);
2921cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        }
293a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey    }
294a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
295a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey    @Override
29616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey    public void addClientProgress(float progress) {
2971cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        synchronized (mLock) {
29877d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            setClientProgress(mClientProgress + progress);
2991cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        }
3001cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    }
3011cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
30277d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey    private void computeProgressLocked(boolean forcePublish) {
30377d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        mProgress = MathUtils.constrain(mClientProgress * 0.8f, 0f, 0.8f)
30477d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey                + MathUtils.constrain(mInternalProgress * 0.2f, 0f, 0.2f);
3051cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
3061cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        // Only publish when meaningful change
30777d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        if (forcePublish || Math.abs(mProgress - mReportedProgress) >= 0.01) {
3081cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            mReportedProgress = mProgress;
3091cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            mCallback.onSessionProgressChanged(this, mProgress);
3101cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        }
3111cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    }
3121cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
3131cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    @Override
314a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey    public String[] getNames() {
31577d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        assertPreparedAndNotSealed("getNames");
316742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        try {
317941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            return resolveStageDir().list();
318742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        } catch (IOException e) {
319742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            throw ExceptionUtils.wrap(e);
320742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        }
3213a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
3223a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
3233a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    @Override
3243a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    public ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes) {
325a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        try {
326a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            return openWriteInternal(name, offsetBytes, lengthBytes);
327a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        } catch (IOException e) {
328a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            throw ExceptionUtils.wrap(e);
329a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        }
330a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey    }
331a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
332a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey    private ParcelFileDescriptor openWriteInternal(String name, long offsetBytes, long lengthBytes)
333a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            throws IOException {
3343a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        // Quick sanity check of state, and allocate a pipe for ourselves. We
3353a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        // then do heavy disk allocation outside the lock, but this open pipe
3363a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        // will block any attempted install transitions.
33778cc340c2de873d6995c283b777476f7237d690fJeff Sharkey        final FileBridge bridge;
3383a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        synchronized (mLock) {
33977d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            assertPreparedAndNotSealed("openWrite");
3403a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
34178cc340c2de873d6995c283b777476f7237d690fJeff Sharkey            bridge = new FileBridge();
34278cc340c2de873d6995c283b777476f7237d690fJeff Sharkey            mBridges.add(bridge);
3433a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
3443a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
3453a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        try {
3463a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            // Use installer provided name for now; we always rename later
3473a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            if (!FileUtils.isValidExtFilename(name)) {
3483a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                throw new IllegalArgumentException("Invalid name: " + name);
3493a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
350941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            final File target = new File(resolveStageDir(), name);
3513a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
352941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            // TODO: this should delegate to DCS so the system process avoids
353941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            // holding open FDs into containers.
3543a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            final FileDescriptor targetFd = Libcore.os.open(target.getAbsolutePath(),
355ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey                    O_CREAT | O_WRONLY, 0644);
356ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey            Os.chmod(target.getAbsolutePath(), 0644);
3573a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
3583a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            // If caller specified a total length, allocate it for them. Free up
3593a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            // cache space to grow, if needed.
3603a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            if (lengthBytes > 0) {
3613a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                final StructStat stat = Libcore.os.fstat(targetFd);
3623a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                final long deltaBytes = lengthBytes - stat.st_size;
363941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                // Only need to free up space when writing to internal stage
364941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                if (stageDir != null && deltaBytes > 0) {
3653a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                    mPm.freeStorage(deltaBytes);
3663a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                }
3673a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                Libcore.os.posix_fallocate(targetFd, 0, lengthBytes);
3683a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
3693a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
3703a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            if (offsetBytes > 0) {
3713a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                Libcore.os.lseek(targetFd, offsetBytes, OsConstants.SEEK_SET);
3723a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
3733a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
37478cc340c2de873d6995c283b777476f7237d690fJeff Sharkey            bridge.setTargetFile(targetFd);
37578cc340c2de873d6995c283b777476f7237d690fJeff Sharkey            bridge.start();
37678cc340c2de873d6995c283b777476f7237d690fJeff Sharkey            return new ParcelFileDescriptor(bridge.getClientSocket());
3773a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
3783a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        } catch (ErrnoException e) {
379a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            throw e.rethrowAsIOException();
3803a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
3813a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
3823a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
3833a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    @Override
3841cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    public ParcelFileDescriptor openRead(String name) {
3851cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        try {
3861cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            return openReadInternal(name);
3871cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        } catch (IOException e) {
3881cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            throw ExceptionUtils.wrap(e);
3891cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        }
3901cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    }
3911cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
3921cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    private ParcelFileDescriptor openReadInternal(String name) throws IOException {
39377d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        assertPreparedAndNotSealed("openRead");
3941cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
3951cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        try {
3961cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            if (!FileUtils.isValidExtFilename(name)) {
3971cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey                throw new IllegalArgumentException("Invalid name: " + name);
3981cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            }
399941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            final File target = new File(resolveStageDir(), name);
4001cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
4011cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            final FileDescriptor targetFd = Libcore.os.open(target.getAbsolutePath(), O_RDONLY, 0);
4021cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            return new ParcelFileDescriptor(targetFd);
4031cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
4041cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        } catch (ErrnoException e) {
4051cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            throw e.rethrowAsIOException();
4061cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        }
4071cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    }
4081cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey
4091cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey    @Override
410a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey    public void commit(IntentSender statusReceiver) {
411a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        Preconditions.checkNotNull(statusReceiver);
412a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey
413cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey        final boolean wasSealed;
41477d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        synchronized (mLock) {
415cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey            wasSealed = mSealed;
41677d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            if (!mSealed) {
41777d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey                // Verify that all writers are hands-off
41877d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey                for (FileBridge bridge : mBridges) {
41977d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey                    if (!bridge.isClosed()) {
42077d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey                        throw new SecurityException("Files still open");
42177d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey                    }
42277d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey                }
42377d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey                mSealed = true;
42477d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            }
425cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey
426cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey            // Client staging is fully done at this point
427cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey            mClientProgress = 1f;
428cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey            computeProgressLocked(true);
42977d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        }
43077d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey
431cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey        if (!wasSealed) {
432cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey            // Persist the fact that we've sealed ourselves to prevent
433cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey            // mutations of any hard links we create. We do this without holding
434cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey            // the session lock, since otherwise it's a lock inversion.
435cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey            mCallback.onSessionSealedBlocking(this);
436cbf47916b3e7a971c3a61035eb2633f96fc043cbJeff Sharkey        }
43777d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey
43877d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        // This ongoing commit should keep session active, even though client
43977d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        // will probably close their end.
44077d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        mActiveCount.incrementAndGet();
44177d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey
442a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        final PackageInstallObserverAdapter adapter = new PackageInstallObserverAdapter(mContext,
443bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                statusReceiver, sessionId);
444a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        mHandler.obtainMessage(MSG_COMMIT, adapter.getBinder()).sendToTarget();
4453a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
4463a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
44716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey    private void commitLocked() throws PackageManagerException {
4481cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        if (mDestroyed) {
44977d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session destroyed");
4503a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
4511cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        if (!mSealed) {
45277d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session not sealed");
4533a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
4543a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
455742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        try {
456941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            resolveStageDir();
457742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        } catch (IOException e) {
458742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
459941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                    "Failed to resolve stage location", e);
460742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        }
461742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
4623a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        // Verify that stage looks sane with respect to existing application.
4633a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        // This currently only ensures packageName, versionCode, and certificate
4643a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        // consistency.
465941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        validateInstallLocked();
4663a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
4673a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        Preconditions.checkNotNull(mPackageName);
4683a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        Preconditions.checkNotNull(mSignatures);
469941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        Preconditions.checkNotNull(mResolvedBaseFile);
4707328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey
4717328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey        if (!mPermissionsAccepted) {
4727328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey            // User needs to accept permissions; give installer an intent they
4737328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey            // can use to involve user.
4747328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey            final Intent intent = new Intent(PackageInstaller.ACTION_CONFIRM_PERMISSIONS);
4757328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey            intent.setPackage("com.android.packageinstaller");
4767328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey            intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
4777328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey            try {
4787328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey                mRemoteObserver.onUserActionRequired(intent);
4797328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey            } catch (RemoteException ignored) {
4807328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey            }
48177d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey
48277d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            // Commit was keeping session marked as active until now; release
48377d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            // that extra refcount so session appears idle.
48477d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            close();
4857328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey            return;
4863a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
4873a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
488941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        if (stageCid != null) {
489941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            // Figure out the final installed size and resize the container once
490941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            // and for all. Internally the parser handles straddling between two
491941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            // locations when inheriting.
492941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            final long finalSize = calculateInstalledSize();
493941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            resizeContainer(stageCid, finalSize);
494941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        }
495941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey
4963a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        // Inherit any packages and native libraries from existing install that
4973a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        // haven't been overridden.
498a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
499941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            try {
50088d2a3c0e1b4a8c53a489db5d627beb80b1b9957Jeff Sharkey                final List<File> fromFiles = mResolvedInheritedFiles;
50188d2a3c0e1b4a8c53a489db5d627beb80b1b9957Jeff Sharkey                final File toDir = resolveStageDir();
50288d2a3c0e1b4a8c53a489db5d627beb80b1b9957Jeff Sharkey
50388d2a3c0e1b4a8c53a489db5d627beb80b1b9957Jeff Sharkey                if (isLinkPossible(fromFiles, toDir)) {
50488d2a3c0e1b4a8c53a489db5d627beb80b1b9957Jeff Sharkey                    linkFiles(fromFiles, toDir);
50588d2a3c0e1b4a8c53a489db5d627beb80b1b9957Jeff Sharkey                } else {
506941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                    // TODO: this should delegate to DCS so the system process
507941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                    // avoids holding open FDs into containers.
50888d2a3c0e1b4a8c53a489db5d627beb80b1b9957Jeff Sharkey                    copyFiles(fromFiles, toDir);
509941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                }
510941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            } catch (IOException e) {
511941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
512941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                        "Failed to inherit existing install", e);
513941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            }
5143a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
5153a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
516a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        // TODO: surface more granular state from dexopt
51777d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        mInternalProgress = 0.5f;
51877d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        computeProgressLocked(true);
519a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
520941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        // Unpack native libraries
521941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        extractNativeLibraries(mResolvedStageDir, params.abiOverride);
522941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey
523941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        // Container is ready to go, let's seal it up!
524941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        if (stageCid != null) {
525941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            finalizeAndFixContainer(stageCid);
526941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        }
5273a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
5283a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        // We've reached point of no return; call into PMS to install the stage.
5293a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        // Regardless of success or failure we always destroy session.
5303a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        final IPackageInstallObserver2 localObserver = new IPackageInstallObserver2.Stub() {
5313a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            @Override
532fbd0e9fa37fc17ccd25e4c1f16195bbd27de3c4cJeff Sharkey            public void onUserActionRequired(Intent intent) {
533fbd0e9fa37fc17ccd25e4c1f16195bbd27de3c4cJeff Sharkey                throw new IllegalStateException();
534fbd0e9fa37fc17ccd25e4c1f16195bbd27de3c4cJeff Sharkey            }
535fbd0e9fa37fc17ccd25e4c1f16195bbd27de3c4cJeff Sharkey
536fbd0e9fa37fc17ccd25e4c1f16195bbd27de3c4cJeff Sharkey            @Override
537fbd0e9fa37fc17ccd25e4c1f16195bbd27de3c4cJeff Sharkey            public void onPackageInstalled(String basePackageName, int returnCode, String msg,
538fbd0e9fa37fc17ccd25e4c1f16195bbd27de3c4cJeff Sharkey                    Bundle extras) {
539a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey                destroyInternal();
5407328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey                dispatchSessionFinished(returnCode, msg, extras);
5413a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
5423a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        };
5433a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
544e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey        final UserHandle user;
545e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey        if ((params.installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {
546e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey            user = UserHandle.ALL;
547e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey        } else {
548e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey            user = new UserHandle(userId);
549e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey        }
550e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey
551e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey        mPm.installStage(mPackageName, stageDir, stageCid, localObserver, params,
552e980804df16c968c14a56b8853886bf5f049f46eJeff Sharkey                installerPackageName, installerUid, user);
5533a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
5543a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
5553a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    /**
5563a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey     * Validate install by confirming that all application packages are have
5573a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey     * consistent package name, version code, and signing certificates.
5583a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey     * <p>
559941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey     * Clears and populates {@link #mResolvedBaseFile},
560941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey     * {@link #mResolvedStagedFiles}, and {@link #mResolvedInheritedFiles}.
561941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey     * <p>
5623a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey     * Renames package files in stage to match split names defined inside.
563bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey     * <p>
564bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey     * Note that upgrade compatibility is still performed by
565bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey     * {@link PackageManagerService}.
5663a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey     */
567941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey    private void validateInstallLocked() throws PackageManagerException {
5683a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        mPackageName = null;
5693a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        mVersionCode = -1;
5701cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        mSignatures = null;
5713a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
572941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        mResolvedBaseFile = null;
573941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        mResolvedStagedFiles.clear();
574941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        mResolvedInheritedFiles.clear();
575941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey
576941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        final File[] files = mResolvedStageDir.listFiles();
5773a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        if (ArrayUtils.isEmpty(files)) {
578e0b0bef75b66f0a87039c8f58c17b1596a2baebeJeff Sharkey            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged");
5793a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
5803a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
5813a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        // Verify that all staged packages are internally consistent
582941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        final ArraySet<String> stagedSplits = new ArraySet<>();
5833a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        for (File file : files) {
584bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey
585bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            // Installers can't stage directories, so it's fine to ignore
586bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            // entries like "lost+found".
587bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            if (file.isDirectory()) continue;
588bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey
589941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            final ApkLite apk;
590275e085d5a42ced54bb79e40ff76c77539e7d82dJeff Sharkey            try {
591941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                apk = PackageParser.parseApkLite(file, PackageParser.PARSE_COLLECT_CERTIFICATES);
592275e085d5a42ced54bb79e40ff76c77539e7d82dJeff Sharkey            } catch (PackageParserException e) {
593bc09755e193c2802d2d88871ac3d1f182b260c30Jeff Sharkey                throw PackageManagerException.from(e);
5943a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
5953a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
596941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            if (!stagedSplits.add(apk.splitName)) {
597e0b0bef75b66f0a87039c8f58c17b1596a2baebeJeff Sharkey                throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
598941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                        "Split " + apk.splitName + " was defined multiple times");
5993a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
6003a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
6013a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            // Use first package to define unknown values
602ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey            if (mPackageName == null) {
603941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                mPackageName = apk.packageName;
604941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                mVersionCode = apk.versionCode;
6053a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
606ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey            if (mSignatures == null) {
607941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                mSignatures = apk.signatures;
6083a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
6093a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
610941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            assertApkConsistent(String.valueOf(file), apk);
6113a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
6123a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            // Take this opportunity to enforce uniform naming
6137328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey            final String targetName;
614941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            if (apk.splitName == null) {
6157328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey                targetName = "base.apk";
6163a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            } else {
617941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                targetName = "split_" + apk.splitName + ".apk";
6183a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
6197328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey            if (!FileUtils.isValidExtFilename(targetName)) {
620e0b0bef75b66f0a87039c8f58c17b1596a2baebeJeff Sharkey                throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
6217328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey                        "Invalid filename: " + targetName);
6227328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey            }
6237328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey
624941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            final File targetFile = new File(mResolvedStageDir, targetName);
6257328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey            if (!file.equals(targetFile)) {
6267328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey                file.renameTo(targetFile);
6273a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
6287328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey
6297328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey            // Base is coming from session
630941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            if (apk.splitName == null) {
631941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                mResolvedBaseFile = targetFile;
6323a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
633941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey
634941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            mResolvedStagedFiles.add(targetFile);
6353a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
6363a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
637a0907436c01fd8c545a6b5c7b28bc3bc9db59270Jeff Sharkey        if (params.mode == SessionParams.MODE_FULL_INSTALL) {
6383a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            // Full installs must include a base package
639941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            if (!stagedSplits.contains(null)) {
640e0b0bef75b66f0a87039c8f58c17b1596a2baebeJeff Sharkey                throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
6413a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                        "Full install must include a base package");
6423a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
6433a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
6443a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        } else {
6457328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey            // Partial installs must be consistent with existing install
6463a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            final ApplicationInfo app = mPm.getApplicationInfo(mPackageName, 0, userId);
6473a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            if (app == null) {
648e0b0bef75b66f0a87039c8f58c17b1596a2baebeJeff Sharkey                throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
6493a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                        "Missing existing base package for " + mPackageName);
6503a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
6513a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
652941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            final PackageLite existing;
653941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            final ApkLite existingBase;
654275e085d5a42ced54bb79e40ff76c77539e7d82dJeff Sharkey            try {
655941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                existing = PackageParser.parsePackageLite(new File(app.getCodePath()), 0);
656941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                existingBase = PackageParser.parseApkLite(new File(app.getBaseCodePath()),
657bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                        PackageParser.PARSE_COLLECT_CERTIFICATES);
658275e085d5a42ced54bb79e40ff76c77539e7d82dJeff Sharkey            } catch (PackageParserException e) {
659bc09755e193c2802d2d88871ac3d1f182b260c30Jeff Sharkey                throw PackageManagerException.from(e);
660941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            }
661941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey
662941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            assertApkConsistent("Existing base", existingBase);
663941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey
664941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            // Inherit base if not overridden
665941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            if (mResolvedBaseFile == null) {
666941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                mResolvedBaseFile = new File(app.getBaseCodePath());
667941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                mResolvedInheritedFiles.add(mResolvedBaseFile);
6683a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
6693a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
670941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            // Inherit splits if not overridden
671941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            if (!ArrayUtils.isEmpty(existing.splitNames)) {
672941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                for (int i = 0; i < existing.splitNames.length; i++) {
673941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                    final String splitName = existing.splitNames[i];
674941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                    final File splitFile = new File(existing.splitCodePaths[i]);
675941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey
676941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                    if (!stagedSplits.contains(splitName)) {
677941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                        mResolvedInheritedFiles.add(splitFile);
678941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                    }
679941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                }
680941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            }
6813a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
6823a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
6833a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
684941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey    private void assertApkConsistent(String tag, ApkLite apk) throws PackageManagerException {
685941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        if (!mPackageName.equals(apk.packageName)) {
686e0b0bef75b66f0a87039c8f58c17b1596a2baebeJeff Sharkey            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " package "
687941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                    + apk.packageName + " inconsistent with " + mPackageName);
6883a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
689941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        if (mVersionCode != apk.versionCode) {
690e0b0bef75b66f0a87039c8f58c17b1596a2baebeJeff Sharkey            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
691941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                    + " version code " + apk.versionCode + " inconsistent with "
6923a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                    + mVersionCode);
6933a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
694941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        if (!Signature.areExactMatch(mSignatures, apk.signatures)) {
695e0b0bef75b66f0a87039c8f58c17b1596a2baebeJeff Sharkey            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
6963a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                    tag + " signatures are inconsistent");
6973a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
6983a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
6993a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
7003a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    /**
701941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey     * Calculate the final install footprint size, combining both staged and
702941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey     * existing APKs together and including unpacked native code from both.
7033a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey     */
704941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey    private long calculateInstalledSize() throws PackageManagerException {
705941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        Preconditions.checkNotNull(mResolvedBaseFile);
7063a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
707941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        final ApkLite baseApk;
708941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        try {
709941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            baseApk = PackageParser.parseApkLite(mResolvedBaseFile, 0);
710941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        } catch (PackageParserException e) {
711bc09755e193c2802d2d88871ac3d1f182b260c30Jeff Sharkey            throw PackageManagerException.from(e);
712941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        }
7133a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
714941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        final List<String> splitPaths = new ArrayList<>();
715941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        for (File file : mResolvedStagedFiles) {
716941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            if (mResolvedBaseFile.equals(file)) continue;
717941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            splitPaths.add(file.getAbsolutePath());
718941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        }
719941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        for (File file : mResolvedInheritedFiles) {
720941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            if (mResolvedBaseFile.equals(file)) continue;
721941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            splitPaths.add(file.getAbsolutePath());
722941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        }
723941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey
724941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        // This is kind of hacky; we're creating a half-parsed package that is
725941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        // straddled between the inherited and staged APKs.
726941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        final PackageLite pkg = new PackageLite(null, baseApk, null,
72788d2a3c0e1b4a8c53a489db5d627beb80b1b9957Jeff Sharkey                splitPaths.toArray(new String[splitPaths.size()]), null);
728941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        final boolean isForwardLocked =
729941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                (params.installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0;
730941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey
731941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        try {
732941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            return PackageHelper.calculateInstalledSize(pkg, isForwardLocked, params.abiOverride);
733941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        } catch (IOException e) {
734941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
735941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                    "Failed to calculate install size", e);
736941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        }
737941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey    }
738941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey
73988d2a3c0e1b4a8c53a489db5d627beb80b1b9957Jeff Sharkey    /**
74088d2a3c0e1b4a8c53a489db5d627beb80b1b9957Jeff Sharkey     * Determine if creating hard links between source and destination is
74188d2a3c0e1b4a8c53a489db5d627beb80b1b9957Jeff Sharkey     * possible. That is, do they all live on the same underlying device.
74288d2a3c0e1b4a8c53a489db5d627beb80b1b9957Jeff Sharkey     */
74388d2a3c0e1b4a8c53a489db5d627beb80b1b9957Jeff Sharkey    private boolean isLinkPossible(List<File> fromFiles, File toDir) {
74488d2a3c0e1b4a8c53a489db5d627beb80b1b9957Jeff Sharkey        try {
74588d2a3c0e1b4a8c53a489db5d627beb80b1b9957Jeff Sharkey            final StructStat toStat = Os.stat(toDir.getAbsolutePath());
74688d2a3c0e1b4a8c53a489db5d627beb80b1b9957Jeff Sharkey            for (File fromFile : fromFiles) {
74788d2a3c0e1b4a8c53a489db5d627beb80b1b9957Jeff Sharkey                final StructStat fromStat = Os.stat(fromFile.getAbsolutePath());
74888d2a3c0e1b4a8c53a489db5d627beb80b1b9957Jeff Sharkey                if (fromStat.st_dev != toStat.st_dev) {
74988d2a3c0e1b4a8c53a489db5d627beb80b1b9957Jeff Sharkey                    return false;
75088d2a3c0e1b4a8c53a489db5d627beb80b1b9957Jeff Sharkey                }
75188d2a3c0e1b4a8c53a489db5d627beb80b1b9957Jeff Sharkey            }
75288d2a3c0e1b4a8c53a489db5d627beb80b1b9957Jeff Sharkey        } catch (ErrnoException e) {
75388d2a3c0e1b4a8c53a489db5d627beb80b1b9957Jeff Sharkey            Slog.w(TAG, "Failed to detect if linking possible: " + e);
75488d2a3c0e1b4a8c53a489db5d627beb80b1b9957Jeff Sharkey            return false;
75588d2a3c0e1b4a8c53a489db5d627beb80b1b9957Jeff Sharkey        }
75688d2a3c0e1b4a8c53a489db5d627beb80b1b9957Jeff Sharkey        return true;
75788d2a3c0e1b4a8c53a489db5d627beb80b1b9957Jeff Sharkey    }
75888d2a3c0e1b4a8c53a489db5d627beb80b1b9957Jeff Sharkey
759941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey    private static void linkFiles(List<File> fromFiles, File toDir) throws IOException {
760941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        for (File fromFile : fromFiles) {
761941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            final File toFile = new File(toDir, fromFile.getName());
762941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            try {
763941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                if (LOGD) Slog.d(TAG, "Linking " + fromFile + " to " + toFile);
764941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                Os.link(fromFile.getAbsolutePath(), toFile.getAbsolutePath());
765941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            } catch (ErrnoException e) {
766941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                throw new IOException("Failed to link " + fromFile + " to " + toFile, e);
767941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            }
768941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        }
769941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        Slog.d(TAG, "Linked " + fromFiles.size() + " files into " + toDir);
770941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey    }
771941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey
772941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey    private static void copyFiles(List<File> fromFiles, File toDir) throws IOException {
773941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        // Remove any partial files from previous attempt
774941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        for (File file : toDir.listFiles()) {
775941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            if (file.getName().endsWith(".tmp")) {
776941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                file.delete();
777941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            }
778941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        }
779941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey
780941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        for (File fromFile : fromFiles) {
781941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            final File tmpFile = File.createTempFile("inherit", ".tmp", toDir);
782941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            if (LOGD) Slog.d(TAG, "Copying " + fromFile + " to " + tmpFile);
783941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            if (!FileUtils.copyFile(fromFile, tmpFile)) {
784941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                throw new IOException("Failed to copy " + fromFile + " to " + tmpFile);
785941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            }
78688d2a3c0e1b4a8c53a489db5d627beb80b1b9957Jeff Sharkey            try {
78788d2a3c0e1b4a8c53a489db5d627beb80b1b9957Jeff Sharkey                Os.chmod(tmpFile.getAbsolutePath(), 0644);
78888d2a3c0e1b4a8c53a489db5d627beb80b1b9957Jeff Sharkey            } catch (ErrnoException e) {
78988d2a3c0e1b4a8c53a489db5d627beb80b1b9957Jeff Sharkey                throw new IOException("Failed to chmod " + tmpFile);
79088d2a3c0e1b4a8c53a489db5d627beb80b1b9957Jeff Sharkey            }
791941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            final File toFile = new File(toDir, fromFile.getName());
792941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            if (LOGD) Slog.d(TAG, "Renaming " + tmpFile + " to " + toFile);
793941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            if (!tmpFile.renameTo(toFile)) {
794941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                throw new IOException("Failed to rename " + tmpFile + " to " + toFile);
795941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            }
796941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        }
797941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        Slog.d(TAG, "Copied " + fromFiles.size() + " files into " + toDir);
798941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey    }
799941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey
800941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey    private static void extractNativeLibraries(File packageDir, String abiOverride)
801941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            throws PackageManagerException {
802941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        // Always start from a clean slate
803941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        final File libDir = new File(packageDir, NativeLibraryHelper.LIB_DIR_NAME);
804941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        NativeLibraryHelper.removeNativeBinariesFromDirLI(libDir, true);
805941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey
806941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        NativeLibraryHelper.Handle handle = null;
807941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        try {
808941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            handle = NativeLibraryHelper.Handle.create(packageDir);
809941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            final int res = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libDir,
810941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                    abiOverride);
811941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            if (res != PackageManager.INSTALL_SUCCEEDED) {
812941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                throw new PackageManagerException(res,
813941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                        "Failed to extract native libraries, res=" + res);
8143a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
815941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        } catch (IOException e) {
816941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
817941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                    "Failed to extract native libraries", e);
818941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        } finally {
819941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            IoUtils.closeQuietly(handle);
820941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        }
821941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey    }
822941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey
823941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey    private static void resizeContainer(String cid, long targetSize)
824941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            throws PackageManagerException {
825941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        String path = PackageHelper.getSdDir(cid);
826941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        if (path == null) {
827941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
828941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                    "Failed to find mounted " + cid);
829941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        }
830941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey
831941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        final long currentSize = new File(path).getTotalSpace();
832941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        if (currentSize > targetSize) {
833941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            Slog.w(TAG, "Current size " + currentSize + " is larger than target size "
834941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                    + targetSize + "; skipping resize");
835941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            return;
836941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        }
837941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey
838941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        if (!PackageHelper.unMountSdDir(cid)) {
839941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
840941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                    "Failed to unmount " + cid + " before resize");
8413a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
8429a445771f57dd15b06db0dbefd66c368d84eec2dJeff Sharkey
843941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        if (!PackageHelper.resizeSdDir(targetSize, cid,
844941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                PackageManagerService.getEncryptKey())) {
845941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
846941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                    "Failed to resize " + cid + " to " + targetSize + " bytes");
847941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        }
848941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey
849941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        path = PackageHelper.mountSdDir(cid, PackageManagerService.getEncryptKey(),
850941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                Process.SYSTEM_UID, false);
851941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        if (path == null) {
852941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
853941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                    "Failed to mount " + cid + " after resize");
854941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        }
855941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey    }
856941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey
857941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey    private void finalizeAndFixContainer(String cid) throws PackageManagerException {
858941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        if (!PackageHelper.finalizeSdDir(cid)) {
859941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
860941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                    "Failed to finalize container " + cid);
861941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        }
862941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey
863941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        final int uid = mPm.getPackageUid(PackageManagerService.DEFAULT_CONTAINER_PACKAGE,
864941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                UserHandle.USER_OWNER);
865941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        final int gid = UserHandle.getSharedAppGid(uid);
866941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        if (!PackageHelper.fixSdPermissions(cid, gid, null)) {
867941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
868941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                    "Failed to fix permissions on container " + cid);
869941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        }
8703a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
8713a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
8727328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey    void setPermissionsResult(boolean accepted) {
8737328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey        if (!mSealed) {
8747328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey            throw new SecurityException("Must be sealed to accept permissions");
8757328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey        }
8767328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey
8777328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey        if (accepted) {
8787328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey            // Mark and kick off another install pass
8797328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey            mPermissionsAccepted = true;
8807328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey            mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
8817328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey        } else {
8827328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey            destroyInternal();
883f06009542390472872da986486d385001e91a2a7Jeff Sharkey            dispatchSessionFinished(INSTALL_FAILED_ABORTED, "User rejected permissions", null);
8847328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey        }
8857328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey    }
8867328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey
88777d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey    public void open() throws IOException {
88877d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        if (mActiveCount.getAndIncrement() == 0) {
889bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey            mCallback.onSessionActiveChanged(this, true);
890742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        }
89177d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey
89277d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        synchronized (mLock) {
89377d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            if (!mPrepared) {
89477d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey                if (stageDir != null) {
89577d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey                    prepareInternalStageDir(stageDir);
89677d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey                } else if (stageCid != null) {
89777d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey                    prepareExternalStageCid(stageCid, params.sizeBytes);
89877d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey
89977d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey                    // TODO: deliver more granular progress for ASEC allocation
90077d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey                    mInternalProgress = 0.25f;
90177d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey                    computeProgressLocked(true);
90277d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey                } else {
90377d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey                    throw new IllegalArgumentException(
90477d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey                            "Exactly one of stageDir or stageCid stage must be set");
90577d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey                }
90677d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey
90777d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey                mPrepared = true;
90877d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey                mCallback.onSessionPrepared(this);
90977d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            }
91077d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        }
911742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    }
912742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
9133a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    @Override
91416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey    public void close() {
91577d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey        if (mActiveCount.decrementAndGet() == 0) {
916bc7bce38b2e4733a14f6296c75f983bd50f996d1Jeff Sharkey            mCallback.onSessionActiveChanged(this, false);
9171cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        }
91816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey    }
91916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey
92016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey    @Override
92116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey    public void abandon() {
9227328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey        destroyInternal();
923f06009542390472872da986486d385001e91a2a7Jeff Sharkey        dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned", null);
9247328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey    }
9257328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey
9267328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey    private void dispatchSessionFinished(int returnCode, String msg, Bundle extras) {
9277328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey        mFinalStatus = returnCode;
9287328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey        mFinalMessage = msg;
9297328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey
9307328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey        if (mRemoteObserver != null) {
9317328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey            try {
9327328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey                mRemoteObserver.onPackageInstalled(mPackageName, returnCode, msg, extras);
9337328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey            } catch (RemoteException ignored) {
9347328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey            }
935a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        }
9367328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey
9377328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey        final boolean success = (returnCode == PackageManager.INSTALL_SUCCEEDED);
9387328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey        mCallback.onSessionFinished(this, success);
939a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey    }
940a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
941a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey    private void destroyInternal() {
942a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        synchronized (mLock) {
9431cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            mSealed = true;
9441cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey            mDestroyed = true;
94577d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey
94677d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            // Force shut down all bridges
94777d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            for (FileBridge bridge : mBridges) {
94877d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey                bridge.forceClose();
94977d218e1869e69c8d436b09cd11dcfe45e50b2cfJeff Sharkey            }
9503a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
951941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        if (stageDir != null) {
952941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            FileUtils.deleteContents(stageDir);
953941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            stageDir.delete();
954742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        }
955941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        if (stageCid != null) {
956941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            PackageHelper.destroySdDir(stageCid);
957742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        }
958a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey    }
959a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
960a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey    void dump(IndentingPrintWriter pw) {
961742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        synchronized (mLock) {
962742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            dumpLocked(pw);
963742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        }
964742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    }
965742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey
966742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey    private void dumpLocked(IndentingPrintWriter pw) {
967a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        pw.println("Session " + sessionId + ":");
968a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        pw.increaseIndent();
969a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
970a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        pw.printPair("userId", userId);
971a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        pw.printPair("installerPackageName", installerPackageName);
972a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        pw.printPair("installerUid", installerUid);
973a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        pw.printPair("createdMillis", createdMillis);
974941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        pw.printPair("stageDir", stageDir);
975941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        pw.printPair("stageCid", stageCid);
976a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        pw.println();
977a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
978a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        params.dump(pw);
979a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
980a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        pw.printPair("mClientProgress", mClientProgress);
981a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        pw.printPair("mProgress", mProgress);
9821cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        pw.printPair("mSealed", mSealed);
9837328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey        pw.printPair("mPermissionsAccepted", mPermissionsAccepted);
9841cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey        pw.printPair("mDestroyed", mDestroyed);
985a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        pw.printPair("mBridges", mBridges.size());
9867328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey        pw.printPair("mFinalStatus", mFinalStatus);
9877328a1b39b3dae1c0cd390c0a3695c6a46b8e9d8Jeff Sharkey        pw.printPair("mFinalMessage", mFinalMessage);
988a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        pw.println();
989a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
990a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        pw.decreaseIndent();
9913a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
9923a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey}
993