From b3562f43d211d10390a5ec454784ab0bdd077167 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Wed, 12 Feb 2020 15:11:56 +0100 Subject: [PATCH] Fixup OBB directories correctly after package install. The installer may pre-create OBB directories for packages that it is installing on external storage, in locations like /storage/emulated/0/data/obb/com.foo . The permissions on this directory is never explicitly setup; instead, sdcardfs magically fixed up the permissions to match the package name "com.foo". With sdcardfs going away in devices launching with R, we need to set the permissions for these paths up explicitly. Since only vold can do that, have PackageManager call into StorageManager after an app install/upgrade to do the correct setup. Bug: 146419093 Test: manually verify directories are setup correctly Change-Id: I530c8de196011b1dc97c7a9ab612e5d6dc9403a1 --- .../os/storage/StorageManagerInternal.java | 11 +++++++++++ .../android/server/StorageManagerService.java | 19 +++++++++++++++++++ .../server/pm/PackageManagerService.java | 8 ++++++++ 3 files changed, 38 insertions(+) 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 ad70345dfc48f..68b52383e52be 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -21785,6 +21785,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)) { @@ -21798,6 +21799,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); + } } } }