Merge "Lifecycle: detecting pending reads." into rvc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
d59d694f11
@@ -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());
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user