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