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