Loading services/core/java/com/android/server/pm/AppDataHelper.java +79 −70 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -86,12 +88,20 @@ final class AppDataHelper { * <p> * 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. * <p> * <em>Note: To avoid a deadlock, do not call this method with {@code mLock} lock held</em> */ 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()); Loading @@ -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() Loading Loading @@ -147,22 +153,26 @@ final class AppDataHelper { * Prepare app data for the given app. * <p> * 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: * <ul> * <li>If previousAppId < 0, app data will be migrated to the new app ID * <li>If previousAppId == 0, no migration will happen and data will be wiped and recreated * <li>If previousAppId > 0, it will migrate all data owned by previousAppId * to the new app ID * </ul> */ 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() Loading @@ -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)); Loading @@ -200,9 +210,11 @@ 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) -> { 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() Loading @@ -211,8 +223,7 @@ final class AppDataHelper { + ", but trying to recover: " + e); destroyAppDataLeafLIF(pkg, userId, flags); try { ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags, appId, seInfo, pkg.getTargetSdkVersion()); ceDataInode = mInstaller.createAppData(args).ceDataInode; logCriticalInfo(Log.DEBUG, "Recovery succeeded!"); } catch (Installer.InstallerException e2) { logCriticalInfo(Log.DEBUG, "Recovery failed!"); Loading Loading @@ -251,11 +262,9 @@ final class AppDataHelper { 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); } } } prepareAppDataContentsLeafLIF(pkg, ps, userId, flags); }); Loading services/core/java/com/android/server/pm/InstallPackageHelper.java +6 −1 Original line number Diff line number Diff line Loading @@ -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 Loading services/core/java/com/android/server/pm/Installer.java +12 −35 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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() { binder.linkToDeath(() -> { Slog.w(TAG, "installd died; reconnecting"); connect(); } }, 0); } catch (RemoteException e) { binder = null; Loading @@ -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); } } Loading @@ -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; Loading @@ -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()) { Loading Loading @@ -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<Long> 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<Long> createAppData(CreateAppDataArgs args) { if (mExecuted) { throw new IllegalStateException(); } final CompletableFuture<Long> future = new CompletableFuture<>(); mArgs.add(args); mFutures.add(future); Loading services/core/java/com/android/server/pm/Settings.java +4 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading Loading
services/core/java/com/android/server/pm/AppDataHelper.java +79 −70 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -86,12 +88,20 @@ final class AppDataHelper { * <p> * 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. * <p> * <em>Note: To avoid a deadlock, do not call this method with {@code mLock} lock held</em> */ 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()); Loading @@ -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() Loading Loading @@ -147,22 +153,26 @@ final class AppDataHelper { * Prepare app data for the given app. * <p> * 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: * <ul> * <li>If previousAppId < 0, app data will be migrated to the new app ID * <li>If previousAppId == 0, no migration will happen and data will be wiped and recreated * <li>If previousAppId > 0, it will migrate all data owned by previousAppId * to the new app ID * </ul> */ 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() Loading @@ -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)); Loading @@ -200,9 +210,11 @@ 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) -> { 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() Loading @@ -211,8 +223,7 @@ final class AppDataHelper { + ", but trying to recover: " + e); destroyAppDataLeafLIF(pkg, userId, flags); try { ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags, appId, seInfo, pkg.getTargetSdkVersion()); ceDataInode = mInstaller.createAppData(args).ceDataInode; logCriticalInfo(Log.DEBUG, "Recovery succeeded!"); } catch (Installer.InstallerException e2) { logCriticalInfo(Log.DEBUG, "Recovery failed!"); Loading Loading @@ -251,11 +262,9 @@ final class AppDataHelper { 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); } } } prepareAppDataContentsLeafLIF(pkg, ps, userId, flags); }); Loading
services/core/java/com/android/server/pm/InstallPackageHelper.java +6 −1 Original line number Diff line number Diff line Loading @@ -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 Loading
services/core/java/com/android/server/pm/Installer.java +12 −35 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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() { binder.linkToDeath(() -> { Slog.w(TAG, "installd died; reconnecting"); connect(); } }, 0); } catch (RemoteException e) { binder = null; Loading @@ -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); } } Loading @@ -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; Loading @@ -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()) { Loading Loading @@ -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<Long> 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<Long> createAppData(CreateAppDataArgs args) { if (mExecuted) { throw new IllegalStateException(); } final CompletableFuture<Long> future = new CompletableFuture<>(); mArgs.add(args); mFutures.add(future); Loading
services/core/java/com/android/server/pm/Settings.java +4 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading