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:
+ *
+ * - If previousAppId < 0, app data will be migrated to the new app ID
+ *
- If previousAppId == 0, no migration will happen and data will be wiped and recreated
+ *
- If previousAppId > 0, it will migrate all data owned by previousAppId
+ * to the new app ID
+ *
*/
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);