summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/os/storage/StorageManagerInternal.java8
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp102
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java40
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java19
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;
}