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

Commit 92f5cf0d authored by Samiul Islam's avatar Samiul Islam Committed by Mohammad Samiul Islam
Browse files

Create separate api for reconciling per-sdk storage

Sdks should get their own storage area under the sdk package path
at: `/data/misc_ce/0/sdksandbox/<package>/<sdk-name>@<random-suffix>`

The random suffix is to prevent sdks from guessing each others storage
paths. It is separated by '@' which is an illegal character for package
names.

The new API prepares the sdk-level directories as follows:
- creates them if they do not exist.
- on occasssions where they already exist, it skips creating them.
- on occasssions where it finds an per-sdk directory that shouldn't be
  there, it deletes them.
- it also creates the package path if its missing for any reason.

Additional Changes:
- For package-level sdk data directory, we now delete it if FLAG_STORAGE_SDK
flag is not passed. This is done so that we clean up properly when an
app that consumes sdk updates to a state where it no longer consumes
sdks.

Bug: 211763739
Test: atest installd_service_tes
Test: atest SdkSandboxStorageHostTest
Ignore-AOSP-First: Feature is being developed in internal branch
Change-Id: I7f144f5da4c4e10851f78d731de5dfb429fbac4d
parent 7d5b1dad
Loading
Loading
Loading
Loading
+181 −11
Original line number Original line Diff line number Diff line
@@ -41,6 +41,7 @@
#include <fstream>
#include <fstream>
#include <functional>
#include <functional>
#include <regex>
#include <regex>
#include <unordered_set>


#include <android-base/file.h>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/logging.h>
@@ -81,6 +82,7 @@
#define GRANULAR_LOCKS
#define GRANULAR_LOCKS


using android::base::ParseUint;
using android::base::ParseUint;
using android::base::Split;
using android::base::StringPrintf;
using android::base::StringPrintf;
using std::endl;
using std::endl;


@@ -723,21 +725,26 @@ binder::Status InstalldNativeService::createAppDataLocked(
    }
    }


    if (flags & FLAG_STORAGE_SDK) {
    if (flags & FLAG_STORAGE_SDK) {
        auto status = createSdkSandboxDataDirectory(uuid, packageName, userId, appId, previousAppId,
        // Safe to ignore status since we can retry creating this by calling reconcileSdkData
                                                    seInfo, flags);
        auto ignore = createSdkSandboxDataPackageDirectory(uuid, packageName, userId, appId,
        if (!status.isOk()) {
                                                           previousAppId, seInfo, flags);
            return status;
        if (!ignore.isOk()) {
            PLOG(WARNING) << "Failed to create sdk data package directory for " << packageName;
        }
        }

    } else {
        // Package does not need sdk storage. Remove it.
        deleteSdkSandboxDataPackageDirectory(uuid, packageName, userId, flags);
    }
    }


    return ok();
    return ok();
}
}


/**
/**
 * Responsible for creating /data/misc_{ce|de}/user/0/sdksandbox/<app-name> directory and other
 * Responsible for creating /data/misc_{ce|de}/user/0/sdksandbox/<package-name> directory and other
 * app level sub directories, such as ./shared
 * app level sub directories, such as ./shared
 */
 */
binder::Status InstalldNativeService::createSdkSandboxDataDirectory(
binder::Status InstalldNativeService::createSdkSandboxDataPackageDirectory(
        const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
        const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
        int32_t appId, int32_t previousAppId, const std::string& seInfo, int32_t flags) {
        int32_t appId, int32_t previousAppId, const std::string& seInfo, int32_t flags) {
    int32_t sdkSandboxUid = multiuser_get_sdk_sandbox_uid(userId, appId);
    int32_t sdkSandboxUid = multiuser_get_sdk_sandbox_uid(userId, appId);
@@ -746,7 +753,6 @@ binder::Status InstalldNativeService::createSdkSandboxDataDirectory(
        return ok();
        return ok();
    }
    }


    // TODO(b/211763739): what if uuid is not nullptr or TEST?
    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
    const char* uuid_ = uuid ? uuid->c_str() : nullptr;


    constexpr int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE};
    constexpr int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE};
