diff --git a/core/java/android/os/storage/StorageManagerInternal.java b/core/java/android/os/storage/StorageManagerInternal.java index e78aef5b7fbbf..4bd31f8b0b3fc 100644 --- a/core/java/android/os/storage/StorageManagerInternal.java +++ b/core/java/android/os/storage/StorageManagerInternal.java @@ -16,6 +16,7 @@ package android.os.storage; +import android.annotation.NonNull; import android.annotation.Nullable; import android.os.IVold; @@ -124,4 +125,14 @@ public abstract class StorageManagerInternal { * legacy storage, {@code false} otherwise. */ public abstract boolean hasLegacyExternalStorage(int uid); + + /** + * Makes sure app-private data directories on external storage are setup correctly + * after an application is installed or upgraded. The main use for this is OBB dirs, + * which can be created/modified by the installer. + * + * @param packageName the package name of the package + * @param uid the uid of the package + */ + public abstract void prepareAppDataAfterInstall(@NonNull String packageName, int uid); } diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index 53dbb9336b36a..3b0a1a3ead0a0 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -4409,6 +4409,25 @@ class StorageManagerService extends IStorageManager.Stub } } + @Override + public void prepareAppDataAfterInstall(String packageName, int uid) { + int userId = UserHandle.getUserId(uid); + final Environment.UserEnvironment userEnv = new Environment.UserEnvironment(userId); + + // The installer may have downloaded OBBs for this newly installed application; + // make sure the OBB dir for the application is setup correctly, if it exists. + File[] packageObbDirs = userEnv.buildExternalStorageAppObbDirs(packageName); + for (File packageObbDir : packageObbDirs) { + try { + mVold.fixupAppDir(packageObbDir.getCanonicalPath() + "/", uid); + } catch (IOException e) { + Log.e(TAG, "Failed to get canonical path for " + packageName); + } catch (RemoteException e) { + Log.e(TAG, "Failed to fixup app dir for " + packageName); + } + } + } + public boolean hasExternalStorage(int uid, String packageName) { // No need to check for system uid. This avoids a deadlock between // PackageManagerService and AppOpsService. diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index e96f85b0d3fa9..2a3f7ed628458 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -21736,6 +21736,7 @@ public class PackageManagerService extends IPackageManager.Stub } UserManagerInternal umInternal = mInjector.getUserManagerInternal(); + StorageManagerInternal smInternal = mInjector.getStorageManagerInternal(); for (UserInfo user : mUserManager.getUsers(false /*excludeDying*/)) { final int flags; if (umInternal.isUserUnlockingOrUnlocked(user.id)) { @@ -21749,6 +21750,13 @@ public class PackageManagerService extends IPackageManager.Stub if (ps.getInstalled(user.id)) { // TODO: when user data is locked, mark that we're still dirty prepareAppDataLIF(pkg, user.id, flags); + + if (umInternal.isUserUnlockingOrUnlocked(user.id)) { + // Prepare app data on external storage; currently this is used to + // setup any OBB dirs that were created by the installer correctly. + int uid = UserHandle.getUid(user.id, UserHandle.getAppId(pkg.getUid())); + smInternal.prepareAppDataAfterInstall(pkg.getPackageName(), uid); + } } } }