PackageInstallerSession.java revision 2f5811dcfd840e149851a9333e27ef3cdddf7a46
11ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot/*
21ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot * Copyright (C) 2014 The Android Open Source Project
3c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin *
41ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot * Licensed under the Apache License, Version 2.0 (the "License");
51ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot * you may not use this file except in compliance with the License.
61ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot * You may obtain a copy of the License at
7c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin *
8c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin *      http://www.apache.org/licenses/LICENSE-2.0
9c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin *
10c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin * Unless required by applicable law or agreed to in writing, software
11c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin * distributed under the License is distributed on an "AS IS" BASIS,
1232dc498f7b8622c59d4b77117eb971ed0a553be5Paul Duffin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin * See the License for the specific language governing permissions and
14c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin * limitations under the License.
15c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin */
16c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin
17c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinpackage com.android.server.pm;
18c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin
19c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport static android.content.pm.PackageManager.INSTALL_FAILED_ABORTED;
20c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport static android.content.pm.PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
21c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
2232dc498f7b8622c59d4b77117eb971ed0a553be5Paul Duffinimport static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
23c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
24c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport static android.system.OsConstants.O_CREAT;
25c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport static android.system.OsConstants.O_RDONLY;
26c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport static android.system.OsConstants.O_WRONLY;
27c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport static com.android.server.pm.PackageInstallerService.prepareExternalStageCid;
28c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport static com.android.server.pm.PackageInstallerService.prepareStageDir;
29c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin
30c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport android.app.admin.DevicePolicyManager;
31c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport android.content.Context;
3232dc498f7b8622c59d4b77117eb971ed0a553be5Paul Duffinimport android.content.Intent;
33c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport android.content.IntentSender;
34c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport android.content.pm.ApplicationInfo;
35c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport android.content.pm.IPackageInstallObserver2;
36c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport android.content.pm.IPackageInstallerSession;
37c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport android.content.pm.PackageInfo;
38c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport android.content.pm.PackageInstaller;
39c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport android.content.pm.PackageInstaller.SessionInfo;
40c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport android.content.pm.PackageInstaller.SessionParams;
41c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport android.content.pm.PackageManager;
4232dc498f7b8622c59d4b77117eb971ed0a553be5Paul Duffinimport android.content.pm.PackageParser;
43c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport android.content.pm.PackageParser.ApkLite;
44c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport android.content.pm.PackageParser.PackageLite;
45c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport android.content.pm.PackageParser.PackageParserException;
46c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport android.content.pm.Signature;
47c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport android.os.Binder;
48c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport android.os.Bundle;
49c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport android.os.FileBridge;
50c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport android.os.FileUtils;
51c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport android.os.Handler;
52c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport android.os.Looper;
53c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport android.os.Message;
54c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport android.os.ParcelFileDescriptor;
55c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport android.os.Process;
56c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport android.os.RemoteException;
57c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport android.os.SELinux;
58c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport android.os.UserHandle;
59c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport android.system.ErrnoException;
60c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport android.system.Os;
61c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport android.system.OsConstants;
62c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport android.system.StructStat;
63c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport android.text.TextUtils;
64c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport android.util.ArraySet;
65c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport android.util.ExceptionUtils;
66c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport android.util.MathUtils;
67c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport android.util.Slog;
681ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot
69c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport libcore.io.IoUtils;
70c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport libcore.io.Libcore;
71c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin
72c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport com.android.internal.annotations.GuardedBy;
73c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport com.android.internal.content.NativeLibraryHelper;
74c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport com.android.internal.content.PackageHelper;
75c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport com.android.internal.util.ArrayUtils;
76c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport com.android.internal.util.IndentingPrintWriter;
77c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport com.android.internal.util.Preconditions;
78c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport com.android.server.pm.Installer.InstallerException;
79c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport com.android.server.pm.PackageInstallerService.PackageInstallObserverAdapter;
80c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin
81c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport java.io.File;
82c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport java.io.FileDescriptor;
83c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport java.io.FileFilter;
84c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport java.io.IOException;
85c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport java.security.cert.Certificate;
86c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport java.util.ArrayList;
87c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport java.util.Arrays;
88c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport java.util.List;
89c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinimport java.util.concurrent.atomic.AtomicInteger;
90c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin
91c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffinpublic class PackageInstallerSession extends IPackageInstallerSession.Stub {
92c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    private static final String TAG = "PackageInstaller";
93c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    private static final boolean LOGD = true;
94c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    private static final String REMOVE_SPLIT_MARKER_EXTENSION = ".removed";
95c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin
96c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    private static final int MSG_COMMIT = 0;
97c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin
98c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    // TODO: enforce INSTALL_ALLOW_TEST
99c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    // TODO: enforce INSTALL_ALLOW_DOWNGRADE
100c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin
1011ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot    private final PackageInstallerService.InternalCallback mCallback;
1021ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot    private final Context mContext;
1031ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot    private final PackageManagerService mPm;
1041ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot    private final Handler mHandler;
1051ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot    private final boolean mIsInstallerDeviceOwner;
1061ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot
107c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    final int sessionId;
108c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    final int userId;
109c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    final String installerPackageName;
110c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    final int installerUid;
111c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    final SessionParams params;
1121ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot    final long createdMillis;
1131ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot    final int defaultContainerGid;
1141ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot
1151ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot    /** Staging location where client data is written. */
1161ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot    final File stageDir;
1171ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot    final String stageCid;
1189599ee2623bb76c0c7f840ba8bfd92a6ecf74390Paul Duffin
1199599ee2623bb76c0c7f840ba8bfd92a6ecf74390Paul Duffin    private final AtomicInteger mActiveCount = new AtomicInteger();
1209599ee2623bb76c0c7f840ba8bfd92a6ecf74390Paul Duffin
1219599ee2623bb76c0c7f840ba8bfd92a6ecf74390Paul Duffin    private final Object mLock = new Object();
1229599ee2623bb76c0c7f840ba8bfd92a6ecf74390Paul Duffin
1239599ee2623bb76c0c7f840ba8bfd92a6ecf74390Paul Duffin    @GuardedBy("mLock")
1249599ee2623bb76c0c7f840ba8bfd92a6ecf74390Paul Duffin    private float mClientProgress = 0;
1259599ee2623bb76c0c7f840ba8bfd92a6ecf74390Paul Duffin    @GuardedBy("mLock")
1269599ee2623bb76c0c7f840ba8bfd92a6ecf74390Paul Duffin    private float mInternalProgress = 0;
1279599ee2623bb76c0c7f840ba8bfd92a6ecf74390Paul Duffin
1289599ee2623bb76c0c7f840ba8bfd92a6ecf74390Paul Duffin    @GuardedBy("mLock")
1299599ee2623bb76c0c7f840ba8bfd92a6ecf74390Paul Duffin    private float mProgress = 0;
1309599ee2623bb76c0c7f840ba8bfd92a6ecf74390Paul Duffin    @GuardedBy("mLock")
1319599ee2623bb76c0c7f840ba8bfd92a6ecf74390Paul Duffin    private float mReportedProgress = -1;
1329599ee2623bb76c0c7f840ba8bfd92a6ecf74390Paul Duffin
1339599ee2623bb76c0c7f840ba8bfd92a6ecf74390Paul Duffin    @GuardedBy("mLock")
134c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    private boolean mPrepared = false;
135c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    @GuardedBy("mLock")
136c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    private boolean mSealed = false;
137c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    @GuardedBy("mLock")
138c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    private boolean mPermissionsAccepted = false;
1391ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot    @GuardedBy("mLock")
140c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    private boolean mRelinquished = false;
141c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    @GuardedBy("mLock")
1421ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot    private boolean mDestroyed = false;
1431ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot
1441ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot    private int mFinalStatus;
145c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    private String mFinalMessage;
1461ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot
147c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    @GuardedBy("mLock")
148c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    private ArrayList<FileBridge> mBridges = new ArrayList<>();
1491ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot
1501ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot    @GuardedBy("mLock")
1511ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot    private IPackageInstallObserver2 mRemoteObserver;
152c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin
153c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    /** Fields derived from commit parsing */
1541ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot    private String mPackageName;
155c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    private int mVersionCode;
156c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    private Signature[] mSignatures;
1571ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot    private Certificate[][] mCertificates;
158c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin
159c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    /**
1601ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot     * Path to the validated base APK for this session, which may point at an
1611ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot     * APK inside the session (when the session defines the base), or it may
1621ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot     * point at the existing base APK (when adding splits to an existing app).
163c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin     * <p>
164c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin     * This is used when confirming permissions, since we can't fully stage the
165c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin     * session inside an ASEC before confirming with user.
166c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin     */
167c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    @GuardedBy("mLock")
168c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    private File mResolvedBaseFile;
169c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin
170c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    @GuardedBy("mLock")
171c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    private File mResolvedStageDir;
1721ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot
173c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    @GuardedBy("mLock")
17432dc498f7b8622c59d4b77117eb971ed0a553be5Paul Duffin    private final List<File> mResolvedStagedFiles = new ArrayList<>();
1751ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot    @GuardedBy("mLock")
1761ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot    private final List<File> mResolvedInheritedFiles = new ArrayList<>();
1771ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot    @GuardedBy("mLock")
178c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    private final List<String> mResolvedInstructionSets = new ArrayList<>();
179c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    @GuardedBy("mLock")
180c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    private File mInheritedFilesBase;
181c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin
182c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    private static final FileFilter sAddedFilter = new FileFilter() {
183c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        @Override
184c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        public boolean accept(File file) {
185c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            // Installers can't stage directories, so it's fine to ignore
186c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            // entries like "lost+found".
1871ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot            if (file.isDirectory()) return false;
188c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            if (file.getName().endsWith(REMOVE_SPLIT_MARKER_EXTENSION)) return false;
18932dc498f7b8622c59d4b77117eb971ed0a553be5Paul Duffin            return true;
1901ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot        }
1911ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot    };
1921ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot    private static final FileFilter sRemovedFilter = new FileFilter() {
193c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        @Override
194c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        public boolean accept(File file) {
195c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            if (file.isDirectory()) return false;
196c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            if (!file.getName().endsWith(REMOVE_SPLIT_MARKER_EXTENSION)) return false;
197c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            return true;
198c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        }
199c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    };
200c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin
201c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    private final Handler.Callback mHandlerCallback = new Handler.Callback() {
2021ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot        @Override
203c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        public boolean handleMessage(Message msg) {
204c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            // Cache package manager data without the lock held
20532dc498f7b8622c59d4b77117eb971ed0a553be5Paul Duffin            final PackageInfo pkgInfo = mPm.getPackageInfo(
2061ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot                    params.appPackageName, PackageManager.GET_SIGNATURES /*flags*/, userId);
2071ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot            final ApplicationInfo appInfo = mPm.getApplicationInfo(
2081ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot                    params.appPackageName, 0, userId);
209c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin
210c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            synchronized (mLock) {
211c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin                if (msg.obj != null) {
212c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin                    mRemoteObserver = (IPackageInstallObserver2) msg.obj;
213c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin                }
214c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin
215c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin                try {
216c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin                    commitLocked(pkgInfo, appInfo);
217c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin                } catch (PackageManagerException e) {
2181ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot                    final String completeMsg = ExceptionUtils.getCompleteMessage(e);
219c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin                    Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg);
220c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin                    destroyInternal();
22132dc498f7b8622c59d4b77117eb971ed0a553be5Paul Duffin                    dispatchSessionFinished(e.error, completeMsg, null);
2221ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot                }
2231ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot
2241ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot                return true;
225c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            }
226c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        }
227c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    };
228c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin
229c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    public PackageInstallerSession(PackageInstallerService.InternalCallback callback,
230c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            Context context, PackageManagerService pm, Looper looper, int sessionId, int userId,
231c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            String installerPackageName, int installerUid, SessionParams params, long createdMillis,
232c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            File stageDir, String stageCid, boolean prepared, boolean sealed) {
233c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        mCallback = callback;
234c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        mContext = context;
235c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        mPm = pm;
236c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        mHandler = new Handler(looper, mHandlerCallback);
237c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin
238c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        this.sessionId = sessionId;
239c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        this.userId = userId;
240c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        this.installerPackageName = installerPackageName;
241c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        this.installerUid = installerUid;
242c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        this.params = params;
243c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        this.createdMillis = createdMillis;
2441ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot        this.stageDir = stageDir;
245c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        this.stageCid = stageCid;
246c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin
2471ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot        if ((stageDir == null) == (stageCid == null)) {
2481ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot            throw new IllegalArgumentException(
2491ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot                    "Exactly one of stageDir or stageCid stage must be set");
250c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        }
251c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin
2521ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot        mPrepared = prepared;
253c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        mSealed = sealed;
254c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin
2551ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot        // Device owners are allowed to silently install packages, so the permission check is
2561ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot        // waived if the installer is the device owner.
2571ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot        DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(
258c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin                Context.DEVICE_POLICY_SERVICE);
259c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        final boolean isPermissionGranted =
260c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin                (mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES, installerUid)
2611ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot                        == PackageManager.PERMISSION_GRANTED);
262c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        final boolean isInstallerRoot = (installerUid == Process.ROOT_UID);
263c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        final boolean forcePermissionPrompt =
264c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin                (params.installFlags & PackageManager.INSTALL_FORCE_PERMISSION_PROMPT) != 0;
265c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        mIsInstallerDeviceOwner = (dpm != null) && dpm.isDeviceOwnerAppOnCallingUser(
266c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin                installerPackageName);
2671ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot        if ((isPermissionGranted
268c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin                        || isInstallerRoot
269c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin                        || mIsInstallerDeviceOwner)
2701ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot                && !forcePermissionPrompt) {
2711ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot            mPermissionsAccepted = true;
2721ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot        } else {
273c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            mPermissionsAccepted = false;
274c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        }
275c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        final long identity = Binder.clearCallingIdentity();
276c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        try {
277c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            final int uid = mPm.getPackageUid(PackageManagerService.DEFAULT_CONTAINER_PACKAGE,
278c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin                    PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
279c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            defaultContainerGid = UserHandle.getSharedAppGid(uid);
2801ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot        } finally {
281c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            Binder.restoreCallingIdentity(identity);
282c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        }
2831ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot    }
2841ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot
2851ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot    public SessionInfo generateInfo() {
286c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        final SessionInfo info = new SessionInfo();
287c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        synchronized (mLock) {
288c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            info.sessionId = sessionId;
289c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            info.installerPackageName = installerPackageName;
2901ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot            info.resolvedBaseCodePath = (mResolvedBaseFile != null) ?
291c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin                    mResolvedBaseFile.getAbsolutePath() : null;
292c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            info.progress = mProgress;
2931ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot            info.sealed = mSealed;
294c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            info.active = mActiveCount.get() > 0;
295c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin
2961ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot            info.mode = params.mode;
2971ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot            info.sizeBytes = params.sizeBytes;
2981ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot            info.appPackageName = params.appPackageName;
299c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            info.appIcon = params.appIcon;
300c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            info.appLabel = params.appLabel;
301c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        }
302c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        return info;
303c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    }
304c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin
305c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    public boolean isPrepared() {
306c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        synchronized (mLock) {
3071ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot            return mPrepared;
308c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        }
309c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    }
310c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin
311c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    public boolean isSealed() {
312c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        synchronized (mLock) {
313c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            return mSealed;
314c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        }
315c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    }
316c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin
317c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    private void assertPreparedAndNotSealed(String cookie) {
318c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        synchronized (mLock) {
319c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            if (!mPrepared) {
320c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin                throw new IllegalStateException(cookie + " before prepared");
3211ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot            }
3221ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot            if (mSealed) {
3231ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot                throw new SecurityException(cookie + " not allowed after commit");
324c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            }
325c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        }
326c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    }
327c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin
328c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    /**
329c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin     * Resolve the actual location where staged data should be written. This
330c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin     * might point at an ASEC mount point, which is why we delay path resolution
331c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin     * until someone actively works with the session.
332c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin     */
3331ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot    private File resolveStageDir() throws IOException {
334c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        synchronized (mLock) {
335c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            if (mResolvedStageDir == null) {
336c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin                if (stageDir != null) {
337c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin                    mResolvedStageDir = stageDir;
338c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin                } else {
339c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin                    final String path = PackageHelper.getSdDir(stageCid);
340c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin                    if (path != null) {
341c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin                        mResolvedStageDir = new File(path);
342c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin                    } else {
343c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin                        throw new IOException("Failed to resolve path to container " + stageCid);
3441ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot                    }
3451ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot                }
3461ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot            }
3471ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot            return mResolvedStageDir;
348c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        }
349c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    }
350c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin
351c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    @Override
352c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    public void setClientProgress(float progress) {
353c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        synchronized (mLock) {
354c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            // Always publish first staging movement
3551ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot            final boolean forcePublish = (mClientProgress == 0);
3561ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot            mClientProgress = progress;
3571ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot            computeProgressLocked(forcePublish);
3581ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot        }
3591ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot    }
3601ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot
361c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    @Override
362c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    public void addClientProgress(float progress) {
363c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        synchronized (mLock) {
364c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            setClientProgress(mClientProgress + progress);
365c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        }
3661ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot    }
367c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin
368c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    private void computeProgressLocked(boolean forcePublish) {
3691ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot        mProgress = MathUtils.constrain(mClientProgress * 0.8f, 0f, 0.8f)
3701ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot                + MathUtils.constrain(mInternalProgress * 0.2f, 0f, 0.2f);
3711ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot
372c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        // Only publish when meaningful change
373c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        if (forcePublish || Math.abs(mProgress - mReportedProgress) >= 0.01) {
374c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            mReportedProgress = mProgress;
375c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            mCallback.onSessionProgressChanged(this, mProgress);
376c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        }
3771ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot    }
378c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin
379c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    @Override
3801ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot    public String[] getNames() {
3811ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot        assertPreparedAndNotSealed("getNames");
3821ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot        try {
383c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            return resolveStageDir().list();
384c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        } catch (IOException e) {
385c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            throw ExceptionUtils.wrap(e);
386c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        }
387c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    }
388c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin
389c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    @Override
3901ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot    public void removeSplit(String splitName) {
391c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        if (TextUtils.isEmpty(params.appPackageName)) {
392c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            throw new IllegalStateException("Must specify package name to remove a split");
393c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        }
394c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        try {
395c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            createRemoveSplitMarker(splitName);
396c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        } catch (IOException e) {
397c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            throw ExceptionUtils.wrap(e);
398c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        }
399c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    }
400c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin
401c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    private void createRemoveSplitMarker(String splitName) throws IOException {
402c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        try {
403c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            final String markerName = splitName + REMOVE_SPLIT_MARKER_EXTENSION;
404c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            if (!FileUtils.isValidExtFilename(markerName)) {
405c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin                throw new IllegalArgumentException("Invalid marker: " + markerName);
406c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            }
407c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            final File target = new File(resolveStageDir(), markerName);
408c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            target.createNewFile();
409c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            Os.chmod(target.getAbsolutePath(), 0 /*mode*/);
410c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        } catch (ErrnoException e) {
411c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            throw e.rethrowAsIOException();
412c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        }
413c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    }
414c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin
415c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    @Override
416c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    public ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes) {
417c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        try {
418c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            return openWriteInternal(name, offsetBytes, lengthBytes);
419c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        } catch (IOException e) {
420c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            throw ExceptionUtils.wrap(e);
421c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        }
422c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    }
423c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin
424c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin    private ParcelFileDescriptor openWriteInternal(String name, long offsetBytes, long lengthBytes)
425c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            throws IOException {
426c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        // Quick sanity check of state, and allocate a pipe for ourselves. We
427c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        // then do heavy disk allocation outside the lock, but this open pipe
428c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        // will block any attempted install transitions.
429c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        final FileBridge bridge;
430c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        synchronized (mLock) {
431c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            assertPreparedAndNotSealed("openWrite");
432c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin
433c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            bridge = new FileBridge();
434c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            mBridges.add(bridge);
435c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        }
436c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin
437c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin        try {
438c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            // Use installer provided name for now; we always rename later
439c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            if (!FileUtils.isValidExtFilename(name)) {
440c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin                throw new IllegalArgumentException("Invalid name: " + name);
441c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            }
442c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            final File target;
443c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            final long identity = Binder.clearCallingIdentity();
444c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            try {
445c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin                target = new File(resolveStageDir(), name);
446c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            } finally {
447c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin                Binder.restoreCallingIdentity(identity);
448c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            }
449c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin
450c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            // TODO: this should delegate to DCS so the system process avoids
451c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            // holding open FDs into containers.
452c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            final FileDescriptor targetFd = Libcore.os.open(target.getAbsolutePath(),
453c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin                    O_CREAT | O_WRONLY, 0644);
454c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            Os.chmod(target.getAbsolutePath(), 0644);
455c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin
456c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            // If caller specified a total length, allocate it for them. Free up
457c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            // cache space to grow, if needed.
458c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin            if (lengthBytes > 0) {
459c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin                final StructStat stat = Libcore.os.fstat(targetFd);
460c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin                final long deltaBytes = lengthBytes - stat.st_size;
461c1dbb44e71e47410ad5685aba3ef3fccb095a2b4Paul Duffin                // Only need to free up space when writing to internal stage
4621ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot                if (stageDir != null && deltaBytes > 0) {
4631ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot                    mPm.freeStorage(params.volumeUuid, deltaBytes);
4641ecfda91236a8970119144e59e0ba6113dc22c0fBrett Chabot                }
465                Libcore.os.posix_fallocate(targetFd, 0, lengthBytes);
466            }
467
468            if (offsetBytes > 0) {
469                Libcore.os.lseek(targetFd, offsetBytes, OsConstants.SEEK_SET);
470            }
471
472            bridge.setTargetFile(targetFd);
473            bridge.start();
474            return new ParcelFileDescriptor(bridge.getClientSocket());
475
476        } catch (ErrnoException e) {
477            throw e.rethrowAsIOException();
478        }
479    }
480
481    @Override
482    public ParcelFileDescriptor openRead(String name) {
483        try {
484            return openReadInternal(name);
485        } catch (IOException e) {
486            throw ExceptionUtils.wrap(e);
487        }
488    }
489
490    private ParcelFileDescriptor openReadInternal(String name) throws IOException {
491        assertPreparedAndNotSealed("openRead");
492
493        try {
494            if (!FileUtils.isValidExtFilename(name)) {
495                throw new IllegalArgumentException("Invalid name: " + name);
496            }
497            final File target = new File(resolveStageDir(), name);
498
499            final FileDescriptor targetFd = Libcore.os.open(target.getAbsolutePath(), O_RDONLY, 0);
500            return new ParcelFileDescriptor(targetFd);
501
502        } catch (ErrnoException e) {
503            throw e.rethrowAsIOException();
504        }
505    }
506
507    @Override
508    public void commit(IntentSender statusReceiver) {
509        Preconditions.checkNotNull(statusReceiver);
510
511        final boolean wasSealed;
512        synchronized (mLock) {
513            wasSealed = mSealed;
514            if (!mSealed) {
515                // Verify that all writers are hands-off
516                for (FileBridge bridge : mBridges) {
517                    if (!bridge.isClosed()) {
518                        throw new SecurityException("Files still open");
519                    }
520                }
521                mSealed = true;
522            }
523
524            // Client staging is fully done at this point
525            mClientProgress = 1f;
526            computeProgressLocked(true);
527        }
528
529        if (!wasSealed) {
530            // Persist the fact that we've sealed ourselves to prevent
531            // mutations of any hard links we create. We do this without holding
532            // the session lock, since otherwise it's a lock inversion.
533            mCallback.onSessionSealedBlocking(this);
534        }
535
536        // This ongoing commit should keep session active, even though client
537        // will probably close their end.
538        mActiveCount.incrementAndGet();
539
540        final PackageInstallObserverAdapter adapter = new PackageInstallObserverAdapter(mContext,
541                statusReceiver, sessionId, mIsInstallerDeviceOwner, userId);
542        mHandler.obtainMessage(MSG_COMMIT, adapter.getBinder()).sendToTarget();
543    }
544
545    private void commitLocked(PackageInfo pkgInfo, ApplicationInfo appInfo)
546            throws PackageManagerException {
547        if (mDestroyed) {
548            throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session destroyed");
549        }
550        if (!mSealed) {
551            throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session not sealed");
552        }
553
554        try {
555            resolveStageDir();
556        } catch (IOException e) {
557            throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
558                    "Failed to resolve stage location", e);
559        }
560
561        // Verify that stage looks sane with respect to existing application.
562        // This currently only ensures packageName, versionCode, and certificate
563        // consistency.
564        validateInstallLocked(pkgInfo, appInfo);
565
566        Preconditions.checkNotNull(mPackageName);
567        Preconditions.checkNotNull(mSignatures);
568        Preconditions.checkNotNull(mResolvedBaseFile);
569
570        if (!mPermissionsAccepted) {
571            // User needs to accept permissions; give installer an intent they
572            // can use to involve user.
573            final Intent intent = new Intent(PackageInstaller.ACTION_CONFIRM_PERMISSIONS);
574            intent.setPackage(mContext.getPackageManager().getPermissionControllerPackageName());
575            intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
576            try {
577                mRemoteObserver.onUserActionRequired(intent);
578            } catch (RemoteException ignored) {
579            }
580
581            // Commit was keeping session marked as active until now; release
582            // that extra refcount so session appears idle.
583            close();
584            return;
585        }
586
587        if (stageCid != null) {
588            // Figure out the final installed size and resize the container once
589            // and for all. Internally the parser handles straddling between two
590            // locations when inheriting.
591            final long finalSize = calculateInstalledSize();
592            resizeContainer(stageCid, finalSize);
593        }
594
595        // Inherit any packages and native libraries from existing install that
596        // haven't been overridden.
597        if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
598            try {
599                final List<File> fromFiles = mResolvedInheritedFiles;
600                final File toDir = resolveStageDir();
601
602                if (LOGD) Slog.d(TAG, "Inherited files: " + mResolvedInheritedFiles);
603                if (!mResolvedInheritedFiles.isEmpty() && mInheritedFilesBase == null) {
604                    throw new IllegalStateException("mInheritedFilesBase == null");
605                }
606
607                if (isLinkPossible(fromFiles, toDir)) {
608                    if (!mResolvedInstructionSets.isEmpty()) {
609                        final File oatDir = new File(toDir, "oat");
610                        createOatDirs(mResolvedInstructionSets, oatDir);
611                    }
612                    linkFiles(fromFiles, toDir, mInheritedFilesBase);
613                } else {
614                    // TODO: this should delegate to DCS so the system process
615                    // avoids holding open FDs into containers.
616                    copyFiles(fromFiles, toDir);
617                }
618            } catch (IOException e) {
619                throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
620                        "Failed to inherit existing install", e);
621            }
622        }
623
624        // TODO: surface more granular state from dexopt
625        mInternalProgress = 0.5f;
626        computeProgressLocked(true);
627
628        // Unpack native libraries
629        extractNativeLibraries(mResolvedStageDir, params.abiOverride);
630
631        // Container is ready to go, let's seal it up!
632        if (stageCid != null) {
633            finalizeAndFixContainer(stageCid);
634        }
635
636        // We've reached point of no return; call into PMS to install the stage.
637        // Regardless of success or failure we always destroy session.
638        final IPackageInstallObserver2 localObserver = new IPackageInstallObserver2.Stub() {
639            @Override
640            public void onUserActionRequired(Intent intent) {
641                throw new IllegalStateException();
642            }
643
644            @Override
645            public void onPackageInstalled(String basePackageName, int returnCode, String msg,
646                    Bundle extras) {
647                destroyInternal();
648                dispatchSessionFinished(returnCode, msg, extras);
649            }
650        };
651
652        final UserHandle user;
653        if ((params.installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {
654            user = UserHandle.ALL;
655        } else {
656            user = new UserHandle(userId);
657        }
658
659        mRelinquished = true;
660        mPm.installStage(mPackageName, stageDir, stageCid, localObserver, params,
661                installerPackageName, installerUid, user, mCertificates);
662    }
663
664    /**
665     * Validate install by confirming that all application packages are have
666     * consistent package name, version code, and signing certificates.
667     * <p>
668     * Clears and populates {@link #mResolvedBaseFile},
669     * {@link #mResolvedStagedFiles}, and {@link #mResolvedInheritedFiles}.
670     * <p>
671     * Renames package files in stage to match split names defined inside.
672     * <p>
673     * Note that upgrade compatibility is still performed by
674     * {@link PackageManagerService}.
675     */
676    private void validateInstallLocked(PackageInfo pkgInfo, ApplicationInfo appInfo)
677            throws PackageManagerException {
678        mPackageName = null;
679        mVersionCode = -1;
680        mSignatures = null;
681
682        mResolvedBaseFile = null;
683        mResolvedStagedFiles.clear();
684        mResolvedInheritedFiles.clear();
685
686        final File[] removedFiles = mResolvedStageDir.listFiles(sRemovedFilter);
687        final List<String> removeSplitList = new ArrayList<>();
688        if (!ArrayUtils.isEmpty(removedFiles)) {
689            for (File removedFile : removedFiles) {
690                final String fileName = removedFile.getName();
691                final String splitName = fileName.substring(
692                        0, fileName.length() - REMOVE_SPLIT_MARKER_EXTENSION.length());
693                removeSplitList.add(splitName);
694            }
695        }
696
697        final File[] addedFiles = mResolvedStageDir.listFiles(sAddedFilter);
698        if (ArrayUtils.isEmpty(addedFiles) && removeSplitList.size() == 0) {
699            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged");
700        }
701        // Verify that all staged packages are internally consistent
702        final ArraySet<String> stagedSplits = new ArraySet<>();
703        for (File addedFile : addedFiles) {
704            final ApkLite apk;
705            try {
706                int flags = PackageParser.PARSE_COLLECT_CERTIFICATES;
707                if ((params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
708                    flags |= PackageParser.PARSE_IS_EPHEMERAL;
709                }
710                apk = PackageParser.parseApkLite(addedFile, flags);
711            } catch (PackageParserException e) {
712                throw PackageManagerException.from(e);
713            }
714
715            if (!stagedSplits.add(apk.splitName)) {
716                throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
717                        "Split " + apk.splitName + " was defined multiple times");
718            }
719
720            // Use first package to define unknown values
721            if (mPackageName == null) {
722                mPackageName = apk.packageName;
723                mVersionCode = apk.versionCode;
724            }
725            if (mSignatures == null) {
726                mSignatures = apk.signatures;
727                mCertificates = apk.certificates;
728            }
729
730            assertApkConsistent(String.valueOf(addedFile), apk);
731
732            // Take this opportunity to enforce uniform naming
733            final String targetName;
734            if (apk.splitName == null) {
735                targetName = "base.apk";
736            } else {
737                targetName = "split_" + apk.splitName + ".apk";
738            }
739            if (!FileUtils.isValidExtFilename(targetName)) {
740                throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
741                        "Invalid filename: " + targetName);
742            }
743
744            final File targetFile = new File(mResolvedStageDir, targetName);
745            if (!addedFile.equals(targetFile)) {
746                addedFile.renameTo(targetFile);
747            }
748
749            // Base is coming from session
750            if (apk.splitName == null) {
751                mResolvedBaseFile = targetFile;
752            }
753
754            mResolvedStagedFiles.add(targetFile);
755        }
756
757        if (removeSplitList.size() > 0) {
758            // validate split names marked for removal
759            for (String splitName : removeSplitList) {
760                if (!ArrayUtils.contains(pkgInfo.splitNames, splitName)) {
761                    throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
762                            "Split not found: " + splitName);
763                }
764            }
765
766            // ensure we've got appropriate package name, version code and signatures
767            if (mPackageName == null) {
768                mPackageName = pkgInfo.packageName;
769                mVersionCode = pkgInfo.versionCode;
770            }
771            if (mSignatures == null) {
772                mSignatures = pkgInfo.signatures;
773            }
774        }
775
776        if (params.mode == SessionParams.MODE_FULL_INSTALL) {
777            // Full installs must include a base package
778            if (!stagedSplits.contains(null)) {
779                throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
780                        "Full install must include a base package");
781            }
782
783        } else {
784            // Partial installs must be consistent with existing install
785            if (appInfo == null) {
786                throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
787                        "Missing existing base package for " + mPackageName);
788            }
789
790            final PackageLite existing;
791            final ApkLite existingBase;
792            try {
793                existing = PackageParser.parsePackageLite(new File(appInfo.getCodePath()), 0);
794                existingBase = PackageParser.parseApkLite(new File(appInfo.getBaseCodePath()),
795                        PackageParser.PARSE_COLLECT_CERTIFICATES);
796            } catch (PackageParserException e) {
797                throw PackageManagerException.from(e);
798            }
799
800            assertApkConsistent("Existing base", existingBase);
801
802            // Inherit base if not overridden
803            if (mResolvedBaseFile == null) {
804                mResolvedBaseFile = new File(appInfo.getBaseCodePath());
805                mResolvedInheritedFiles.add(mResolvedBaseFile);
806            }
807
808            // Inherit splits if not overridden
809            if (!ArrayUtils.isEmpty(existing.splitNames)) {
810                for (int i = 0; i < existing.splitNames.length; i++) {
811                    final String splitName = existing.splitNames[i];
812                    final File splitFile = new File(existing.splitCodePaths[i]);
813                    final boolean splitRemoved = removeSplitList.contains(splitName);
814                    if (!stagedSplits.contains(splitName) && !splitRemoved) {
815                        mResolvedInheritedFiles.add(splitFile);
816                    }
817                }
818            }
819
820            // Inherit compiled oat directory.
821            final File packageInstallDir = (new File(appInfo.getBaseCodePath())).getParentFile();
822            mInheritedFilesBase = packageInstallDir;
823            final File oatDir = new File(packageInstallDir, "oat");
824            if (oatDir.exists()) {
825                final File[] archSubdirs = oatDir.listFiles();
826
827                // Keep track of all instruction sets we've seen compiled output for.
828                // If we're linking (and not copying) inherited files, we can recreate the
829                // instruction set hierarchy and link compiled output.
830                if (archSubdirs != null && archSubdirs.length > 0) {
831                    final String[] instructionSets = InstructionSets.getAllDexCodeInstructionSets();
832                    for (File archSubDir : archSubdirs) {
833                        // Skip any directory that isn't an ISA subdir.
834                        if (!ArrayUtils.contains(instructionSets, archSubDir.getName())) {
835                            continue;
836                        }
837
838                        mResolvedInstructionSets.add(archSubDir.getName());
839                        List<File> oatFiles = Arrays.asList(archSubDir.listFiles());
840                        if (!oatFiles.isEmpty()) {
841                            mResolvedInheritedFiles.addAll(oatFiles);
842                        }
843                    }
844                }
845            }
846        }
847    }
848
849    private void assertApkConsistent(String tag, ApkLite apk)
850            throws PackageManagerException {
851        if (!mPackageName.equals(apk.packageName)) {
852            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " package "
853                    + apk.packageName + " inconsistent with " + mPackageName);
854        }
855        if (params.appPackageName != null && !params.appPackageName.equals(apk.packageName)) {
856            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
857                    + " specified package " + params.appPackageName
858                    + " inconsistent with " + apk.packageName);
859        }
860        if (mVersionCode != apk.versionCode) {
861            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
862                    + " version code " + apk.versionCode + " inconsistent with "
863                    + mVersionCode);
864        }
865        if (!Signature.areExactMatch(mSignatures, apk.signatures)) {
866            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
867                    tag + " signatures are inconsistent");
868        }
869    }
870
871    /**
872     * Calculate the final install footprint size, combining both staged and
873     * existing APKs together and including unpacked native code from both.
874     */
875    private long calculateInstalledSize() throws PackageManagerException {
876        Preconditions.checkNotNull(mResolvedBaseFile);
877
878        final ApkLite baseApk;
879        try {
880            baseApk = PackageParser.parseApkLite(mResolvedBaseFile, 0);
881        } catch (PackageParserException e) {
882            throw PackageManagerException.from(e);
883        }
884
885        final List<String> splitPaths = new ArrayList<>();
886        for (File file : mResolvedStagedFiles) {
887            if (mResolvedBaseFile.equals(file)) continue;
888            splitPaths.add(file.getAbsolutePath());
889        }
890        for (File file : mResolvedInheritedFiles) {
891            if (mResolvedBaseFile.equals(file)) continue;
892            splitPaths.add(file.getAbsolutePath());
893        }
894
895        // This is kind of hacky; we're creating a half-parsed package that is
896        // straddled between the inherited and staged APKs.
897        final PackageLite pkg = new PackageLite(null, baseApk, null, null,
898                splitPaths.toArray(new String[splitPaths.size()]), null);
899        final boolean isForwardLocked =
900                (params.installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0;
901
902        try {
903            return PackageHelper.calculateInstalledSize(pkg, isForwardLocked, params.abiOverride);
904        } catch (IOException e) {
905            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
906                    "Failed to calculate install size", e);
907        }
908    }
909
910    /**
911     * Determine if creating hard links between source and destination is
912     * possible. That is, do they all live on the same underlying device.
913     */
914    private boolean isLinkPossible(List<File> fromFiles, File toDir) {
915        try {
916            final StructStat toStat = Os.stat(toDir.getAbsolutePath());
917            for (File fromFile : fromFiles) {
918                final StructStat fromStat = Os.stat(fromFile.getAbsolutePath());
919                if (fromStat.st_dev != toStat.st_dev) {
920                    return false;
921                }
922            }
923        } catch (ErrnoException e) {
924            Slog.w(TAG, "Failed to detect if linking possible: " + e);
925            return false;
926        }
927        return true;
928    }
929
930    private static String getRelativePath(File file, File base) throws IOException {
931        final String pathStr = file.getAbsolutePath();
932        final String baseStr = base.getAbsolutePath();
933        // Don't allow relative paths.
934        if (pathStr.contains("/.") ) {
935            throw new IOException("Invalid path (was relative) : " + pathStr);
936        }
937
938        if (pathStr.startsWith(baseStr)) {
939            return pathStr.substring(baseStr.length());
940        }
941
942        throw new IOException("File: " + pathStr + " outside base: " + baseStr);
943    }
944
945    private void createOatDirs(List<String> instructionSets, File fromDir)
946            throws PackageManagerException {
947        for (String instructionSet : instructionSets) {
948            try {
949                mPm.mInstaller.createOatDir(fromDir.getAbsolutePath(), instructionSet);
950            } catch (InstallerException e) {
951                throw PackageManagerException.from(e);
952            }
953        }
954    }
955
956    private void linkFiles(List<File> fromFiles, File toDir, File fromDir)
957            throws IOException {
958        for (File fromFile : fromFiles) {
959            final String relativePath = getRelativePath(fromFile, fromDir);
960            try {
961                mPm.mInstaller.linkFile(relativePath, fromDir.getAbsolutePath(),
962                        toDir.getAbsolutePath());
963            } catch (InstallerException e) {
964                throw new IOException("failed linkOrCreateDir(" + relativePath + ", "
965                        + fromDir + ", " + toDir + ")", e);
966            }
967        }
968
969        Slog.d(TAG, "Linked " + fromFiles.size() + " files into " + toDir);
970    }
971
972    private static void copyFiles(List<File> fromFiles, File toDir) throws IOException {
973        // Remove any partial files from previous attempt
974        for (File file : toDir.listFiles()) {
975            if (file.getName().endsWith(".tmp")) {
976                file.delete();
977            }
978        }
979
980        for (File fromFile : fromFiles) {
981            final File tmpFile = File.createTempFile("inherit", ".tmp", toDir);
982            if (LOGD) Slog.d(TAG, "Copying " + fromFile + " to " + tmpFile);
983            if (!FileUtils.copyFile(fromFile, tmpFile)) {
984                throw new IOException("Failed to copy " + fromFile + " to " + tmpFile);
985            }
986            try {
987                Os.chmod(tmpFile.getAbsolutePath(), 0644);
988            } catch (ErrnoException e) {
989                throw new IOException("Failed to chmod " + tmpFile);
990            }
991            final File toFile = new File(toDir, fromFile.getName());
992            if (LOGD) Slog.d(TAG, "Renaming " + tmpFile + " to " + toFile);
993            if (!tmpFile.renameTo(toFile)) {
994                throw new IOException("Failed to rename " + tmpFile + " to " + toFile);
995            }
996        }
997        Slog.d(TAG, "Copied " + fromFiles.size() + " files into " + toDir);
998    }
999
1000    private static void extractNativeLibraries(File packageDir, String abiOverride)
1001            throws PackageManagerException {
1002        // Always start from a clean slate
1003        final File libDir = new File(packageDir, NativeLibraryHelper.LIB_DIR_NAME);
1004        NativeLibraryHelper.removeNativeBinariesFromDirLI(libDir, true);
1005
1006        NativeLibraryHelper.Handle handle = null;
1007        try {
1008            handle = NativeLibraryHelper.Handle.create(packageDir);
1009            final int res = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libDir,
1010                    abiOverride);
1011            if (res != PackageManager.INSTALL_SUCCEEDED) {
1012                throw new PackageManagerException(res,
1013                        "Failed to extract native libraries, res=" + res);
1014            }
1015        } catch (IOException e) {
1016            throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
1017                    "Failed to extract native libraries", e);
1018        } finally {
1019            IoUtils.closeQuietly(handle);
1020        }
1021    }
1022
1023    private static void resizeContainer(String cid, long targetSize)
1024            throws PackageManagerException {
1025        String path = PackageHelper.getSdDir(cid);
1026        if (path == null) {
1027            throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
1028                    "Failed to find mounted " + cid);
1029        }
1030
1031        final long currentSize = new File(path).getTotalSpace();
1032        if (currentSize > targetSize) {
1033            Slog.w(TAG, "Current size " + currentSize + " is larger than target size "
1034                    + targetSize + "; skipping resize");
1035            return;
1036        }
1037
1038        if (!PackageHelper.unMountSdDir(cid)) {
1039            throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
1040                    "Failed to unmount " + cid + " before resize");
1041        }
1042
1043        if (!PackageHelper.resizeSdDir(targetSize, cid,
1044                PackageManagerService.getEncryptKey())) {
1045            throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
1046                    "Failed to resize " + cid + " to " + targetSize + " bytes");
1047        }
1048
1049        path = PackageHelper.mountSdDir(cid, PackageManagerService.getEncryptKey(),
1050                Process.SYSTEM_UID, false);
1051        if (path == null) {
1052            throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
1053                    "Failed to mount " + cid + " after resize");
1054        }
1055    }
1056
1057    private void finalizeAndFixContainer(String cid) throws PackageManagerException {
1058        if (!PackageHelper.finalizeSdDir(cid)) {
1059            throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
1060                    "Failed to finalize container " + cid);
1061        }
1062
1063        if (!PackageHelper.fixSdPermissions(cid, defaultContainerGid, null)) {
1064            throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
1065                    "Failed to fix permissions on container " + cid);
1066        }
1067    }
1068
1069    void setPermissionsResult(boolean accepted) {
1070        if (!mSealed) {
1071            throw new SecurityException("Must be sealed to accept permissions");
1072        }
1073
1074        if (accepted) {
1075            // Mark and kick off another install pass
1076            synchronized (mLock) {
1077                mPermissionsAccepted = true;
1078            }
1079            mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
1080        } else {
1081            destroyInternal();
1082            dispatchSessionFinished(INSTALL_FAILED_ABORTED, "User rejected permissions", null);
1083        }
1084    }
1085
1086    public void open() throws IOException {
1087        if (mActiveCount.getAndIncrement() == 0) {
1088            mCallback.onSessionActiveChanged(this, true);
1089        }
1090
1091        synchronized (mLock) {
1092            if (!mPrepared) {
1093                if (stageDir != null) {
1094                    prepareStageDir(stageDir);
1095                } else if (stageCid != null) {
1096                    final long identity = Binder.clearCallingIdentity();
1097                    try {
1098                        prepareExternalStageCid(stageCid, params.sizeBytes);
1099                    } finally {
1100                        Binder.restoreCallingIdentity(identity);
1101                    }
1102
1103                    // TODO: deliver more granular progress for ASEC allocation
1104                    mInternalProgress = 0.25f;
1105                    computeProgressLocked(true);
1106                } else {
1107                    throw new IllegalArgumentException(
1108                            "Exactly one of stageDir or stageCid stage must be set");
1109                }
1110
1111                mPrepared = true;
1112                mCallback.onSessionPrepared(this);
1113            }
1114        }
1115    }
1116
1117    @Override
1118    public void close() {
1119        if (mActiveCount.decrementAndGet() == 0) {
1120            mCallback.onSessionActiveChanged(this, false);
1121        }
1122    }
1123
1124    @Override
1125    public void abandon() {
1126        if (mRelinquished) {
1127            Slog.d(TAG, "Ignoring abandon after commit relinquished control");
1128            return;
1129        }
1130        destroyInternal();
1131        dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned", null);
1132    }
1133
1134    private void dispatchSessionFinished(int returnCode, String msg, Bundle extras) {
1135        mFinalStatus = returnCode;
1136        mFinalMessage = msg;
1137
1138        if (mRemoteObserver != null) {
1139            try {
1140                mRemoteObserver.onPackageInstalled(mPackageName, returnCode, msg, extras);
1141            } catch (RemoteException ignored) {
1142            }
1143        }
1144
1145        final boolean success = (returnCode == PackageManager.INSTALL_SUCCEEDED);
1146        mCallback.onSessionFinished(this, success);
1147    }
1148
1149    private void destroyInternal() {
1150        synchronized (mLock) {
1151            mSealed = true;
1152            mDestroyed = true;
1153
1154            // Force shut down all bridges
1155            for (FileBridge bridge : mBridges) {
1156                bridge.forceClose();
1157            }
1158        }
1159        if (stageDir != null) {
1160            try {
1161                mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
1162            } catch (InstallerException ignored) {
1163            }
1164        }
1165        if (stageCid != null) {
1166            PackageHelper.destroySdDir(stageCid);
1167        }
1168    }
1169
1170    void dump(IndentingPrintWriter pw) {
1171        synchronized (mLock) {
1172            dumpLocked(pw);
1173        }
1174    }
1175
1176    private void dumpLocked(IndentingPrintWriter pw) {
1177        pw.println("Session " + sessionId + ":");
1178        pw.increaseIndent();
1179
1180        pw.printPair("userId", userId);
1181        pw.printPair("installerPackageName", installerPackageName);
1182        pw.printPair("installerUid", installerUid);
1183        pw.printPair("createdMillis", createdMillis);
1184        pw.printPair("stageDir", stageDir);
1185        pw.printPair("stageCid", stageCid);
1186        pw.println();
1187
1188        params.dump(pw);
1189
1190        pw.printPair("mClientProgress", mClientProgress);
1191        pw.printPair("mProgress", mProgress);
1192        pw.printPair("mSealed", mSealed);
1193        pw.printPair("mPermissionsAccepted", mPermissionsAccepted);
1194        pw.printPair("mRelinquished", mRelinquished);
1195        pw.printPair("mDestroyed", mDestroyed);
1196        pw.printPair("mBridges", mBridges.size());
1197        pw.printPair("mFinalStatus", mFinalStatus);
1198        pw.printPair("mFinalMessage", mFinalMessage);
1199        pw.println();
1200
1201        pw.decreaseIndent();
1202    }
1203}
1204