diff options
author | Alex Buynytskyy <alexbuy@google.com> | 2020-05-05 12:48:41 -0700 |
---|---|---|
committer | Alex Buynytskyy <alexbuy@google.com> | 2020-05-07 21:22:14 +0000 |
commit | cca2c1110ce3eed8820579d0319d015aa4cdcf55 (patch) | |
tree | f11979e28df0dcd45c54b2319683f809758e307f | |
parent | 7efdd5d903848c592d9bcd2e1fc3844f4cace3ca (diff) |
Lifecycle: detecting pending reads.
Once pending read detected, try to start the dataloader.
Bug: 153874006
Test: test PackageManagerShellCommandTest PackageManagerShellCommandIncrementalTest IncrementalServiceTest
Change-Id: Ia8169ccbb0f710317715e6fddb9bc6a718543766
-rw-r--r-- | services/incremental/IncrementalService.cpp | 116 | ||||
-rw-r--r-- | services/incremental/IncrementalService.h | 17 | ||||
-rw-r--r-- | services/incremental/ServiceWrappers.cpp | 21 | ||||
-rw-r--r-- | services/incremental/ServiceWrappers.h | 13 | ||||
-rw-r--r-- | services/incremental/test/IncrementalServiceTest.cpp | 122 |
5 files changed, 269 insertions, 20 deletions
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp index c3c215730e4c..d412a19f241f 100644 --- a/services/incremental/IncrementalService.cpp +++ b/services/incremental/IncrementalService.cpp @@ -266,6 +266,7 @@ IncrementalService::IncrementalService(ServiceManagerWrapper&& sm, std::string_v mIncFs(sm.getIncFs()), mAppOpsManager(sm.getAppOpsManager()), mJni(sm.getJni()), + mLooper(sm.getLooper()), mIncrementalDir(rootDir) { if (!mVold) { LOG(FATAL) << "Vold service is unavailable"; @@ -276,12 +277,22 @@ IncrementalService::IncrementalService(ServiceManagerWrapper&& sm, std::string_v if (!mAppOpsManager) { LOG(FATAL) << "AppOpsManager is unavailable"; } + if (!mJni) { + LOG(FATAL) << "JNI is unavailable"; + } + if (!mLooper) { + LOG(FATAL) << "Looper is unavailable"; + } mJobQueue.reserve(16); mJobProcessor = std::thread([this]() { mJni->initializeForCurrentThread(); runJobProcessing(); }); + mCmdLooperThread = std::thread([this]() { + mJni->initializeForCurrentThread(); + runCmdLooper(); + }); const auto mountedRootNames = adoptMountedInstances(); mountExistingImages(mountedRootNames); @@ -294,6 +305,7 @@ IncrementalService::~IncrementalService() { } mJobCondition.notify_all(); mJobProcessor.join(); + mCmdLooperThread.join(); } static const char* toString(IncrementalService::BindKind kind) { @@ -1315,6 +1327,13 @@ bool IncrementalService::mountExistingImage(std::string_view root) { return true; } +void IncrementalService::runCmdLooper() { + constexpr auto kTimeoutMsecs = 1000; + while (mRunning.load(std::memory_order_relaxed)) { + mLooper->pollAll(kTimeoutMsecs); + } +} + IncrementalService::DataLoaderStubPtr IncrementalService::prepareDataLoader( IncFsMount& ifs, DataLoaderParamsParcel&& params, const DataLoaderStatusListener* externalListener) { @@ -1337,8 +1356,16 @@ void IncrementalService::prepareDataLoaderLocked(IncFsMount& ifs, DataLoaderPara fsControlParcel.incremental->log.reset(dup(ifs.control.logs())); fsControlParcel.service = new IncrementalServiceConnector(*this, ifs.mountId); - ifs.dataLoaderStub = new DataLoaderStub(*this, ifs.mountId, std::move(params), - std::move(fsControlParcel), externalListener); + incfs::UniqueControl healthControl = mIncFs->openMount(ifs.root.c_str()); + if (healthControl.pendingReads() < 0) { + LOG(ERROR) << "Failed to open health control for: " << ifs.root << "(" + << healthControl.cmd() << ":" << healthControl.pendingReads() << ":" + << healthControl.logs() << ")"; + } + + ifs.dataLoaderStub = + new DataLoaderStub(*this, ifs.mountId, std::move(params), std::move(fsControlParcel), + std::move(healthControl), externalListener); } template <class Duration> @@ -1658,24 +1685,34 @@ void IncrementalService::onAppOpChanged(const std::string& packageName) { IncrementalService::DataLoaderStub::DataLoaderStub(IncrementalService& service, MountId id, DataLoaderParamsParcel&& params, FileSystemControlParcel&& control, + incfs::UniqueControl&& healthControl, const DataLoaderStatusListener* externalListener) : mService(service), mId(id), mParams(std::move(params)), mControl(std::move(control)), + mHealthControl(std::move(healthControl)), mListener(externalListener ? *externalListener : DataLoaderStatusListener()) { + addToCmdLooperLocked(); } -IncrementalService::DataLoaderStub::~DataLoaderStub() = default; +IncrementalService::DataLoaderStub::~DataLoaderStub() { + if (mId != kInvalidStorageId) { + cleanupResources(); + } +} void IncrementalService::DataLoaderStub::cleanupResources() { requestDestroy(); auto now = Clock::now(); - std::unique_lock lock(mMutex); + + removeFromCmdLooperLocked(); + mParams = {}; mControl = {}; + mHealthControl = {}; mStatusCondition.wait_until(lock, now + 60s, [this] { return mCurrentStatus == IDataLoaderStatusListener::DATA_LOADER_DESTROYED; }); @@ -1710,21 +1747,19 @@ bool IncrementalService::DataLoaderStub::requestDestroy() { } bool IncrementalService::DataLoaderStub::setTargetStatus(int newStatus) { - int oldStatus, curStatus; { std::unique_lock lock(mMutex); - oldStatus = mTargetStatus; - curStatus = mCurrentStatus; setTargetStatusLocked(newStatus); } - LOG(DEBUG) << "Target status update for DataLoader " << mId << ": " << oldStatus << " -> " - << newStatus << " (current " << curStatus << ")"; return fsmStep(); } void IncrementalService::DataLoaderStub::setTargetStatusLocked(int status) { + auto oldStatus = mTargetStatus; mTargetStatus = status; mTargetStatusTs = Clock::now(); + LOG(DEBUG) << "Target status update for DataLoader " << mId << ": " << oldStatus << " -> " + << status << " (current " << mCurrentStatus << ")"; } bool IncrementalService::DataLoaderStub::bind() { @@ -1860,12 +1895,75 @@ binder::Status IncrementalService::DataLoaderStub::onStatusChanged(MountId mount return binder::Status::ok(); } +void IncrementalService::DataLoaderStub::addToCmdLooperLocked() { + const auto pendingReadsFd = mHealthControl.pendingReads(); + if (pendingReadsFd < 0) { + return; + } + + mService.mLooper->addFd( + pendingReadsFd, android::Looper::POLL_CALLBACK, android::Looper::EVENT_INPUT, + [](int, int, void* data) -> int { + auto&& self = (DataLoaderStub*)data; + return self->onCmdLooperEvent(); + }, + this); + mService.mLooper->wake(); +} + +void IncrementalService::DataLoaderStub::removeFromCmdLooperLocked() { + const auto pendingReadsFd = mHealthControl.pendingReads(); + if (pendingReadsFd < 0) { + return; + } + + mService.mLooper->removeFd(pendingReadsFd); + mService.mLooper->wake(); +} + +int IncrementalService::DataLoaderStub::onCmdLooperEvent() { + if (!mService.mRunning.load(std::memory_order_relaxed)) { + return 0; + } + + bool pendingReadsOccur = false; + + { + std::unique_lock lock(mMutex); + const auto now = Clock::now(); + if (now < mEarliestMissingPageTs) { + // Transition: duration::max -> now. + mEarliestMissingPageTs = now; + pendingReadsOccur = true; + } + } + + if (pendingReadsOccur) { + LOG(INFO) << "Pending reads occur for, requesting start for: " << mId; + requestStart(); + } + + { + // Drop pending reads. + static constexpr auto kMaxDropIterations = 3; + std::unique_lock lock(mMutex); + for (int i = 0; i < kMaxDropIterations; ++i) { + if (IncFs_DropPendingReads(mHealthControl) <= 0) { + break; + } + } + } + return 1; +} + void IncrementalService::DataLoaderStub::onDump(int fd) { dprintf(fd, " dataLoader: {\n"); dprintf(fd, " currentStatus: %d\n", mCurrentStatus); dprintf(fd, " targetStatus: %d\n", mTargetStatus); dprintf(fd, " targetStatusTs: %lldmcs\n", (long long)(elapsedMcs(mTargetStatusTs, Clock::now()))); + dprintf(fd, " earliestMissingPageTs: %lldmcs\n", + (long long)(elapsedMcs(mEarliestMissingPageTs, Clock::now()))); const auto& params = mParams; dprintf(fd, " dataLoaderParams: {\n"); dprintf(fd, " type: %s\n", toString(params.type).c_str()); diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h index cf310b15b6d9..640ca53e80d4 100644 --- a/services/incremental/IncrementalService.h +++ b/services/incremental/IncrementalService.h @@ -18,6 +18,7 @@ #include <android/content/pm/BnDataLoaderStatusListener.h> #include <android/content/pm/DataLoaderParamsParcel.h> +#include <android/content/pm/FileSystemControlParcel.h> #include <android/content/pm/IDataLoaderStatusListener.h> #include <android/os/incremental/BnIncrementalServiceConnector.h> #include <binder/IAppOpsCallback.h> @@ -160,6 +161,7 @@ private: DataLoaderStub(IncrementalService& service, MountId id, content::pm::DataLoaderParamsParcel&& params, content::pm::FileSystemControlParcel&& control, + incfs::UniqueControl&& healthControl, const DataLoaderStatusListener* externalListener); ~DataLoaderStub(); // Cleans up the internal state and invalidates DataLoaderStub. Any subsequent calls will @@ -178,6 +180,10 @@ private: private: binder::Status onStatusChanged(MountId mount, int newStatus) final; + void addToCmdLooperLocked(); + void removeFromCmdLooperLocked(); + int onCmdLooperEvent(); + bool isValid() const { return mId != kInvalidStorageId; } sp<content::pm::IDataLoader> getDataLoader(); @@ -197,12 +203,15 @@ private: MountId mId = kInvalidStorageId; content::pm::DataLoaderParamsParcel mParams; content::pm::FileSystemControlParcel mControl; + incfs::UniqueControl mHealthControl; DataLoaderStatusListener mListener; std::condition_variable mStatusCondition; int mCurrentStatus = content::pm::IDataLoaderStatusListener::DATA_LOADER_DESTROYED; int mTargetStatus = content::pm::IDataLoaderStatusListener::DATA_LOADER_DESTROYED; TimePoint mTargetStatusTs = {}; + + TimePoint mEarliestMissingPageTs{Clock::duration::max()}; }; using DataLoaderStubPtr = sp<DataLoaderStub>; @@ -300,12 +309,15 @@ private: const incfs::FileId& libFileId, std::string_view targetLibPath, Clock::time_point scheduledTs); + void runCmdLooper(); + private: const std::unique_ptr<VoldServiceWrapper> mVold; const std::unique_ptr<DataLoaderManagerWrapper> mDataLoaderManager; const std::unique_ptr<IncFsWrapper> mIncFs; const std::unique_ptr<AppOpsManagerWrapper> mAppOpsManager; const std::unique_ptr<JniWrapper> mJni; + const std::unique_ptr<LooperWrapper> mLooper; const std::string mIncrementalDir; mutable std::mutex mLock; @@ -319,13 +331,16 @@ private: std::atomic_bool mSystemReady = false; StorageId mNextId = 0; + std::atomic_bool mRunning{true}; + using Job = std::function<void()>; std::unordered_map<MountId, std::vector<Job>> mJobQueue; MountId mPendingJobsMount = kInvalidStorageId; std::condition_variable mJobCondition; std::mutex mJobMutex; std::thread mJobProcessor; - bool mRunning = true; + + std::thread mCmdLooperThread; }; } // namespace android::incremental diff --git a/services/incremental/ServiceWrappers.cpp b/services/incremental/ServiceWrappers.cpp index 85f744152ea4..08fb486c8058 100644 --- a/services/incremental/ServiceWrappers.cpp +++ b/services/incremental/ServiceWrappers.cpp @@ -113,6 +113,23 @@ private: JavaVM* const mJvm; }; +class RealLooperWrapper final : public LooperWrapper { +public: + int addFd(int fd, int ident, int events, android::Looper_callbackFunc callback, + void* data) final { + return mLooper.addFd(fd, ident, events, callback, data); + } + int removeFd(int fd) final { return mLooper.removeFd(fd); } + void wake() final { return mLooper.wake(); } + int pollAll(int timeoutMillis) final { return mLooper.pollAll(timeoutMillis); } + +private: + struct Looper : public android::Looper { + Looper() : android::Looper(/*allowNonCallbacks=*/false) {} + ~Looper() {} + } mLooper; +}; + class RealIncFs : public IncFsWrapper { public: RealIncFs() = default; @@ -203,6 +220,10 @@ std::unique_ptr<JniWrapper> RealServiceManager::getJni() { return std::make_unique<RealJniWrapper>(mJvm); } +std::unique_ptr<LooperWrapper> RealServiceManager::getLooper() { + return std::make_unique<RealLooperWrapper>(); +} + static JavaVM* getJavaVm(JNIEnv* env) { CHECK(env); JavaVM* jvm = nullptr; diff --git a/services/incremental/ServiceWrappers.h b/services/incremental/ServiceWrappers.h index 37928308b506..abbf2f4c4424 100644 --- a/services/incremental/ServiceWrappers.h +++ b/services/incremental/ServiceWrappers.h @@ -26,6 +26,7 @@ #include <binder/Status.h> #include <incfs.h> #include <jni.h> +#include <utils/Looper.h> #include <memory> #include <span> @@ -106,6 +107,16 @@ public: virtual void initializeForCurrentThread() const = 0; }; +class LooperWrapper { +public: + virtual ~LooperWrapper() = default; + virtual int addFd(int fd, int ident, int events, android::Looper_callbackFunc callback, + void* data) = 0; + virtual int removeFd(int fd) = 0; + virtual void wake() = 0; + virtual int pollAll(int timeoutMillis) = 0; +}; + class ServiceManagerWrapper { public: virtual ~ServiceManagerWrapper() = default; @@ -114,6 +125,7 @@ public: virtual std::unique_ptr<IncFsWrapper> getIncFs() = 0; virtual std::unique_ptr<AppOpsManagerWrapper> getAppOpsManager() = 0; virtual std::unique_ptr<JniWrapper> getJni() = 0; + virtual std::unique_ptr<LooperWrapper> getLooper() = 0; }; // --- Real stuff --- @@ -127,6 +139,7 @@ public: std::unique_ptr<IncFsWrapper> getIncFs() final; std::unique_ptr<AppOpsManagerWrapper> getAppOpsManager() final; std::unique_ptr<JniWrapper> getJni() final; + std::unique_ptr<LooperWrapper> getLooper() final; private: template <class INTERFACE> diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp index 2205bfed15d1..325218dfa6a5 100644 --- a/services/incremental/test/IncrementalServiceTest.cpp +++ b/services/incremental/test/IncrementalServiceTest.cpp @@ -242,6 +242,9 @@ public: void setDataLoaderStatusDestroyed() { mListener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_DESTROYED); } + void setDataLoaderStatusUnavailable() { + mListener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_UNAVAILABLE); + } binder::Status unbindFromDataLoaderOk(int32_t id) { if (mDataLoader) { if (auto status = mDataLoader->destroy(id); !status.isOk()) { @@ -286,6 +289,14 @@ public: void makeFileFails() { ON_CALL(*this, makeFile(_, _, _, _, _)).WillByDefault(Return(-1)); } void makeFileSuccess() { ON_CALL(*this, makeFile(_, _, _, _, _)).WillByDefault(Return(0)); } + void openMountSuccess() { + ON_CALL(*this, openMount(_)).WillByDefault(Invoke(this, &MockIncFs::openMountForHealth)); + } + + static constexpr auto kPendingReadsFd = 42; + Control openMountForHealth(std::string_view) { + return UniqueControl(IncFs_CreateControl(-1, kPendingReadsFd, -1)); + } RawMetadata getMountInfoMetadata(const Control& control, std::string_view path) { metadata::Mount m; @@ -346,7 +357,42 @@ class MockJniWrapper : public JniWrapper { public: MOCK_CONST_METHOD0(initializeForCurrentThread, void()); - MockJniWrapper() { EXPECT_CALL(*this, initializeForCurrentThread()).Times(1); } + MockJniWrapper() { EXPECT_CALL(*this, initializeForCurrentThread()).Times(2); } +}; + +class MockLooperWrapper : public LooperWrapper { +public: + MOCK_METHOD5(addFd, int(int, int, int, android::Looper_callbackFunc, void*)); + MOCK_METHOD1(removeFd, int(int)); + MOCK_METHOD0(wake, void()); + MOCK_METHOD1(pollAll, int(int)); + + MockLooperWrapper() { + ON_CALL(*this, addFd(_, _, _, _, _)) + .WillByDefault(Invoke(this, &MockLooperWrapper::storeCallback)); + ON_CALL(*this, removeFd(_)).WillByDefault(Invoke(this, &MockLooperWrapper::clearCallback)); + ON_CALL(*this, pollAll(_)).WillByDefault(Invoke(this, &MockLooperWrapper::sleepFor)); + } + + int storeCallback(int, int, int, android::Looper_callbackFunc callback, void* data) { + mCallback = callback; + mCallbackData = data; + return 0; + } + + int clearCallback(int) { + mCallback = nullptr; + mCallbackData = nullptr; + return 0; + } + + int sleepFor(int timeoutMillis) { + std::this_thread::sleep_for(std::chrono::milliseconds(timeoutMillis)); + return 0; + } + + android::Looper_callbackFunc mCallback = nullptr; + void* mCallbackData = nullptr; }; class MockServiceManager : public ServiceManagerWrapper { @@ -355,12 +401,14 @@ public: std::unique_ptr<MockDataLoaderManager> dataLoaderManager, std::unique_ptr<MockIncFs> incfs, std::unique_ptr<MockAppOpsManager> appOpsManager, - std::unique_ptr<MockJniWrapper> jni) + std::unique_ptr<MockJniWrapper> jni, + std::unique_ptr<MockLooperWrapper> looper) : mVold(std::move(vold)), mDataLoaderManager(std::move(dataLoaderManager)), mIncFs(std::move(incfs)), mAppOpsManager(std::move(appOpsManager)), - mJni(std::move(jni)) {} + mJni(std::move(jni)), + mLooper(std::move(looper)) {} std::unique_ptr<VoldServiceWrapper> getVoldService() final { return std::move(mVold); } std::unique_ptr<DataLoaderManagerWrapper> getDataLoaderManager() final { return std::move(mDataLoaderManager); @@ -368,6 +416,7 @@ public: std::unique_ptr<IncFsWrapper> getIncFs() final { return std::move(mIncFs); } std::unique_ptr<AppOpsManagerWrapper> getAppOpsManager() final { return std::move(mAppOpsManager); } std::unique_ptr<JniWrapper> getJni() final { return std::move(mJni); } + std::unique_ptr<LooperWrapper> getLooper() final { return std::move(mLooper); } private: std::unique_ptr<MockVoldService> mVold; @@ -375,6 +424,7 @@ private: std::unique_ptr<MockIncFs> mIncFs; std::unique_ptr<MockAppOpsManager> mAppOpsManager; std::unique_ptr<MockJniWrapper> mJni; + std::unique_ptr<MockLooperWrapper> mLooper; }; // --- IncrementalServiceTest --- @@ -394,13 +444,16 @@ public: mAppOpsManager = appOps.get(); auto jni = std::make_unique<NiceMock<MockJniWrapper>>(); mJni = jni.get(); + auto looper = std::make_unique<NiceMock<MockLooperWrapper>>(); + mLooper = looper.get(); mIncrementalService = std::make_unique<IncrementalService>(MockServiceManager(std::move(vold), std::move( dataloaderManager), std::move(incFs), std::move(appOps), - std::move(jni)), + std::move(jni), + std::move(looper)), mRootDir.path); mDataLoaderParcel.packageName = "com.test"; mDataLoaderParcel.arguments = "uri"; @@ -430,12 +483,13 @@ public: } protected: - NiceMock<MockVoldService>* mVold; - NiceMock<MockIncFs>* mIncFs; - NiceMock<MockDataLoaderManager>* mDataLoaderManager; - NiceMock<MockAppOpsManager>* mAppOpsManager; - NiceMock<MockJniWrapper>* mJni; - NiceMock<MockDataLoader>* mDataLoader; + NiceMock<MockVoldService>* mVold = nullptr; + NiceMock<MockIncFs>* mIncFs = nullptr; + NiceMock<MockDataLoaderManager>* mDataLoaderManager = nullptr; + NiceMock<MockAppOpsManager>* mAppOpsManager = nullptr; + NiceMock<MockJniWrapper>* mJni = nullptr; + NiceMock<MockLooperWrapper>* mLooper = nullptr; + NiceMock<MockDataLoader>* mDataLoader = nullptr; std::unique_ptr<IncrementalService> mIncrementalService; TemporaryDir mRootDir; DataLoaderParamsParcel mDataLoaderParcel; @@ -593,6 +647,54 @@ TEST_F(IncrementalServiceTest, testStartDataLoaderPendingStart) { mDataLoaderManager->setDataLoaderStatusCreated(); } +TEST_F(IncrementalServiceTest, testStartDataLoaderCreateUnavailable) { + mVold->mountIncFsSuccess(); + mIncFs->makeFileSuccess(); + mVold->bindMountSuccess(); + mDataLoader->initializeCreateOkNoStatus(); + mDataLoaderManager->bindToDataLoaderSuccess(); + mDataLoaderManager->getDataLoaderSuccess(); + EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(1); + EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(1); + EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(1); + EXPECT_CALL(*mDataLoader, start(_)).Times(0); + EXPECT_CALL(*mDataLoader, destroy(_)).Times(1); + EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2); + TemporaryDir tempDir; + int storageId = + mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, + IncrementalService::CreateOptions::CreateNew); + ASSERT_GE(storageId, 0); + mDataLoaderManager->setDataLoaderStatusUnavailable(); +} + +TEST_F(IncrementalServiceTest, testStartDataLoaderRecreateOnPendingReads) { + mVold->mountIncFsSuccess(); + mIncFs->makeFileSuccess(); + mIncFs->openMountSuccess(); + mVold->bindMountSuccess(); + mDataLoader->initializeCreateOkNoStatus(); + mDataLoaderManager->bindToDataLoaderSuccess(); + mDataLoaderManager->getDataLoaderSuccess(); + EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(2); + EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(1); + EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(2); + EXPECT_CALL(*mDataLoader, start(_)).Times(0); + EXPECT_CALL(*mDataLoader, destroy(_)).Times(1); + EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2); + EXPECT_CALL(*mLooper, addFd(MockIncFs::kPendingReadsFd, _, _, _, _)).Times(1); + EXPECT_CALL(*mLooper, removeFd(MockIncFs::kPendingReadsFd)).Times(1); + TemporaryDir tempDir; + int storageId = + mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, + IncrementalService::CreateOptions::CreateNew); + ASSERT_GE(storageId, 0); + mDataLoaderManager->setDataLoaderStatusUnavailable(); + ASSERT_NE(nullptr, mLooper->mCallback); + ASSERT_NE(nullptr, mLooper->mCallbackData); + mLooper->mCallback(-1, -1, mLooper->mCallbackData); +} + TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccess) { mVold->mountIncFsSuccess(); mIncFs->makeFileSuccess(); |