diff options
4 files changed, 166 insertions, 3 deletions
diff --git a/core/java/android/os/storage/StorageManagerInternal.java b/core/java/android/os/storage/StorageManagerInternal.java index e78aef5b7fbb..f15d9260f5f8 100644 --- a/core/java/android/os/storage/StorageManagerInternal.java +++ b/core/java/android/os/storage/StorageManagerInternal.java @@ -19,6 +19,8 @@ package android.os.storage; import android.annotation.Nullable; import android.os.IVold; +import java.util.Set; + /** * Mount service local interface. * @@ -97,6 +99,12 @@ public abstract class StorageManagerInternal { } /** + * Check if fuse is running in target user, if it's running then setup its obb directories. + * TODO: System server should store a list of active pids that obb is not mounted and use it. + */ + public abstract void prepareObbDirs(int userId, Set<String> packageList, String processName); + + /** * Add a listener to listen to reset event in StorageManagerService. * * @param listener The listener that will be notified on reset events. diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index d91911c3a6c0..e4141e02ab1c 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -105,10 +105,12 @@ namespace { using namespace std::placeholders; using android::String8; +using android::base::ReadFileToString; using android::base::StringAppendF; using android::base::StringPrintf; using android::base::WriteStringToFile; using android::base::GetBoolProperty; +using android::base::GetProperty; #define CREATE_ERROR(...) StringPrintf("%s:%d: ", __FILE__, __LINE__). \ append(StringPrintf(__VA_ARGS__)) @@ -174,6 +176,12 @@ static constexpr int DEFAULT_DATA_DIR_PERMISSION = 0751; static const std::string ANDROID_APP_DATA_ISOLATION_ENABLED_PROPERTY = "persist.zygote.app_data_isolation"; +/** + * Property to enable app data isolation for sdcard obb or data in vold. + */ +static const std::string ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY = + "persist.sys.vold_app_data_isolation_enabled"; + static constexpr const uint64_t UPPER_HALF_WORD_MASK = 0xFFFF'FFFF'0000'0000; static constexpr const uint64_t LOWER_HALF_WORD_MASK = 0x0000'0000'FFFF'FFFF; @@ -603,6 +611,15 @@ static void EnableDebugger() { } } +static bool IsFilesystemSupported(const std::string& fsType) { + std::string supported; + if (!ReadFileToString("/proc/filesystems", &supported)) { + ALOGE("Failed to read supported filesystems"); + return false; + } + return supported.find(fsType + "\n") != std::string::npos; +} + static void PreApplicationInit() { // The child process sets this to indicate it's not the zygote. android_mallopt(M_SET_ZYGOTE_CHILD, nullptr, 0); @@ -782,6 +799,31 @@ static void MountAppDataTmpFs(const std::string& target_dir, } } +static void BindMountObbPackage(std::string_view package_name, int userId, fail_fn_t fail_fn) { + + // TODO(148772775): Pass primary volume name from zygote argument to here + std::string source; + if (IsFilesystemSupported("sdcardfs")) { + source = StringPrintf("/mnt/runtime/default/emulated/%d/Android/obb/%s", + userId, package_name.data()); + } else { + source = StringPrintf("/mnt/pass_through/%d/emulated/%d/Android/obb/%s", + userId, userId, package_name.data()); + } + std::string target( + StringPrintf("/storage/emulated/%d/Android/obb/%s", userId, package_name.data())); + + if (access(source.c_str(), F_OK) != 0) { + fail_fn(CREATE_ERROR("Cannot access source %s: %s", source.c_str(), strerror(errno))); + } + + if (access(target.c_str(), F_OK) != 0) { + fail_fn(CREATE_ERROR("Cannot access target %s: %s", target.c_str(), strerror(errno))); + } + + BindMount(source, target, fail_fn); +} + // Create a private mount namespace and bind mount appropriate emulated // storage for the given user. static void MountEmulatedStorage(uid_t uid, jint mount_mode, @@ -1504,6 +1546,60 @@ static void isolateJitProfile(JNIEnv* env, jobjectArray pkg_data_info_list, } } +// Bind mount all obb directories that are visible to this app. +// If app data isolation is not enabled for this process, bind mount the whole obb +// directory instead. +static void BindMountAppObbDirs(JNIEnv* env, jobjectArray pkg_data_info_list, + uid_t uid, const char* process_name, jstring managed_nice_name, fail_fn_t fail_fn) { + + auto extract_fn = std::bind(ExtractJString, env, process_name, managed_nice_name, _1); + const userid_t user_id = multiuser_get_user_id(uid); + + // If FUSE is not ready for this user, skip it + // TODO(148772775): Pass primary volume name from zygote argument to here + std::string tmp = GetProperty("vold.fuse_running_users", ""); + std::istringstream fuse_running_users(tmp); + bool user_found = false; + std::string s; + std::string user_id_str = std::to_string(user_id); + while (!user_found && std::getline(fuse_running_users, s, ',')) { + if (user_id_str == s) { + user_found = true; + } + } + if (!user_found) { + ALOGI("User %d is not running fuse yet, fuse_running_users=%s", user_id, tmp.c_str()); + return; + } + + // Fuse is ready, so we can start using fuse path. + int size = (pkg_data_info_list != nullptr) ? env->GetArrayLength(pkg_data_info_list) : 0; + + if (size == 0) { + // App data isolation is not enabled for this process, so we bind mount to whole obb/ dir. + std::string source; + if (IsFilesystemSupported("sdcardfs")) { + source = StringPrintf("/mnt/runtime/default/emulated/%d/Android/obb", user_id); + } else { + source = StringPrintf("/mnt/pass_through/%d/emulated/%d/Android/obb", user_id, user_id); + } + std::string target(StringPrintf("/storage/emulated/%d/Android/obb", user_id)); + + if (access(source.c_str(), F_OK) != 0) { + fail_fn(CREATE_ERROR("Error accessing %s: %s", source.c_str(), strerror(errno))); + } + BindMount(source, target, fail_fn); + return; + } + + // Bind mount each package obb directory + for (int i = 0; i < size; i += 3) { + jstring package_str = (jstring) (env->GetObjectArrayElement(pkg_data_info_list, i)); + std::string packageName = extract_fn(package_str).value(); + BindMountObbPackage(packageName, user_id, fail_fn); + } +} + // Utility routine to specialize a zygote child process. static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, @@ -1552,6 +1648,12 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, isolateJitProfile(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn); } + if ((mount_external != MOUNT_EXTERNAL_INSTALLER) && + GetBoolProperty(kPropFuse, false) && + GetBoolProperty(ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, false)) { + BindMountAppObbDirs(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn); + } + // If this zygote isn't root, it won't be able to create a process group, // since the directory is owned by root. if (!is_system_server && getuid() == 0) { diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index 53dbb9336b36..c992ac425023 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -2120,8 +2120,6 @@ class StorageManagerService extends IStorageManager.Stub private void unmount(VolumeInfo vol) { try { - mVold.unmount(vol.id); - mStorageSessionController.onVolumeUnmount(vol); try { if (vol.type == VolumeInfo.TYPE_PRIVATE) { mInstaller.onPrivateVolumeRemoved(vol.getFsUuid()); @@ -2129,6 +2127,8 @@ class StorageManagerService extends IStorageManager.Stub } catch (Installer.InstallerException e) { Slog.e(TAG, "Failed unmount mirror data", e); } + mVold.unmount(vol.id); + mStorageSessionController.onVolumeUnmount(vol); } catch (Exception e) { Slog.wtf(TAG, e); } @@ -4346,6 +4346,42 @@ class StorageManagerService extends IStorageManager.Stub mPolicies.add(policy); } + /** + * Check if fuse is running in target user, if it's running then setup its obb directories. + * TODO: System server should store a list of active pids that obb is not mounted and use it. + */ + @Override + public void prepareObbDirs(int userId, Set<String> packageList, String processName) { + String fuseRunningUsersList = SystemProperties.get("vold.fuse_running_users", ""); + String[] fuseRunningUsers = fuseRunningUsersList.split(","); + boolean fuseReady = false; + String targetUserId = String.valueOf(userId); + for (String user : fuseRunningUsers) { + if (targetUserId.equals(user)) { + fuseReady = true; + } + } + if (fuseReady) { + try { + final IVold vold = IVold.Stub.asInterface( + ServiceManager.getServiceOrThrow("vold")); + for (String pkg : packageList) { + final String obbDir = + String.format("/storage/emulated/%d/Android/obb", userId); + final String packageObbDir = String.format("%s/%s/", obbDir, pkg); + + // Create package obb dir if it doesn't exist. + File file = new File(packageObbDir); + if (!file.exists()) { + vold.setupAppDir(packageObbDir, mPmInternal.getPackage(pkg).getUid()); + } + } + } catch (ServiceManager.ServiceNotFoundException | RemoteException e) { + Slog.e(TAG, "Unable to create obb directories for " + processName, e); + } + } + } + @Override public void onExternalStoragePolicyChanged(int uid, String packageName) { final int mountMode = getExternalStorageMountMode(uid, packageName); diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index ffa7d9202371..0dc44f79d19f 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -80,11 +80,13 @@ import android.os.Bundle; import android.os.DropBoxManager; import android.os.Handler; import android.os.IBinder; +import android.os.IVold; import android.os.Looper; import android.os.Message; import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; +import android.os.ServiceManager; import android.os.StrictMode; import android.os.SystemClock; import android.os.SystemProperties; @@ -142,10 +144,14 @@ import java.util.Map; public final class ProcessList { static final String TAG = TAG_WITH_CLASS_NAME ? "ProcessList" : TAG_AM; - // A device config to control the minimum target SDK to enable app data isolation + // A system property to control if app data isolation is enabled. static final String ANDROID_APP_DATA_ISOLATION_ENABLED_PROPERTY = "persist.zygote.app_data_isolation"; + // A system property to control if obb app data isolation is enabled in vold. + static final String ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY = + "persist.sys.vold_app_data_isolation_enabled"; + // A device config to control the minimum target SDK to enable app data isolation static final String ANDROID_APP_DATA_ISOLATION_MIN_SDK = "android_app_data_isolation_min_sdk"; @@ -379,6 +385,8 @@ public final class ProcessList { private boolean mAppDataIsolationEnabled = false; + private boolean mVoldAppDataIsolationEnabled = false; + private ArrayList<String> mAppDataIsolationWhitelistedApps; /** @@ -691,6 +699,8 @@ public final class ProcessList { // want some apps enabled while some apps disabled mAppDataIsolationEnabled = SystemProperties.getBoolean(ANDROID_APP_DATA_ISOLATION_ENABLED_PROPERTY, true); + mVoldAppDataIsolationEnabled = SystemProperties.getBoolean( + ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, false); mAppDataIsolationWhitelistedApps = new ArrayList<>( SystemConfig.getInstance().getAppDataIsolationWhitelistedApps()); @@ -2113,6 +2123,13 @@ public final class ProcessList { app.info.packageName, app.userId); pkgDataInfoMap = getPackageAppDataInfoMap(pmInt, sharedPackages.length == 0 ? new String[]{app.info.packageName} : sharedPackages, uid); + + if (mVoldAppDataIsolationEnabled) { + StorageManagerInternal storageManagerInternal = LocalServices.getService( + StorageManagerInternal.class); + storageManagerInternal.prepareObbDirs(UserHandle.getUserId(uid), + pkgDataInfoMap.keySet(), app.processName); + } } else { pkgDataInfoMap = null; } |