@@ -761,10 +767,14 @@ binder::Status InstalldNativeService::createSdkSandboxDataDirectory(
        // during user creation
        // during user creation


        // Prepare the app directory
        // Prepare the app directory
        auto appPath = create_data_misc_sdk_sandbox_package_path(uuid_, isCeData, userId,
        auto packagePath = create_data_misc_sdk_sandbox_package_path(uuid_, isCeData, userId,
                                                                     packageName.c_str());
                                                                     packageName.c_str());
        if (prepare_app_dir(appPath, 0751, AID_SYSTEM)) {
#if SDK_DEBUG
            return error("Failed to prepare " + appPath);
        LOG(DEBUG) << "Creating app-level sdk data directory: " << packagePath;
#endif

        if (prepare_app_dir(packagePath, 0751, AID_SYSTEM)) {
            return error("Failed to prepare " + packagePath);
        }
        }


        // Now prepare the shared directory which will be accessible by all codes
        // Now prepare the shared directory which will be accessible by all codes
@@ -792,6 +802,32 @@ binder::Status InstalldNativeService::createSdkSandboxDataDirectory(
    return ok();
    return ok();
}
}


/**
 * Responsible for deleting /data/misc_{ce|de}/user/0/sdksandbox/<package-name> directory
 */
binder::Status InstalldNativeService::deleteSdkSandboxDataPackageDirectory(
        const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
        int32_t flags) {
    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
    auto res = ok();

    constexpr int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE};
    for (int currentFlag : storageFlags) {
        if ((flags & currentFlag) == 0) {
            continue;
        }
        bool isCeData = (currentFlag == FLAG_STORAGE_CE);

        const auto& packagePath = create_data_misc_sdk_sandbox_package_path(uuid_, isCeData, userId,
                                                                            packageName.c_str());
        if (delete_dir_contents_and_dir(packagePath, /*ignore_if_missing=*/true) != 0) {
            res = error("Failed to delete sdk package directory: " + packagePath);
        }
    }

    return res;
}

