diff --git a/services/core/java/com/android/server/pm/AppDataHelper.java b/services/core/java/com/android/server/pm/AppDataHelper.java index 9696d3d14ce91..6ee198133281e 100644 --- a/services/core/java/com/android/server/pm/AppDataHelper.java +++ b/services/core/java/com/android/server/pm/AppDataHelper.java @@ -26,8 +26,10 @@ import android.annotation.Nullable; import android.content.pm.PackageManager; import android.content.pm.SELinuxUtil; import android.content.pm.UserInfo; +import android.os.CreateAppDataArgs; import android.os.Environment; import android.os.FileUtils; +import android.os.Process; import android.os.Trace; import android.os.UserHandle; import android.os.storage.StorageManager; @@ -86,12 +88,20 @@ final class AppDataHelper { *

* Verifies that directories exist and that ownership and labeling is * correct for all installed apps. If there is an ownership mismatch, it - * will try recovering system apps by wiping data; third-party app data is - * left intact. + * will wipe and recreate the data. *

* Note: To avoid a deadlock, do not call this method with {@code mLock} lock held */ public void prepareAppDataAfterInstallLIF(AndroidPackage pkg) { + prepareAppDataPostCommitLIF(pkg, 0 /* previousAppId */); + } + + /** + * For more details about data verification and previousAppId, check + * {@link #prepareAppData(Installer.Batch, AndroidPackage, int, int, int)} + * @see #prepareAppDataAfterInstallLIF(AndroidPackage) + */ + public void prepareAppDataPostCommitLIF(AndroidPackage pkg, int previousAppId) { final PackageSetting ps; synchronized (mPm.mLock) { ps = mPm.mSettings.getPackageLPr(pkg.getPackageName()); @@ -113,13 +123,9 @@ final class AppDataHelper { continue; } - // TODO@ashfall check ScanResult.mNeedsNewAppId, and if true instead - // of creating app data, migrate / change ownership of existing - // data. - if (ps.getInstalled(user.id)) { // TODO: when user data is locked, mark that we're still dirty - prepareAppData(batch, pkg, user.id, flags).thenRun(() -> { + prepareAppData(batch, pkg, previousAppId, user.id, flags).thenRun(() -> { // Note: this code block is executed with the Installer lock // already held, since it's invoked as a side-effect of // executeBatchLI() @@ -147,22 +153,26 @@ final class AppDataHelper { * Prepare app data for the given app. *

* Verifies that directories exist and that ownership and labeling is - * correct for all installed apps. If there is an ownership mismatch, this - * will try recovering system apps by wiping data; third-party app data is - * left intact. + * correct for all installed apps. If there is an ownership mismatch: + *

*/ private @NonNull CompletableFuture prepareAppData(@NonNull Installer.Batch batch, - @Nullable AndroidPackage pkg, int userId, int flags) { + @Nullable AndroidPackage pkg, int previousAppId, int userId, int flags) { if (pkg == null) { Slog.wtf(TAG, "Package was null!", new Throwable()); return CompletableFuture.completedFuture(null); } - return prepareAppDataLeaf(batch, pkg, userId, flags); + return prepareAppDataLeaf(batch, pkg, previousAppId, userId, flags); } private void prepareAppDataAndMigrate(@NonNull Installer.Batch batch, @NonNull AndroidPackage pkg, int userId, int flags, boolean maybeMigrateAppData) { - prepareAppData(batch, pkg, userId, flags).thenRun(() -> { + prepareAppData(batch, pkg, Process.INVALID_UID, userId, flags).thenRun(() -> { // Note: this code block is executed with the Installer lock // already held, since it's invoked as a side-effect of // executeBatchLI() @@ -170,14 +180,14 @@ final class AppDataHelper { // We may have just shuffled around app data directories, so // prepare them one more time final Installer.Batch batchInner = new Installer.Batch(); - prepareAppData(batchInner, pkg, userId, flags); + prepareAppData(batchInner, pkg, Process.INVALID_UID, userId, flags); executeBatchLI(batchInner); } }); } private @NonNull CompletableFuture prepareAppDataLeaf(@NonNull Installer.Batch batch, - @NonNull AndroidPackage pkg, int userId, int flags) { + @NonNull AndroidPackage pkg, int previousAppId, int userId, int flags) { if (DEBUG_APP_DATA) { Slog.v(TAG, "prepareAppData for " + pkg.getPackageName() + " u" + userId + " 0x" + Integer.toHexString(flags)); @@ -200,65 +210,64 @@ final class AppDataHelper { final String seInfo = pkgSeInfo + seInfoUser; final int targetSdkVersion = pkg.getTargetSdkVersion(); + final CreateAppDataArgs args = Installer.buildCreateAppDataArgs(volumeUuid, packageName, + userId, flags, appId, seInfo, targetSdkVersion); + args.previousAppId = previousAppId; - return batch.createAppData(volumeUuid, packageName, userId, flags, appId, seInfo, - targetSdkVersion).whenComplete((ceDataInode, e) -> { - // Note: this code block is executed with the Installer lock - // already held, since it's invoked as a side-effect of - // executeBatchLI() - if (e != null) { - logCriticalInfo(Log.WARN, "Failed to create app data for " + packageName - + ", but trying to recover: " + e); - destroyAppDataLeafLIF(pkg, userId, flags); - try { - ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, - flags, appId, seInfo, pkg.getTargetSdkVersion()); - logCriticalInfo(Log.DEBUG, "Recovery succeeded!"); - } catch (Installer.InstallerException e2) { - logCriticalInfo(Log.DEBUG, "Recovery failed!"); - } - } + return batch.createAppData(args).whenComplete((ceDataInode, e) -> { + // Note: this code block is executed with the Installer lock + // already held, since it's invoked as a side-effect of + // executeBatchLI() + if (e != null) { + logCriticalInfo(Log.WARN, "Failed to create app data for " + packageName + + ", but trying to recover: " + e); + destroyAppDataLeafLIF(pkg, userId, flags); + try { + ceDataInode = mInstaller.createAppData(args).ceDataInode; + logCriticalInfo(Log.DEBUG, "Recovery succeeded!"); + } catch (Installer.InstallerException e2) { + logCriticalInfo(Log.DEBUG, "Recovery failed!"); + } + } - // Prepare the application profiles only for upgrades and - // first boot (so that we don't repeat the same operation at - // each boot). - // - // We only have to cover the upgrade and first boot here - // because for app installs we prepare the profiles before - // invoking dexopt (in installPackageLI). - // - // We also have to cover non system users because we do not - // call the usual install package methods for them. - // - // NOTE: in order to speed up first boot time we only create - // the current profile and do not update the content of the - // reference profile. A system image should already be - // configured with the right profile keys and the profiles - // for the speed-profile prebuilds should already be copied. - // That's done in #performDexOptUpgrade. - // - // TODO(calin, mathieuc): We should use .dm files for - // prebuilds profiles instead of manually copying them in - // #performDexOptUpgrade. When we do that we should have a - // more granular check here and only update the existing - // profiles. - if (mPm.isDeviceUpgrading() || mPm.isFirstBoot() - || (userId != UserHandle.USER_SYSTEM)) { - mArtManagerService.prepareAppProfiles(pkg, userId, - /* updateReferenceProfileContent= */ false); - } + // Prepare the application profiles only for upgrades and + // first boot (so that we don't repeat the same operation at + // each boot). + // + // We only have to cover the upgrade and first boot here + // because for app installs we prepare the profiles before + // invoking dexopt (in installPackageLI). + // + // We also have to cover non system users because we do not + // call the usual install package methods for them. + // + // NOTE: in order to speed up first boot time we only create + // the current profile and do not update the content of the + // reference profile. A system image should already be + // configured with the right profile keys and the profiles + // for the speed-profile prebuilds should already be copied. + // That's done in #performDexOptUpgrade. + // + // TODO(calin, mathieuc): We should use .dm files for + // prebuilds profiles instead of manually copying them in + // #performDexOptUpgrade. When we do that we should have a + // more granular check here and only update the existing + // profiles. + if (mPm.isDeviceUpgrading() || mPm.isFirstBoot() + || (userId != UserHandle.USER_SYSTEM)) { + mArtManagerService.prepareAppProfiles(pkg, userId, + /* updateReferenceProfileContent= */ false); + } - if ((flags & StorageManager.FLAG_STORAGE_CE) != 0 && ceDataInode != -1) { - // TODO: mark this structure as dirty so we persist it! - synchronized (mPm.mLock) { - if (ps != null) { - ps.setCeDataInode(ceDataInode, userId); - } - } - } + if ((flags & StorageManager.FLAG_STORAGE_CE) != 0 && ceDataInode != -1) { + // TODO: mark this structure as dirty so we persist it! + synchronized (mPm.mLock) { + ps.setCeDataInode(ceDataInode, userId); + } + } - prepareAppDataContentsLeafLIF(pkg, ps, userId, flags); - }); + prepareAppDataContentsLeafLIF(pkg, ps, userId, flags); + }); } public void prepareAppDataContentsLIF(AndroidPackage pkg, @Nullable PackageSetting pkgSetting, diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java index 30d32ad197ae7..53e76a7a594d0 100644 --- a/services/core/java/com/android/server/pm/InstallPackageHelper.java +++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java @@ -2433,7 +2433,12 @@ final class InstallPackageHelper { } incrementalStorages.add(storage); } - appDataHelper.prepareAppDataAfterInstallLIF(pkg); + int previousAppId = 0; + if (reconciledPkg.mScanResult.needsNewAppId()) { + // Only set previousAppId if the app is migrating out of shared UID + previousAppId = reconciledPkg.mScanResult.mPreviousAppId; + } + appDataHelper.prepareAppDataPostCommitLIF(pkg, previousAppId); if (reconciledPkg.mPrepareResult.mClearCodeCache) { appDataHelper.clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java index 7e002bf8c14f5..55355d81ffe2d 100644 --- a/services/core/java/com/android/server/pm/Installer.java +++ b/services/core/java/com/android/server/pm/Installer.java @@ -26,7 +26,6 @@ import android.os.Build; import android.os.CreateAppDataArgs; import android.os.CreateAppDataResult; import android.os.IBinder; -import android.os.IBinder.DeathRecipient; import android.os.IInstalld; import android.os.RemoteException; import android.os.ServiceManager; @@ -148,12 +147,9 @@ public class Installer extends SystemService { IBinder binder = ServiceManager.getService("installd"); if (binder != null) { try { - binder.linkToDeath(new DeathRecipient() { - @Override - public void binderDied() { - Slog.w(TAG, "installd died; reconnecting"); - connect(); - } + binder.linkToDeath(() -> { + Slog.w(TAG, "installd died; reconnecting"); + connect(); }, 0); } catch (RemoteException e) { binder = null; @@ -168,9 +164,7 @@ public class Installer extends SystemService { } } else { Slog.w(TAG, "installd not found; trying again"); - BackgroundThread.getHandler().postDelayed(() -> { - connect(); - }, DateUtils.SECOND_IN_MILLIS); + BackgroundThread.getHandler().postDelayed(this::connect, DateUtils.SECOND_IN_MILLIS); } } @@ -192,7 +186,9 @@ public class Installer extends SystemService { } } - private static CreateAppDataArgs buildCreateAppDataArgs(String uuid, String packageName, + // We explicitly do NOT set previousAppId because the default value should always be 0. + // Manually override previousAppId after building CreateAppDataArgs for specific behaviors. + static CreateAppDataArgs buildCreateAppDataArgs(String uuid, String packageName, int userId, int flags, int appId, String seInfo, int targetSdkVersion) { final CreateAppDataArgs args = new CreateAppDataArgs(); args.uuid = uuid; @@ -213,23 +209,6 @@ public class Installer extends SystemService { return result; } - /** - * @deprecated callers are encouraged to migrate to using {@link Batch} to - * more efficiently handle operations in bulk. - */ - @Deprecated - public long createAppData(String uuid, String packageName, int userId, int flags, int appId, - String seInfo, int targetSdkVersion) throws InstallerException { - final CreateAppDataArgs args = buildCreateAppDataArgs(uuid, packageName, userId, flags, - appId, seInfo, targetSdkVersion); - final CreateAppDataResult result = createAppData(args); - if (result.exceptionCode == 0) { - return result.ceDataInode; - } else { - throw new InstallerException(result.exceptionMessage); - } - } - public @NonNull CreateAppDataResult createAppData(@NonNull CreateAppDataArgs args) throws InstallerException { if (!checkBeforeRemote()) { @@ -284,13 +263,11 @@ public class Installer extends SystemService { * Callers of this method are not required to hold a monitor lock on an * {@link Installer} object. */ - public synchronized @NonNull CompletableFuture createAppData(String uuid, - String packageName, int userId, int flags, int appId, String seInfo, - int targetSdkVersion) { - if (mExecuted) throw new IllegalStateException(); - - final CreateAppDataArgs args = buildCreateAppDataArgs(uuid, packageName, userId, flags, - appId, seInfo, targetSdkVersion); + @NonNull + public synchronized CompletableFuture createAppData(CreateAppDataArgs args) { + if (mExecuted) { + throw new IllegalStateException(); + } final CompletableFuture future = new CompletableFuture<>(); mArgs.add(args); mFutures.add(future); diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 6df100640e26c..3877b45045a22 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -61,6 +61,7 @@ import android.content.pm.pkg.PackageUserStateUtils; import android.net.Uri; import android.os.Binder; import android.os.Build; +import android.os.CreateAppDataArgs; import android.os.Environment; import android.os.FileUtils; import android.os.Handler; @@ -4016,9 +4017,11 @@ public final class Settings implements Watchable, Snappable { // Accumulate all required args and call the installer after mPackages lock // has been released final String seInfo = AndroidPackageUtils.getSeInfo(ps.getPkg(), ps); - batch.createAppData(ps.getVolumeUuid(), ps.getPackageName(), userHandle, + final CreateAppDataArgs args = Installer.buildCreateAppDataArgs( + ps.getVolumeUuid(), ps.getPackageName(), userHandle, StorageManager.FLAG_STORAGE_CE | StorageManager.FLAG_STORAGE_DE, ps.getAppId(), seInfo, ps.getPkg().getTargetSdkVersion()); + batch.createAppData(args); } else { // Make sure the app is excluded from storage mapping for this user writeKernelMappingLPr(ps);