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

Commit 629051fd authored by Yurii Zubrytskyi's avatar Yurii Zubrytskyi
Browse files

[incfs] Use MountRegistry to import existing mounts on start

This is a big cleanup in IncrementalService that makes it behave
nicely on runtime restart, and more:

- fixed a bunch of threading issues in createStorage/bind
- made public functions correctly accept any path in any
  bind mount and translate it to the proper root mount
- got rid of "using namespace" in headers, cleaned includes
- removed all unused functions
- set CLOEXEC bit on all duped FDs

Bug: 151241369
Test: atest PackageManagerShellCommandTest \
  PackageManagerShellCommandIncrementalTest \
  IncrementalServiceTest

Change-Id: Ided4415aabfbfca3925b5e71c91896055886ac4a
parent 360bbdc7
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@ filegroup {
    srcs: [
        "incremental_service.c",
        "IncrementalService.cpp",
        "IncrementalServiceValidation.cpp",
        "BinderIncrementalService.cpp",
        "path.cpp",
        "ServiceWrappers.cpp",
+6 −7
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@

#include <android-base/logging.h>
#include <android-base/no_destructor.h>
#include <android/os/IVold.h>
#include <binder/IResultReceiver.h>
#include <binder/PermissionCache.h>
#include <incfs.h>
@@ -117,11 +118,12 @@ binder::Status BinderIncrementalService::openStorage(const std::string& path,
}

binder::Status BinderIncrementalService::createStorage(
        const std::string& path, const DataLoaderParamsParcel& params,
        const std::string& path, const content::pm::DataLoaderParamsParcel& params,
        const ::android::sp<::android::content::pm::IDataLoaderStatusListener>& listener,
        int32_t createMode, int32_t* _aidl_return) {
    *_aidl_return =
            mImpl.createStorage(path, const_cast<DataLoaderParamsParcel&&>(params), listener,
            mImpl.createStorage(path, const_cast<content::pm::DataLoaderParamsParcel&&>(params),
                                listener,
                                android::incremental::IncrementalService::CreateOptions(
                                        createMode));
    return ok();
@@ -238,11 +240,8 @@ binder::Status BinderIncrementalService::isFileRangeLoaded(int32_t storageId,
binder::Status BinderIncrementalService::getMetadataByPath(int32_t storageId,
                                                           const std::string& path,
                                                           std::vector<uint8_t>* _aidl_return) {
    auto fid = mImpl.nodeFor(storageId, path);
    if (fid != kIncFsInvalidFileId) {
        auto metadata = mImpl.getMetadata(storageId, fid);
    auto metadata = mImpl.getMetadata(storageId, path);
    _aidl_return->assign(metadata.begin(), metadata.end());
    }
    return ok();
}

+428 −214

File changed.

Preview size limit exceeded, changes collapsed.

+34 −35
Original line number Diff line number Diff line
@@ -16,13 +16,13 @@

#pragma once

#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <android/content/pm/BnDataLoaderStatusListener.h>
#include <android/content/pm/DataLoaderParamsParcel.h>
#include <binder/IServiceManager.h>
#include <android/content/pm/IDataLoaderStatusListener.h>
#include <android/os/incremental/BnIncrementalServiceConnector.h>
#include <binder/IAppOpsCallback.h>
#include <utils/String16.h>
#include <utils/StrongPointer.h>
#include <utils/Vector.h>
#include <ziparchive/zip_archive.h>

#include <atomic>
@@ -37,21 +37,14 @@
#include <string_view>
#include <thread>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>

#include "ServiceWrappers.h"
#include "android/content/pm/BnDataLoaderStatusListener.h"
#include "android/os/incremental/BnIncrementalServiceConnector.h"
#include "incfs.h"
#include "path.h"

using namespace android::os::incremental;

namespace android::os {
class IVold;
}

namespace android::incremental {

using MountId = int;
@@ -101,17 +94,14 @@ public:

    void onSystemReady();

    StorageId createStorage(std::string_view mountPoint, DataLoaderParamsParcel&& dataLoaderParams,
    StorageId createStorage(std::string_view mountPoint,
                            content::pm::DataLoaderParamsParcel&& dataLoaderParams,
                            const DataLoaderStatusListener& dataLoaderStatusListener,
                            CreateOptions options = CreateOptions::Default);
    StorageId createLinkedStorage(std::string_view mountPoint, StorageId linkedStorage,
                                  CreateOptions options = CreateOptions::Default);
    StorageId openStorage(std::string_view path);

    FileId nodeFor(StorageId storage, std::string_view path) const;
    std::pair<FileId, std::string_view> parentAndNameFor(StorageId storage,
                                                         std::string_view path) const;

    int bind(StorageId storage, std::string_view source, std::string_view target, BindKind kind);
    int unbind(StorageId storage, std::string_view target);
    void deleteStorage(StorageId storage);
@@ -131,9 +121,9 @@ public:
        return false;
    }

    RawMetadata getMetadata(StorageId storage, std::string_view path) const;
    RawMetadata getMetadata(StorageId storage, FileId node) const;

    std::vector<std::string> listFiles(StorageId storage) const;
    bool startLoading(StorageId storage) const;

    bool configureNativeBinaries(StorageId storage, std::string_view apkFullPath,
@@ -151,7 +141,7 @@ public:
        const std::string packageName;
    };

    class IncrementalServiceConnector : public BnIncrementalServiceConnector {
    class IncrementalServiceConnector : public os::incremental::BnIncrementalServiceConnector {
    public:
        IncrementalServiceConnector(IncrementalService& incrementalService, int32_t storage)
              : incrementalService(incrementalService), storage(storage) {}
@@ -163,14 +153,13 @@ public:
    };

private:
    static const bool sEnablePerfLogging;

    struct IncFsMount;

    class DataLoaderStub : public android::content::pm::BnDataLoaderStatusListener {
    class DataLoaderStub : public content::pm::BnDataLoaderStatusListener {
    public:
        DataLoaderStub(IncrementalService& service, MountId id, DataLoaderParamsParcel&& params,
                       FileSystemControlParcel&& control,
        DataLoaderStub(IncrementalService& service, MountId id,
                       content::pm::DataLoaderParamsParcel&& params,
                       content::pm::FileSystemControlParcel&& control,
                       const DataLoaderStatusListener* externalListener);
        ~DataLoaderStub();
        // Cleans up the internal state and invalidates DataLoaderStub. Any subsequent calls will
@@ -184,7 +173,7 @@ private:
        void onDump(int fd);

        MountId id() const { return mId; }
        const DataLoaderParamsParcel& params() const { return mParams; }
        const content::pm::DataLoaderParamsParcel& params() const { return mParams; }

    private:
        binder::Status onStatusChanged(MountId mount, int newStatus) final;
@@ -202,14 +191,14 @@ private:

        IncrementalService& mService;
        MountId mId = kInvalidStorageId;
        DataLoaderParamsParcel mParams;
        FileSystemControlParcel mControl;
        content::pm::DataLoaderParamsParcel mParams;
        content::pm::FileSystemControlParcel mControl;
        DataLoaderStatusListener mListener;

        std::mutex mStatusMutex;
        std::condition_variable mStatusCondition;
        int mCurrentStatus = IDataLoaderStatusListener::DATA_LOADER_DESTROYED;
        int mTargetStatus = IDataLoaderStatusListener::DATA_LOADER_DESTROYED;
        int mCurrentStatus = content::pm::IDataLoaderStatusListener::DATA_LOADER_DESTROYED;
        int mTargetStatus = content::pm::IDataLoaderStatusListener::DATA_LOADER_DESTROYED;
        TimePoint mTargetStatusTs = {};
    };
    using DataLoaderStubPtr = sp<DataLoaderStub>;
@@ -228,7 +217,7 @@ private:

        using Control = incfs::UniqueControl;

        using BindMap = std::map<std::string, Bind>;
        using BindMap = std::map<std::string, Bind, path::PathLess>;
        using StorageMap = std::unordered_map<StorageId, Storage>;

        mutable std::mutex lock;
@@ -260,7 +249,10 @@ private:
    using MountMap = std::unordered_map<MountId, IfsMountPtr>;
    using BindPathMap = std::map<std::string, IncFsMount::BindMap::iterator, path::PathLess>;

    void mountExistingImages();
    static bool perfLoggingEnabled();

    std::unordered_set<std::string_view> adoptMountedInstances();
    void mountExistingImages(const std::unordered_set<std::string_view>& mountedRootNames);
    bool mountExistingImage(std::string_view root);

    IfsMountPtr getIfs(StorageId storage) const;
@@ -273,7 +265,13 @@ private:
                           std::string&& source, std::string&& target, BindKind kind,
                           std::unique_lock<std::mutex>& mainLock);

    DataLoaderStubPtr prepareDataLoader(IncFsMount& ifs, DataLoaderParamsParcel&& params,
    void addBindMountRecordLocked(IncFsMount& ifs, StorageId storage, std::string&& metadataName,
                                  std::string&& source, std::string&& target, BindKind kind);

    DataLoaderStubPtr prepareDataLoader(IncFsMount& ifs,
                                        content::pm::DataLoaderParamsParcel&& params,
                                        const DataLoaderStatusListener* externalListener = nullptr);
    void prepareDataLoaderLocked(IncFsMount& ifs, content::pm::DataLoaderParamsParcel&& params,
                                 const DataLoaderStatusListener* externalListener = nullptr);

    BindPathMap::const_iterator findStorageLocked(std::string_view path) const;
@@ -283,9 +281,10 @@ private:
    void deleteStorageLocked(IncFsMount& ifs, std::unique_lock<std::mutex>&& ifsLock);
    MountMap::iterator getStorageSlotLocked();
    std::string normalizePathToStorage(const IfsMountPtr& incfs, StorageId storage,
                                       std::string_view path);
    std::string normalizePathToStorageLocked(IncFsMount::StorageMap::iterator storageIt,
                                             std::string_view path);
                                       std::string_view path) const;
    std::string normalizePathToStorageLocked(const IfsMountPtr& incfs,
                                             IncFsMount::StorageMap::iterator storageIt,
                                             std::string_view path) const;

    binder::Status applyStorageParams(IncFsMount& ifs, bool enableReadLogs);

+77 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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.
 */

#include "IncrementalServiceValidation.h"

#include <android-base/stringprintf.h>
#include <binder/IPCThreadState.h>
#include <binder/PermissionCache.h>
#include <binder/PermissionController.h>
#include <errno.h>
#include <utils/String16.h>

namespace android::incremental {

binder::Status Ok() {
    return binder::Status::ok();
}

binder::Status Exception(uint32_t code, const std::string& msg) {
    return binder::Status::fromExceptionCode(code, String8(msg.c_str()));
}

int fromBinderStatus(const binder::Status& status) {
    return status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC
            ? status.serviceSpecificErrorCode() > 0
                    ? -status.serviceSpecificErrorCode()
                    : status.serviceSpecificErrorCode() == 0 ? -EFAULT
                                                             : status.serviceSpecificErrorCode()
            : -EIO;
}

binder::Status CheckPermissionForDataDelivery(const char* permission, const char* operation,
                                              const char* package) {
    using android::base::StringPrintf;

    int32_t pid;
    int32_t uid;

    if (!PermissionCache::checkCallingPermission(String16(permission), &pid, &uid)) {
        return Exception(binder::Status::EX_SECURITY,
                         StringPrintf("UID %d / PID %d lacks permission %s", uid, pid, permission));
    }

    String16 packageName{package};

    // Caller must also have op granted.
    PermissionController pc;
    if (auto packageUid = pc.getPackageUid(packageName, 0); packageUid != uid) {
        return Exception(binder::Status::EX_SECURITY,
                         StringPrintf("UID %d / PID %d does not own package %s", uid, pid,
                                      package));
    }
    switch (auto result = pc.noteOp(String16(operation), uid, packageName); result) {
        case PermissionController::MODE_ALLOWED:
        case PermissionController::MODE_DEFAULT:
            return binder::Status::ok();
        default:
            return Exception(binder::Status::EX_SECURITY,
                             StringPrintf("UID %d / PID %d / package %s lacks app-op %s, error %d",
                                          uid, pid, package, operation, result));
    }
}

} // namespace android::incremental
Loading