binder::Status InstalldNativeService::createAppData(
binder::Status InstalldNativeService::createAppData(
        const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
        const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
        int32_t flags, int32_t appId, int32_t previousAppId, const std::string& seInfo,
        int32_t flags, int32_t appId, int32_t previousAppId, const std::string& seInfo,
@@ -835,6 +871,140 @@ binder::Status InstalldNativeService::createAppDataBatched(
    return ok();
    return ok();
}
}


binder::Status InstalldNativeService::reconcileSdkData(
        const android::os::ReconcileSdkDataArgs& args) {
    ENFORCE_UID(AID_SYSTEM);
    // Locking is performed depeer in the callstack.

    return reconcileSdkData(args.uuid, args.packageName, args.sdkPackageNames, args.randomSuffixes,
                            args.userId, args.appId, args.previousAppId, args.seInfo, args.flags);
}

/**
 * Reconciles per-sdk directory under app-level sdk data directory.

 * E.g. `/data/misc_ce/0/sdksandbox/<package-name>/<sdkPackageName>-<randomSuffix>
 *
 * - If the sdk data package directory is missing, we create it first.
 * - If sdkPackageNames is empty, we delete sdk package directory since it's not needed anymore.
 * - If a sdk level directory we need to prepare already exist, we skip creating it again. This
 *   is to avoid having same per-sdk directory with different suffix.
 * - If a sdk level directory exist which is absent from sdkPackageNames, we remove it.
 */
binder::Status InstalldNativeService::reconcileSdkData(
        const std::optional<std::string>& uuid, const std::string& packageName,
        const std::vector<std::string>& sdkPackageNames,
        const std::vector<std::string>& randomSuffixes, int userId, int appId, int previousAppId,
        const std::string& seInfo, int flags) {
    CHECK_ARGUMENT_UUID(uuid);
    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
    for (const auto& sdkPackageName : sdkPackageNames) {
        CHECK_ARGUMENT_PACKAGE_NAME(sdkPackageName);
    }
    LOCK_PACKAGE_USER();

#if SDK_DEBUG
    LOG(DEBUG) << "Creating per sdk data directory for: " << packageName;
#endif

    const char* uuid_ = uuid ? uuid->c_str() : nullptr;

    // Validate we have enough randomSuffixStrings
    if (randomSuffixes.size() != sdkPackageNames.size()) {
        return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
                         StringPrintf("Not enough random suffix. Required %d, received %d.",
                                      (int)sdkPackageNames.size(), (int)randomSuffixes.size()));
    }

    // Prepare the sdk package directory in case it's missing
    const auto status = createSdkSandboxDataPackageDirectory(uuid, packageName, userId, appId,
                                                             previousAppId, seInfo, flags);
    if (!status.isOk()) {
        return status;
    }

    auto res = ok();
    // We have to create sdk data for CE and DE storage
    const int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE};
    for (int currentFlag : storageFlags) {
        if ((flags & currentFlag) == 0) {
            continue;
        }
        const bool isCeData = (currentFlag == FLAG_STORAGE_CE);

        // Since random suffix provided will be random every time, we need to ensure we don't end up
        // creating multuple directories for same sdk package with different suffixes. This
        // is ensured by fetching all the existing sub directories and storing them so that we can
        // check for existence later. We also remove unconsumed sdk directories in this check.
        const auto packagePath = create_data_misc_sdk_sandbox_package_path(uuid_, isCeData, userId,
                                                                           packageName.c_str());
        const std::unordered_set<std::string> expectedSdkNames(sdkPackageNames.begin(),
                                                               sdkPackageNames.end());
        // Store paths of per-sdk directory for sdk that already exists
        std::unordered_map<std::string, std::string> sdkNamesThatExist;

        const auto subDirHandler = [&packagePath, &expectedSdkNames, &sdkNamesThatExist,
                                    &res](const std::string& filename) {
            auto filepath = packagePath + "/" + filename;
            auto tokens = Split(filename, "@");
            if (tokens.size() != 2) {
                // Not a per-sdk directory with random suffix
                return;
            }
            auto sdkName = tokens[0];

            // Remove the per-sdk directory if it is not referred in
            // expectedSdkNames
            if (expectedSdkNames.find(sdkName) == expectedSdkNames.end()) {
                if (delete_dir_contents_and_dir(filepath) != 0) {
                    res = error("Failed to delete " + filepath);
                    return;
                }
            } else {
                // Otherwise, store it as existing sdk level directory
                sdkNamesThatExist[sdkName] = filepath;
            }
        };
        const int ec = foreach_subdir(packagePath, subDirHandler);
        if (ec != 0) {
            res = error("Failed to process subdirs for " + packagePath);
            continue;
        }

        // Create sdksandbox data directory for each sdksandbox package
        for (int i = 0, size = sdkPackageNames.size(); i < size; i++) {
            const std::string& sdkName = sdkPackageNames[i];
            const std::string& randomSuffix = randomSuffixes[i];
            std::string path;
            if (const auto& it = sdkNamesThatExist.find(sdkName); it != sdkNamesThatExist.end()) {
                // Already exists. Use existing path instead of creating a new one
                path = it->second;
            } else {
                path = create_data_misc_sdk_sandbox_sdk_path(uuid_, isCeData, userId,
                                                             packageName.c_str(), sdkName.c_str(),
                                                             randomSuffix.c_str());
            }

            // Create the directory along with cache and code_cache
            const int32_t cacheGid = multiuser_get_cache_gid(userId, appId);
            if (cacheGid == -1) {
                return exception(binder::Status::EX_ILLEGAL_STATE,
                                 StringPrintf("cacheGid cannot be -1 for sdk data"));
            }
            const int32_t sandboxUid = multiuser_get_sdk_sandbox_uid(userId, appId);
            int32_t previousSandboxUid = multiuser_get_sdk_sandbox_uid(userId, previousAppId);
            auto status = createAppDataDirs(path, sandboxUid, &previousSandboxUid, cacheGid, seInfo,
                                            0700);
            if (!status.isOk()) {
                res = status;
                continue;
            }
        }
    }

    return res;
}

