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

Commit ff9d3ea0 authored by Ricky Wai's avatar Ricky Wai
Browse files

Create, mount and unmount app data mirror directory

- When volume is ready, system/installd will
create app data mirror, and bind mount it the actual CE storage for
that app.

- When a new private volume is mounted, DE mirror will be created and
mounted.

- When a private volume is unmounted, all users CE mirror will be
unmounted and DE mirror will be unmounted also.

- Fix inode createAppData() return a wrong inode number in 32bit system.

Bug: 143937733
Bug: 145989852
Test: After reboot, all apps mirror CE directories are created and
mounted
Test: After adding a new private volume, new CE DE mirror for that volume
are created and mounted.
Test: After unmounting a private volume, that vol CE DE mirror are
unmounted.
Change-Id: I8a06ae8917e5f2c7f1f905b73ec934de7f1ee802
parent af87114f
Loading
Loading
Loading
Loading
+102 −3
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/mount.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
@@ -86,6 +87,9 @@ static constexpr const mode_t kRollbackFolderMode = 0700;
static constexpr const char* kCpPath = "/system/bin/cp";
static constexpr const char* kXattrDefault = "user.default";

static constexpr const char* kDataMirrorCePath = "/data_mirror/data_ce";
static constexpr const char* kDataMirrorDePath = "/data_mirror/data_de";

static constexpr const int MIN_RESTRICTED_HOME_SDK_VERSION = 24; // > M

static constexpr const char* PKG_LIB_POSTFIX = "/lib";
@@ -99,6 +103,13 @@ static constexpr size_t kSha256Size = 32;
static constexpr const char* kPropApkVerityMode = "ro.apk_verity.mode";
static constexpr const char* kFuseProp = "persist.sys.fuse";

/**
 * Property to control if app data isolation is enabled.
 */
static constexpr const char* kAppDataIsolationEnabledProperty = "persist.zygote.app_data_isolation";

static std::atomic<bool> sAppDataIsolationEnabled(false);

