diff options
| -rw-r--r-- | services/incremental/Android.bp | 1 | ||||
| -rw-r--r-- | services/incremental/IncrementalService.cpp | 145 | ||||
| -rw-r--r-- | services/incremental/IncrementalService.h | 38 | ||||
| -rw-r--r-- | services/incremental/IncrementalServiceValidation.h | 75 | ||||
| -rw-r--r-- | services/incremental/ServiceWrappers.cpp | 4 | ||||
| -rw-r--r-- | services/incremental/ServiceWrappers.h | 25 | ||||
| -rw-r--r-- | services/incremental/test/IncrementalServiceTest.cpp | 21 |
7 files changed, 246 insertions, 63 deletions
diff --git a/services/incremental/Android.bp b/services/incremental/Android.bp index b13d33054e19..02bb0bc3e49c 100644 --- a/services/incremental/Android.bp +++ b/services/incremental/Android.bp @@ -50,6 +50,7 @@ cc_defaults { "libbinder", "libcrypto", "libcutils", + "libdataloader", "libincfs", "liblog", "libz", diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp index 7349cf673cc4..0da167303ccd 100644 --- a/services/incremental/IncrementalService.cpp +++ b/services/incremental/IncrementalService.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "IncrementalService" #include "IncrementalService.h" +#include "IncrementalServiceValidation.h" #include <android-base/file.h> #include <android-base/logging.h> @@ -50,6 +51,9 @@ using namespace std::literals; using namespace android::content::pm; namespace fs = std::filesystem; +constexpr const char* kDataUsageStats = "android.permission.LOADER_USAGE_STATS"; +constexpr const char* kOpUsage = "android:get_usage_stats"; + namespace android::incremental { namespace { @@ -232,6 +236,7 @@ IncrementalService::IncrementalService(ServiceManagerWrapper&& sm, std::string_v : mVold(sm.getVoldService()), mDataLoaderManager(sm.getDataLoaderManager()), mIncFs(sm.getIncFs()), + mAppOpsManager(sm.getAppOpsManager()), mIncrementalDir(rootDir) { if (!mVold) { LOG(FATAL) << "Vold service is unavailable"; @@ -239,6 +244,9 @@ IncrementalService::IncrementalService(ServiceManagerWrapper&& sm, std::string_v if (!mDataLoaderManager) { LOG(FATAL) << "DataLoaderManagerService is unavailable"; } + if (!mAppOpsManager) { + LOG(FATAL) << "AppOpsManager is unavailable"; + } mountExistingImages(); } @@ -279,12 +287,9 @@ void IncrementalService::onDump(int fd) { dprintf(fd, "\t\troot: %s\n", mnt.root.c_str()); dprintf(fd, "\t\tnextStorageDirNo: %d\n", mnt.nextStorageDirNo.load()); dprintf(fd, "\t\tdataLoaderStatus: %d\n", mnt.dataLoaderStatus.load()); - dprintf(fd, "\t\tconnectionLostTime: %s\n", toString(mnt.connectionLostTime)); - dprintf(fd, "\t\tsavedDataLoaderParams:\n"); - if (!mnt.savedDataLoaderParams) { - dprintf(fd, "\t\t\tnone\n"); - } else { - const auto& params = mnt.savedDataLoaderParams.value(); + { + const auto& params = mnt.dataLoaderParams; + dprintf(fd, "\t\tdataLoaderParams:\n"); dprintf(fd, "\t\t\ttype: %s\n", toString(params.type).c_str()); dprintf(fd, "\t\t\tpackageName: %s\n", params.packageName.c_str()); dprintf(fd, "\t\t\tclassName: %s\n", params.className.c_str()); @@ -332,6 +337,7 @@ std::optional<std::future<void>> IncrementalService::onSystemReady() { } std::thread([this, mounts = std::move(mounts)]() { + /* TODO(b/151241369): restore data loaders on reboot. for (auto&& ifs : mounts) { if (prepareDataLoader(*ifs)) { LOG(INFO) << "Successfully started data loader for mount " << ifs->mountId; @@ -340,6 +346,7 @@ std::optional<std::future<void>> IncrementalService::onSystemReady() { LOG(WARNING) << "Failed to start data loader for mount " << ifs->mountId; } } + */ mPrepareDataLoaders.set_value_at_thread_exit(); }).detach(); return mPrepareDataLoaders.get_future(); @@ -459,13 +466,15 @@ StorageId IncrementalService::createStorage( return kInvalidStorageId; } + ifs->dataLoaderParams = std::move(dataLoaderParams); + { metadata::Mount m; m.mutable_storage()->set_id(ifs->mountId); - m.mutable_loader()->set_type((int)dataLoaderParams.type); - m.mutable_loader()->set_package_name(dataLoaderParams.packageName); - m.mutable_loader()->set_class_name(dataLoaderParams.className); - m.mutable_loader()->set_arguments(dataLoaderParams.arguments); + m.mutable_loader()->set_type((int)ifs->dataLoaderParams.type); + m.mutable_loader()->set_package_name(ifs->dataLoaderParams.packageName); + m.mutable_loader()->set_class_name(ifs->dataLoaderParams.className); + m.mutable_loader()->set_arguments(ifs->dataLoaderParams.arguments); const auto metadata = m.SerializeAsString(); m.mutable_loader()->release_arguments(); m.mutable_loader()->release_class_name(); @@ -493,7 +502,7 @@ StorageId IncrementalService::createStorage( // Done here as well, all data structures are in good state. secondCleanupOnFailure.release(); - if (!prepareDataLoader(*ifs, &dataLoaderParams, &dataLoaderStatusListener)) { + if (!prepareDataLoader(*ifs, &dataLoaderStatusListener)) { LOG(ERROR) << "prepareDataLoader() failed"; deleteStorageLocked(*ifs, std::move(l)); return kInvalidStorageId; @@ -573,11 +582,30 @@ int IncrementalService::setStorageParams(StorageId storageId, bool enableReadLog return -EINVAL; } + ifs->dataLoaderFilesystemParams.readLogsEnabled = enableReadLogs; + if (enableReadLogs) { + // We never unregister the callbacks, but given a restricted number of data loaders and even fewer asking for read log access, should be ok. + registerAppOpsCallback(ifs->dataLoaderParams.packageName); + } + + return applyStorageParams(*ifs); +} + +int IncrementalService::applyStorageParams(IncFsMount& ifs) { + const bool enableReadLogs = ifs.dataLoaderFilesystemParams.readLogsEnabled; + if (enableReadLogs) { + if (auto status = CheckPermissionForDataDelivery(kDataUsageStats, kOpUsage); + !status.isOk()) { + LOG(ERROR) << "CheckPermissionForDataDelivery failed: " << status.toString8(); + return fromBinderStatus(status); + } + } + using unique_fd = ::android::base::unique_fd; ::android::os::incremental::IncrementalFileSystemControlParcel control; - control.cmd.reset(unique_fd(dup(ifs->control.cmd()))); - control.pendingReads.reset(unique_fd(dup(ifs->control.pendingReads()))); - auto logsFd = ifs->control.logs(); + control.cmd.reset(unique_fd(dup(ifs.control.cmd()))); + control.pendingReads.reset(unique_fd(dup(ifs.control.pendingReads()))); + auto logsFd = ifs.control.logs(); if (logsFd >= 0) { control.log.reset(unique_fd(dup(logsFd))); } @@ -586,12 +614,7 @@ int IncrementalService::setStorageParams(StorageId storageId, bool enableReadLog const auto status = mVold->setIncFsMountOptions(control, enableReadLogs); if (!status.isOk()) { LOG(ERROR) << "Calling Vold::setIncFsMountOptions() failed: " << status.toString8(); - return status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC - ? status.serviceSpecificErrorCode() > 0 ? -status.serviceSpecificErrorCode() - : status.serviceSpecificErrorCode() == 0 - ? -EFAULT - : status.serviceSpecificErrorCode() - : -EIO; + return fromBinderStatus(status); } return 0; @@ -1015,16 +1038,26 @@ bool IncrementalService::mountExistingImage(std::string_view root) { auto ifs = std::make_shared<IncFsMount>(std::string(root), -1, std::move(control), *this); - auto m = parseFromIncfs<metadata::Mount>(mIncFs.get(), ifs->control, - path::join(mountTarget, constants().infoMdName)); - if (!m.has_loader() || !m.has_storage()) { + auto mount = parseFromIncfs<metadata::Mount>(mIncFs.get(), ifs->control, + path::join(mountTarget, constants().infoMdName)); + if (!mount.has_loader() || !mount.has_storage()) { LOG(ERROR) << "Bad mount metadata in mount at " << root; return false; } - ifs->mountId = m.storage().id(); + ifs->mountId = mount.storage().id(); mNextId = std::max(mNextId, ifs->mountId + 1); + // DataLoader params + { + auto& dlp = ifs->dataLoaderParams; + const auto& loader = mount.loader(); + dlp.type = (android::content::pm::DataLoaderType)loader.type(); + dlp.packageName = loader.package_name(); + dlp.className = loader.class_name(); + dlp.arguments = loader.arguments(); + } + std::vector<std::pair<std::string, metadata::BindPoint>> bindPoints; auto d = openDir(path::c_str(mountTarget)); while (auto e = ::readdir(d.get())) { @@ -1095,23 +1128,9 @@ bool IncrementalService::mountExistingImage(std::string_view root) { } bool IncrementalService::prepareDataLoader(IncrementalService::IncFsMount& ifs, - DataLoaderParamsParcel* params, const DataLoaderStatusListener* externalListener) { if (!mSystemReady.load(std::memory_order_relaxed)) { std::unique_lock l(ifs.lock); - if (params) { - if (ifs.savedDataLoaderParams) { - LOG(WARNING) << "Trying to pass second set of data loader parameters, ignored it"; - } else { - ifs.savedDataLoaderParams = std::move(*params); - } - } else { - if (!ifs.savedDataLoaderParams) { - LOG(ERROR) << "Mount " << ifs.mountId - << " is broken: no data loader params (system is not ready yet)"; - return false; - } - } return true; // eventually... } @@ -1121,12 +1140,6 @@ bool IncrementalService::prepareDataLoader(IncrementalService::IncFsMount& ifs, return true; } - auto* dlp = params ? params - : ifs.savedDataLoaderParams ? &ifs.savedDataLoaderParams.value() : nullptr; - if (!dlp) { - LOG(ERROR) << "Mount " << ifs.mountId << " is broken: no data loader params"; - return false; - } FileSystemControlParcel fsControlParcel; fsControlParcel.incremental = aidl::make_nullable<IncrementalFileSystemControlParcel>(); fsControlParcel.incremental->cmd.reset(base::unique_fd(::dup(ifs.control.cmd()))); @@ -1138,13 +1151,11 @@ bool IncrementalService::prepareDataLoader(IncrementalService::IncFsMount& ifs, externalListener ? *externalListener : DataLoaderStatusListener()); bool created = false; - auto status = mDataLoaderManager->initializeDataLoader(ifs.mountId, *dlp, fsControlParcel, - listener, &created); + auto status = mDataLoaderManager->initializeDataLoader(ifs.mountId, ifs.dataLoaderParams, fsControlParcel, listener, &created); if (!status.isOk() || !created) { LOG(ERROR) << "Failed to create a data loader for mount " << ifs.mountId; return false; } - ifs.savedDataLoaderParams.reset(); return true; } @@ -1268,6 +1279,42 @@ bool IncrementalService::configureNativeBinaries(StorageId storage, std::string_ return success; } +void IncrementalService::registerAppOpsCallback(const std::string& packageName) { + if (packageName.empty()) { + return; + } + + { + std::unique_lock lock{mCallbacksLock}; + if (!mCallbackRegistered.insert(packageName).second) { + return; + } + } + + /* TODO(b/152633648): restore callback after it's not crashing Binder anymore. + sp<AppOpsListener> listener = new AppOpsListener(*this, packageName); + mAppOpsManager->startWatchingMode(AppOpsManager::OP_GET_USAGE_STATS, String16(packageName.c_str()), listener); + */ +} + +void IncrementalService::onAppOppChanged(const std::string& packageName) { + std::vector<IfsMountPtr> affected; + { + std::lock_guard l(mLock); + affected.reserve(mMounts.size()); + for (auto&& [id, ifs] : mMounts) { + if (ifs->dataLoaderFilesystemParams.readLogsEnabled && ifs->dataLoaderParams.packageName == packageName) { + affected.push_back(ifs); + } + } + } + /* TODO(b/152633648): restore callback after it's not crashing Kernel anymore. + for (auto&& ifs : affected) { + applyStorageParams(*ifs); + } + */ +} + binder::Status IncrementalService::IncrementalDataLoaderListener::onStatusChanged(MountId mountId, int newStatus) { if (externalListener) { @@ -1331,4 +1378,8 @@ binder::Status IncrementalService::IncrementalDataLoaderListener::onStatusChange return binder::Status::ok(); } +void IncrementalService::AppOpsListener::opChanged(int32_t op, const String16&) { + incrementalService.onAppOppChanged(packageName); +} + } // namespace android::incremental diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h index 3615314c7162..ff69633e185b 100644 --- a/services/incremental/IncrementalService.h +++ b/services/incremental/IncrementalService.h @@ -40,6 +40,7 @@ #include "ServiceWrappers.h" #include "android/content/pm/BnDataLoaderStatusListener.h" #include "incfs.h" +#include "dataloader_ndk.h" #include "path.h" using namespace android::os::incremental; @@ -132,6 +133,7 @@ public: bool startLoading(StorageId storage) const; bool configureNativeBinaries(StorageId storage, std::string_view apkFullPath, std::string_view libDirRelativePath, std::string_view abi); + class IncrementalDataLoaderListener : public android::content::pm::BnDataLoaderStatusListener { public: IncrementalDataLoaderListener(IncrementalService& incrementalService, @@ -145,6 +147,16 @@ public: DataLoaderStatusListener externalListener; }; + class AppOpsListener : public android::BnAppOpsCallback { + public: + AppOpsListener(IncrementalService& incrementalService, std::string packageName) : incrementalService(incrementalService), packageName(std::move(packageName)) {} + void opChanged(int32_t op, const String16& packageName) override; + + private: + IncrementalService& incrementalService; + const std::string packageName; + }; + private: struct IncFsMount { struct Bind { @@ -169,11 +181,11 @@ private: /*const*/ MountId mountId; StorageMap storages; BindMap bindPoints; - std::optional<DataLoaderParamsParcel> savedDataLoaderParams; + DataLoaderParamsParcel dataLoaderParams; + DataLoaderFilesystemParams dataLoaderFilesystemParams; std::atomic<int> nextStorageDirNo{0}; std::atomic<int> dataLoaderStatus = -1; bool dataLoaderStartRequested = false; - TimePoint connectionLostTime = TimePoint(); const IncrementalService& incrementalService; IncFsMount(std::string root, MountId mountId, Control control, @@ -181,7 +193,9 @@ private: : root(std::move(root)), control(std::move(control)), mountId(mountId), - incrementalService(incrementalService) {} + incrementalService(incrementalService) { + dataLoaderFilesystemParams.readLogsEnabled = false; + } IncFsMount(IncFsMount&&) = delete; IncFsMount& operator=(IncFsMount&&) = delete; ~IncFsMount(); @@ -208,8 +222,7 @@ private: std::string&& source, std::string&& target, BindKind kind, std::unique_lock<std::mutex>& mainLock); - bool prepareDataLoader(IncFsMount& ifs, DataLoaderParamsParcel* params = nullptr, - const DataLoaderStatusListener* externalListener = nullptr); + bool prepareDataLoader(IncFsMount& ifs, const DataLoaderStatusListener* externalListener = nullptr); bool startDataLoader(MountId mountId) const; BindPathMap::const_iterator findStorageLocked(std::string_view path) const; @@ -221,10 +234,16 @@ private: std::string normalizePathToStorage(const IfsMountPtr incfs, StorageId storage, std::string_view path); + int applyStorageParams(IncFsMount& ifs); + + void registerAppOpsCallback(const std::string& packageName); + void onAppOppChanged(const std::string& packageName); + // Member variables - std::unique_ptr<VoldServiceWrapper> mVold; - std::unique_ptr<DataLoaderManagerWrapper> mDataLoaderManager; - std::unique_ptr<IncFsWrapper> mIncFs; + std::unique_ptr<VoldServiceWrapper> const mVold; + std::unique_ptr<DataLoaderManagerWrapper> const mDataLoaderManager; + std::unique_ptr<IncFsWrapper> const mIncFs; + std::unique_ptr<AppOpsManagerWrapper> const mAppOpsManager; const std::string mIncrementalDir; mutable std::mutex mLock; @@ -232,6 +251,9 @@ private: MountMap mMounts; BindPathMap mBindsByPath; + std::mutex mCallbacksLock; + std::set<std::string> mCallbackRegistered; + std::atomic_bool mSystemReady = false; StorageId mNextId = 0; std::promise<void> mPrepareDataLoaders; diff --git a/services/incremental/IncrementalServiceValidation.h b/services/incremental/IncrementalServiceValidation.h new file mode 100644 index 000000000000..24f9f7f94dfd --- /dev/null +++ b/services/incremental/IncrementalServiceValidation.h @@ -0,0 +1,75 @@ +/* + * 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. + */ + +#pragma once + +#include <android-base/stringprintf.h> +#include <binder/IPCThreadState.h> +#include <binder/PermissionCache.h> +#include <binder/PermissionController.h> +#include <binder/Status.h> + +namespace android::incremental { + +inline binder::Status Ok() { + return binder::Status::ok(); +} + +inline binder::Status Exception(uint32_t code, const std::string& msg) { + return binder::Status::fromExceptionCode(code, String8(msg.c_str())); +} + +inline 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; +} + +inline binder::Status CheckPermissionForDataDelivery(const char* permission, const char* operation) { + 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)); + } + + // Caller must also have op granted. + PermissionController pc; + // Package is a required parameter. Need to obtain one. + Vector<String16> packages; + pc.getPackagesForUid(uid, packages); + if (packages.empty()) { + return Exception(binder::Status::EX_SECURITY, + StringPrintf("UID %d / PID %d has no packages", uid, pid)); + } + switch (auto result = pc.noteOp(String16(operation), uid, packages[0]); 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 lacks app-op %s, error %d", uid, pid, + operation, result)); + } +} + +} // namespace android::incremental diff --git a/services/incremental/ServiceWrappers.cpp b/services/incremental/ServiceWrappers.cpp index 2e31ef1dcc2f..9f4192fbf531 100644 --- a/services/incremental/ServiceWrappers.cpp +++ b/services/incremental/ServiceWrappers.cpp @@ -59,4 +59,8 @@ std::unique_ptr<IncFsWrapper> RealServiceManager::getIncFs() { return std::make_unique<RealIncFs>(); } +std::unique_ptr<AppOpsManagerWrapper> RealServiceManager::getAppOpsManager() { + return std::make_unique<RealAppOpsManager>(); +} + } // namespace android::os::incremental diff --git a/services/incremental/ServiceWrappers.h b/services/incremental/ServiceWrappers.h index c3300305f515..449b457045c6 100644 --- a/services/incremental/ServiceWrappers.h +++ b/services/incremental/ServiceWrappers.h @@ -24,6 +24,7 @@ #include <android/content/pm/IDataLoaderManager.h> #include <android/content/pm/IDataLoaderStatusListener.h> #include <android/os/IVold.h> +#include <binder/AppOpsManager.h> #include <binder/IServiceManager.h> #include <incfs.h> @@ -81,12 +82,19 @@ public: virtual ErrorCode writeBlocks(Span<const DataBlock> blocks) const = 0; }; +class AppOpsManagerWrapper { +public: + virtual ~AppOpsManagerWrapper() = default; + virtual void startWatchingMode(int32_t op, const String16& packageName, const sp<IAppOpsCallback>& callback) = 0; +}; + class ServiceManagerWrapper { public: virtual ~ServiceManagerWrapper() = default; virtual std::unique_ptr<VoldServiceWrapper> getVoldService() = 0; virtual std::unique_ptr<DataLoaderManagerWrapper> getDataLoaderManager() = 0; virtual std::unique_ptr<IncFsWrapper> getIncFs() = 0; + virtual std::unique_ptr<AppOpsManagerWrapper> getAppOpsManager() = 0; }; // --- Real stuff --- @@ -137,13 +145,24 @@ private: sp<content::pm::IDataLoaderManager> mInterface; }; +class RealAppOpsManager : public AppOpsManagerWrapper { +public: + ~RealAppOpsManager() = default; + void startWatchingMode(int32_t op, const String16& packageName, const sp<IAppOpsCallback>& callback) override { + mAppOpsManager.startWatchingMode(op, packageName, callback); + } +private: + android::AppOpsManager mAppOpsManager; +}; + class RealServiceManager : public ServiceManagerWrapper { public: RealServiceManager(sp<IServiceManager> serviceManager); ~RealServiceManager() = default; - std::unique_ptr<VoldServiceWrapper> getVoldService() override; - std::unique_ptr<DataLoaderManagerWrapper> getDataLoaderManager() override; - std::unique_ptr<IncFsWrapper> getIncFs() override; + std::unique_ptr<VoldServiceWrapper> getVoldService() final; + std::unique_ptr<DataLoaderManagerWrapper> getDataLoaderManager() final; + std::unique_ptr<IncFsWrapper> getIncFs() final; + std::unique_ptr<AppOpsManagerWrapper> getAppOpsManager() final; private: template <class INTERFACE> diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp index cde38fbb3ca2..5553f688060a 100644 --- a/services/incremental/test/IncrementalServiceTest.cpp +++ b/services/incremental/test/IncrementalServiceTest.cpp @@ -220,24 +220,32 @@ public: } }; +class MockAppOpsManager : public AppOpsManagerWrapper { + MOCK_METHOD3(startWatchingMode, void(int32_t, const String16&, const sp<IAppOpsCallback>&)); +}; + class MockServiceManager : public ServiceManagerWrapper { public: MockServiceManager(std::unique_ptr<MockVoldService> vold, std::unique_ptr<MockDataLoaderManager> manager, - std::unique_ptr<MockIncFs> incfs) + std::unique_ptr<MockIncFs> incfs, + std::unique_ptr<MockAppOpsManager> appOpsManager) : mVold(std::move(vold)), mDataLoaderManager(std::move(manager)), - mIncFs(std::move(incfs)) {} + mIncFs(std::move(incfs)), + mAppOpsManager(std::move(appOpsManager)) {} std::unique_ptr<VoldServiceWrapper> getVoldService() final { return std::move(mVold); } std::unique_ptr<DataLoaderManagerWrapper> getDataLoaderManager() final { return std::move(mDataLoaderManager); } std::unique_ptr<IncFsWrapper> getIncFs() final { return std::move(mIncFs); } + std::unique_ptr<AppOpsManagerWrapper> getAppOpsManager() final { return std::move(mAppOpsManager); } private: std::unique_ptr<MockVoldService> mVold; std::unique_ptr<MockDataLoaderManager> mDataLoaderManager; std::unique_ptr<MockIncFs> mIncFs; + std::unique_ptr<MockAppOpsManager> mAppOpsManager; }; // --- IncrementalServiceTest --- @@ -251,11 +259,13 @@ public: mDataLoaderManager = dataloaderManager.get(); auto incFs = std::make_unique<NiceMock<MockIncFs>>(); mIncFs = incFs.get(); + auto appOps = std::make_unique<NiceMock<MockAppOpsManager>>(); + mAppOpsManager = appOps.get(); mIncrementalService = std::make_unique<IncrementalService>(MockServiceManager(std::move(vold), - std::move( - dataloaderManager), - std::move(incFs)), + std::move(dataloaderManager), + std::move(incFs), + std::move(appOps)), mRootDir.path); mDataLoaderParcel.packageName = "com.test"; mDataLoaderParcel.arguments = "uri"; @@ -287,6 +297,7 @@ protected: NiceMock<MockVoldService>* mVold; NiceMock<MockIncFs>* mIncFs; NiceMock<MockDataLoaderManager>* mDataLoaderManager; + NiceMock<MockAppOpsManager>* mAppOpsManager; std::unique_ptr<IncrementalService> mIncrementalService; TemporaryDir mRootDir; DataLoaderParamsParcel mDataLoaderParcel; |