binder::Status InstalldNativeService::migrateAppData(const std::optional<std::string>& uuid,
binder::Status InstalldNativeService::migrateAppData(const std::optional<std::string>& uuid,
        const std::string& packageName, int32_t userId, int32_t flags) {
        const std::string& packageName, int32_t userId, int32_t flags) {
    ENFORCE_UID(AID_SYSTEM);
    ENFORCE_UID(AID_SYSTEM);
+18 −4
Original line number Original line Diff line number Diff line
@@ -58,6 +58,8 @@ public:
            const std::vector<android::os::CreateAppDataArgs>& args,
            const std::vector<android::os::CreateAppDataArgs>& args,
            std::vector<android::os::CreateAppDataResult>* _aidl_return);
            std::vector<android::os::CreateAppDataResult>* _aidl_return);


    binder::Status reconcileSdkData(const android::os::ReconcileSdkDataArgs& args);

    binder::Status restoreconAppData(const std::optional<std::string>& uuid,
    binder::Status restoreconAppData(const std::optional<std::string>& uuid,
            const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
            const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
            const std::string& seInfo);
            const std::string& seInfo);
@@ -205,10 +207,22 @@ private:
                                       const std::string& seInfo, int32_t targetSdkVersion,
                                       const std::string& seInfo, int32_t targetSdkVersion,
                                       int64_t* _aidl_return);
                                       int64_t* _aidl_return);


    binder::Status createSdkSandboxDataDirectory(const std::optional<std::string>& uuid,
    binder::Status createSdkSandboxDataPackageDirectory(const std::optional<std::string>& uuid,
                                                 const std::string& packageName, int32_t userId,
                                                        const std::string& packageName,
                                                 int32_t appId, int32_t previousAppId,
                                                        int32_t userId, int32_t appId,
                                                        int32_t previousAppId,
                                                        const std::string& seInfo, int32_t flags);
                                                        const std::string& seInfo, int32_t flags);

    binder::Status deleteSdkSandboxDataPackageDirectory(const std::optional<std::string>& uuid,
                                                        const std::string& packageName,
                                                        int32_t userId, int32_t flags);

    binder::Status reconcileSdkData(const std::optional<std::string>& uuid,
                                    const std::string& packageName,
                                    const std::vector<std::string>& sdkPackageNames,
                                    const std::vector<std::string>& randomSuffixes, int32_t userId,
                                    int32_t appId, int32_t previousAppId, const std::string& seInfo,
                                    int flags);
};
};


}  // namespace installd
}  // namespace installd
+2 −0
Original line number Original line Diff line number Diff line
@@ -24,6 +24,8 @@ interface IInstalld {
    android.os.CreateAppDataResult createAppData(in android.os.CreateAppDataArgs args);
    android.os.CreateAppDataResult createAppData(in android.os.CreateAppDataArgs args);
    android.os.CreateAppDataResult[] createAppDataBatched(in android.os.CreateAppDataArgs[] args);
    android.os.CreateAppDataResult[] createAppDataBatched(in android.os.CreateAppDataArgs[] args);


    void reconcileSdkData(in android.os.ReconcileSdkDataArgs args);

    void restoreconAppData(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
    void restoreconAppData(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
            int userId, int flags, int appId, @utf8InCpp String seInfo);
            int userId, int flags, int appId, @utf8InCpp String seInfo);
    void migrateAppData(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
    void migrateAppData(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
+30 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.os;

/** {@hide} */
parcelable ReconcileSdkDataArgs {
    @nullable @utf8InCpp String uuid;
    @utf8InCpp String packageName;
    @utf8InCpp List<String> sdkPackageNames;
    @utf8InCpp List<String> randomSuffixes;
    int userId;
    int appId;
    int previousAppId;
    @utf8InCpp String seInfo;
    int flags;
}
+1 −0
Original line number Original line Diff line number Diff line
@@ -26,6 +26,7 @@ cc_test {
        "libasync_safe",
        "libasync_safe",
        "libdiskusage",
        "libdiskusage",
        "libext2_uuid",
        "libext2_uuid",
        "libgmock",
        "libinstalld",
        "libinstalld",
        "liblog",
        "liblog",
    ],
    ],
Loading