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

Commit 649ed78a authored by Samiul Islam's avatar Samiul Islam Committed by Automerger Merge Worker
Browse files

Create separate api for reconciling per-sdk storage am: b9e96bf4

Original change: https://android-review.googlesource.com/c/platform/frameworks/native/+/2028266

Change-Id: I1ebca84f0ac6fb2c3e4bf61456da7b95782ede5f
parents 5397cb62 b9e96bf4
Loading
Loading
Loading
Loading
+181 −11
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@
#include <fstream>
#include <functional>
#include <regex>
#include <unordered_set>

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

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

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

    if (flags & FLAG_STORAGE_SDK) {
        auto status = createSdkSandboxDataDirectory(uuid, packageName, userId, appId, previousAppId,
                                                    seInfo, flags);
        if (!status.isOk()) {
            return status;
        // Safe to ignore status since we can retry creating this by calling reconcileSdkData
        auto ignore = createSdkSandboxDataPackageDirectory(uuid, packageName, userId, appId,
                                                           previousAppId, seInfo, flags);
        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();
}

/**
 * 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
 */
binder::Status InstalldNativeService::createSdkSandboxDataDirectory(
binder::Status InstalldNativeService::createSdkSandboxDataPackageDirectory(
        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 sdkSandboxUid = multiuser_get_sdk_sandbox_uid(userId, appId);
@@ -746,7 +753,6 @@ binder::Status InstalldNativeService::createSdkSandboxDataDirectory(
        return ok();
    }

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

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

        // 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());
        if (prepare_app_dir(appPath, 0751, AID_SYSTEM)) {
            return error("Failed to prepare " + appPath);
#if SDK_DEBUG
        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
@@ -792,6 +802,32 @@ binder::Status InstalldNativeService::createSdkSandboxDataDirectory(
    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(
        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,
@@ -835,6 +871,140 @@ binder::Status InstalldNativeService::createAppDataBatched(
    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,
        const std::string& packageName, int32_t userId, int32_t flags) {
    ENFORCE_UID(AID_SYSTEM);
+18 −4
Original line number Diff line number Diff line
@@ -58,6 +58,8 @@ public:
            const std::vector<android::os::CreateAppDataArgs>& args,
            std::vector<android::os::CreateAppDataResult>* _aidl_return);

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

    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& seInfo);
@@ -204,10 +206,22 @@ private:
                                       const std::string& seInfo, int32_t targetSdkVersion,
                                       int64_t* _aidl_return);

    binder::Status createSdkSandboxDataDirectory(const std::optional<std::string>& uuid,
                                                 const std::string& packageName, int32_t userId,
                                                 int32_t appId, int32_t previousAppId,
    binder::Status createSdkSandboxDataPackageDirectory(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);

    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
+2 −0
Original line number Diff line number Diff line
@@ -24,6 +24,8 @@ interface IInstalld {
    android.os.CreateAppDataResult createAppData(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,
            int userId, int flags, int appId, @utf8InCpp String seInfo);
    void migrateAppData(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
+30 −0
Original line number 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 Diff line number Diff line
@@ -26,6 +26,7 @@ cc_test {
        "libasync_safe",
        "libdiskusage",
        "libext2_uuid",
        "libgmock",
        "libinstalld",
        "liblog",
    ],
Loading