Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 62048287 authored by Ricky Wai's avatar Ricky Wai Committed by Android (Google) Code Review
Browse files

Merge "Bind mount obb directory in emulated storage."

parents cb7f6ffe e5088d92
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.IVold;

import java.util.Set;

/**
 * Mount service local interface.
 *
@@ -97,6 +99,12 @@ public abstract class StorageManagerInternal {
        void onReset(IVold vold);
    }

    /**
     * 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.
     *
+102 −0
Original line number Diff line number Diff line
@@ -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) {
+38 −2
Original line number Diff line number Diff line
@@ -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);
+18 −1
Original line number Diff line number Diff line
@@ -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;
            }