namespace {

constexpr const char* kDump = "android.permission.DUMP";
@@ -258,6 +269,8 @@ status_t InstalldNativeService::start() {
    sp<ProcessState> ps(ProcessState::self());
    ps->startThreadPool();
    ps->giveThreadPoolName();
    sAppDataIsolationEnabled = android::base::GetBoolProperty(
            kAppDataIsolationEnabledProperty, false);
    return android::OK;
}

@@ -450,10 +463,13 @@ binder::Status InstalldNativeService::createAppData(const std::unique_ptr<std::s

        // And return the CE inode of the top-level data directory so we can
        // clear contents while CE storage is locked
        if ((_aidl_return != nullptr)
                && get_path_inode(path, reinterpret_cast<ino_t*>(_aidl_return)) != 0) {
        if (_aidl_return != nullptr) {
            ino_t result;
            if (get_path_inode(path, &result) != 0) {
                return error("Failed to get_path_inode for " + path);
            }
            *_aidl_return = static_cast<uint64_t>(result);
        }
    }
    if (flags & FLAG_STORAGE_DE) {
        auto path = create_data_user_de_package_path(uuid_, userId, pkgname);
@@ -2613,6 +2629,89 @@ binder::Status InstalldNativeService::invalidateMounts() {
    return ok();
}

// Mount volume's CE and DE storage to mirror
binder::Status InstalldNativeService::onPrivateVolumeMounted(
        const std::unique_ptr<std::string>& uuid) {
    ENFORCE_UID(AID_SYSTEM);
    CHECK_ARGUMENT_UUID(uuid);
    if (!sAppDataIsolationEnabled) {
        return ok();
    }
    if (!uuid) {
        return error("Should not happen, mounting uuid == null");
    }

    const char* uuid_ = uuid->c_str();
    // Mount CE mirror
    std::string mirrorVolCePath(StringPrintf("%s/%s", kDataMirrorCePath, uuid_));
    std::lock_guard<std::recursive_mutex> lock(mLock);
    if (fs_prepare_dir(mirrorVolCePath.c_str(), 0700, AID_ROOT, AID_ROOT) != 0) {
        return error("Failed to create CE mirror");
    }
    auto cePath = StringPrintf("%s/user_ce", create_data_path(uuid_).c_str());
    if (TEMP_FAILURE_RETRY(mount(cePath.c_str(), mirrorVolCePath.c_str(), NULL,
            MS_NOSUID | MS_NODEV | MS_NOATIME | MS_BIND | MS_NOEXEC, nullptr)) == -1) {
        return error("Failed to mount " + mirrorVolCePath);
    }

    // Mount DE mirror
    std::string mirrorVolDePath(StringPrintf("%s/%s", kDataMirrorDePath, uuid_));
    if (fs_prepare_dir(mirrorVolDePath.c_str(), 0700, AID_ROOT, AID_ROOT) != 0) {
        return error("Failed to create DE mirror");
    }
    auto dePath = StringPrintf("%s/user_de", create_data_path(uuid_).c_str());
    if (TEMP_FAILURE_RETRY(mount(dePath.c_str(), mirrorVolDePath.c_str(), NULL,
            MS_NOSUID | MS_NODEV | MS_NOATIME | MS_BIND | MS_NOEXEC, nullptr)) == -1) {
        return error("Failed to mount " + mirrorVolDePath);
    }
    return ok();
}

// Unmount volume's CE and DE storage from mirror
binder::Status InstalldNativeService::onPrivateVolumeRemoved(
        const std::unique_ptr<std::string>& uuid) {
    ENFORCE_UID(AID_SYSTEM);
    CHECK_ARGUMENT_UUID(uuid);
    if (!sAppDataIsolationEnabled) {
        return ok();
    }
    if (!uuid) {
        // It happens when private volume failed to mount.
        LOG(INFO) << "Ignore unmount uuid=null";
        return ok();
    }
    const char* uuid_ = uuid->c_str();

    binder::Status res = ok();

    std::string mirrorCeVolPath(StringPrintf("%s/%s", kDataMirrorCePath, uuid_));
    std::string mirrorDeVolPath(StringPrintf("%s/%s", kDataMirrorDePath, uuid_));

    // Unmount CE storage
    std::lock_guard<std::recursive_mutex> lock(mLock);
    if (TEMP_FAILURE_RETRY(umount(mirrorCeVolPath.c_str())) != 0) {
        if (errno != ENOENT) {
            res = error(StringPrintf("Failed to umount %s %s", mirrorCeVolPath.c_str(),
                                strerror(errno)));
        }
    }
    if (delete_dir_contents_and_dir(mirrorCeVolPath, true) != 0) {
        res = error("Failed to delete " + mirrorCeVolPath);
    }

    // Unmount DE storage
    if (TEMP_FAILURE_RETRY(umount(mirrorDeVolPath.c_str())) != 0) {
        if (errno != ENOENT) {
            res = error(StringPrintf("Failed to umount %s %s", mirrorDeVolPath.c_str(),
                                strerror(errno)));
        }
    }
    if (delete_dir_contents_and_dir(mirrorDeVolPath, true) != 0) {
        res = error("Failed to delete " + mirrorDeVolPath);
    }
    return res;
}

std::string InstalldNativeService::findDataMediaPath(
        const std::unique_ptr<std::string>& uuid, userid_t userid) {
    std::lock_guard<std::recursive_mutex> lock(mMountsLock);
+2 −0
Original line number Diff line number Diff line
@@ -146,6 +146,8 @@ public:
    binder::Status invalidateMounts();
    binder::Status isQuotaSupported(const std::unique_ptr<std::string>& volumeUuid,
            bool* _aidl_return);
    binder::Status onPrivateVolumeMounted(const std::unique_ptr<std::string>& volumeUuid);
    binder::Status onPrivateVolumeRemoved(const std::unique_ptr<std::string>& volumeUuid);

    binder::Status prepareAppProfile(const std::string& packageName,
            int32_t userId, int32_t appId, const std::string& profileName,
+4 −0
Original line number Diff line number Diff line
@@ -61,6 +61,10 @@ bool InvalidateQuotaMounts() {
        std::getline(in, target, ' ');
        std::getline(in, ignored);

        if (target.compare(0, 13, "/data_mirror/") == 0) {
            continue;
        }

        if (source.compare(0, 11, "/dev/block/") == 0) {
            struct dqblk dq;
            if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), source.c_str(), 0,
+2 −0
Original line number Diff line number Diff line
@@ -109,6 +109,8 @@ interface IInstalld {
            int appId, @utf8InCpp String seInfo, int user, int snapshotId, int storageflags);
    void destroyAppDataSnapshot(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
            int userId, long ceSnapshotInode, int snapshotId, int storageFlags);
    void onPrivateVolumeMounted(@nullable @utf8InCpp String volumeUuid);
    void onPrivateVolumeRemoved(@nullable @utf8InCpp String volumeUuid);

    void migrateLegacyObbData();