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()),
|
mIncFs(sm.getIncFs()),
|
||||||
mAppOpsManager(sm.getAppOpsManager()),
|
mAppOpsManager(sm.getAppOpsManager()),
|
||||||
mJni(sm.getJni()),
|
mJni(sm.getJni()),
|
||||||
|
mLooper(sm.getLooper()),
|
||||||
mIncrementalDir(rootDir) {
|
mIncrementalDir(rootDir) {
|
||||||
if (!mVold) {
|
if (!mVold) {
|
||||||
LOG(FATAL) << "Vold service is unavailable";
|
LOG(FATAL) << "Vold service is unavailable";
|
||||||
@@ -276,12 +277,22 @@ IncrementalService::IncrementalService(ServiceManagerWrapper&& sm, std::string_v
|
|||||||
if (!mAppOpsManager) {
|
if (!mAppOpsManager) {
|
||||||
LOG(FATAL) << "AppOpsManager is unavailable";
|
LOG(FATAL) << "AppOpsManager is unavailable";
|
||||||
}
|
}
|
||||||
|
if (!mJni) {
|
||||||
|
LOG(FATAL) << "JNI is unavailable";
|
||||||
|
}
|
||||||
|
if (!mLooper) {
|
||||||
|
LOG(FATAL) << "Looper is unavailable";
|
||||||
|
}
|
||||||
|
|
||||||
mJobQueue.reserve(16);
|
mJobQueue.reserve(16);
|
||||||
mJobProcessor = std::thread([this]() {
|
mJobProcessor = std::thread([this]() {
|
||||||
mJni->initializeForCurrentThread();
|
mJni->initializeForCurrentThread();
|
||||||
runJobProcessing();
|
runJobProcessing();
|
||||||
});
|
});
|
||||||
|
mCmdLooperThread = std::thread([this]() {
|
||||||
|
mJni->initializeForCurrentThread();
|
||||||
|
runCmdLooper();
|
||||||
|
});
|
||||||
|
|
||||||
const auto mountedRootNames = adoptMountedInstances();
|
const auto mountedRootNames = adoptMountedInstances();
|
||||||
mountExistingImages(mountedRootNames);
|
mountExistingImages(mountedRootNames);
|
||||||
@@ -294,6 +305,7 @@ IncrementalService::~IncrementalService() {
|
|||||||
}
|
}
|
||||||
mJobCondition.notify_all();
|
mJobCondition.notify_all();
|
||||||
mJobProcessor.join();
|
mJobProcessor.join();
|
||||||
|
mCmdLooperThread.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char* toString(IncrementalService::BindKind kind) {
|
static const char* toString(IncrementalService::BindKind kind) {
|
||||||
@@ -1315,6 +1327,13 @@ bool IncrementalService::mountExistingImage(std::string_view root) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IncrementalService::runCmdLooper() {
|
||||||
|
constexpr auto kTimeoutMsecs = 1000;
|
||||||
|
while (mRunning.load(std::memory_order_relaxed)) {
|
||||||
|
mLooper->pollAll(kTimeoutMsecs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
IncrementalService::DataLoaderStubPtr IncrementalService::prepareDataLoader(
|
IncrementalService::DataLoaderStubPtr IncrementalService::prepareDataLoader(
|
||||||
IncFsMount& ifs, DataLoaderParamsParcel&& params,
|
IncFsMount& ifs, DataLoaderParamsParcel&& params,
|
||||||
const DataLoaderStatusListener* externalListener) {
|
const DataLoaderStatusListener* externalListener) {
|
||||||
@@ -1337,8 +1356,16 @@ void IncrementalService::prepareDataLoaderLocked(IncFsMount& ifs, DataLoaderPara
|
|||||||
fsControlParcel.incremental->log.reset(dup(ifs.control.logs()));
|
fsControlParcel.incremental->log.reset(dup(ifs.control.logs()));
|
||||||
fsControlParcel.service = new IncrementalServiceConnector(*this, ifs.mountId);
|
fsControlParcel.service = new IncrementalServiceConnector(*this, ifs.mountId);
|
||||||
|
|
||||||
ifs.dataLoaderStub = new DataLoaderStub(*this, ifs.mountId, std::move(params),
|
incfs::UniqueControl healthControl = mIncFs->openMount(ifs.root.c_str());
|
||||||
std::move(fsControlParcel), externalListener);
|
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>
|
template <class Duration>
|
||||||
@@ -1658,24 +1685,34 @@ void IncrementalService::onAppOpChanged(const std::string& packageName) {
|
|||||||
IncrementalService::DataLoaderStub::DataLoaderStub(IncrementalService& service, MountId id,
|
IncrementalService::DataLoaderStub::DataLoaderStub(IncrementalService& service, MountId id,
|
||||||
DataLoaderParamsParcel&& params,
|
DataLoaderParamsParcel&& params,
|
||||||
FileSystemControlParcel&& control,
|
FileSystemControlParcel&& control,
|
||||||
|
incfs::UniqueControl&& healthControl,
|
||||||
const DataLoaderStatusListener* externalListener)
|
const DataLoaderStatusListener* externalListener)
|
||||||
: mService(service),
|
: mService(service),
|
||||||
mId(id),
|
mId(id),
|
||||||
mParams(std::move(params)),
|
mParams(std::move(params)),
|
||||||
mControl(std::move(control)),
|
mControl(std::move(control)),
|
||||||
|
mHealthControl(std::move(healthControl)),
|
||||||
mListener(externalListener ? *externalListener : DataLoaderStatusListener()) {
|
mListener(externalListener ? *externalListener : DataLoaderStatusListener()) {
|
||||||
|
addToCmdLooperLocked();
|
||||||
}
|
}
|
||||||
|
|
||||||
IncrementalService::DataLoaderStub::~DataLoaderStub() = default;
|
IncrementalService::DataLoaderStub::~DataLoaderStub() {
|
||||||
|
if (mId != kInvalidStorageId) {
|
||||||
|
cleanupResources();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void IncrementalService::DataLoaderStub::cleanupResources() {
|
void IncrementalService::DataLoaderStub::cleanupResources() {
|
||||||
requestDestroy();
|
requestDestroy();
|
||||||
|
|
||||||
auto now = Clock::now();
|
auto now = Clock::now();
|
||||||
|
|
||||||
std::unique_lock lock(mMutex);
|
std::unique_lock lock(mMutex);
|
||||||
|
|
||||||
|
removeFromCmdLooperLocked();
|
||||||
|
|
||||||
mParams = {};
|
mParams = {};
|
||||||
mControl = {};
|
mControl = {};
|
||||||
|
mHealthControl = {};
|
||||||
mStatusCondition.wait_until(lock, now + 60s, [this] {
|
mStatusCondition.wait_until(lock, now + 60s, [this] {
|
||||||
return mCurrentStatus == IDataLoaderStatusListener::DATA_LOADER_DESTROYED;
|
return mCurrentStatus == IDataLoaderStatusListener::DATA_LOADER_DESTROYED;
|
||||||
});
|
});
|
||||||
@@ -1710,21 +1747,19 @@ bool IncrementalService::DataLoaderStub::requestDestroy() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool IncrementalService::DataLoaderStub::setTargetStatus(int newStatus) {
|
bool IncrementalService::DataLoaderStub::setTargetStatus(int newStatus) {
|
||||||
int oldStatus, curStatus;
|
|
||||||
{
|
{
|
||||||
std::unique_lock lock(mMutex);
|
std::unique_lock lock(mMutex);
|
||||||
oldStatus = mTargetStatus;
|
|
||||||
curStatus = mCurrentStatus;
|
|
||||||
setTargetStatusLocked(newStatus);
|
setTargetStatusLocked(newStatus);
|
||||||
}
|
}
|
||||||
LOG(DEBUG) << "Target status update for DataLoader " << mId << ": " << oldStatus << " -> "
|
|
||||||
<< newStatus << " (current " << curStatus << ")";
|
|
||||||
return fsmStep();
|
return fsmStep();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IncrementalService::DataLoaderStub::setTargetStatusLocked(int status) {
|
void IncrementalService::DataLoaderStub::setTargetStatusLocked(int status) {
|
||||||
|
auto oldStatus = mTargetStatus;
|
||||||
mTargetStatus = status;
|
mTargetStatus = status;
|
||||||
mTargetStatusTs = Clock::now();
|
mTargetStatusTs = Clock::now();
|
||||||
|
LOG(DEBUG) << "Target status update for DataLoader " << mId << ": " << oldStatus << " -> "
|
||||||
|
<< status << " (current " << mCurrentStatus << ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IncrementalService::DataLoaderStub::bind() {
|
bool IncrementalService::DataLoaderStub::bind() {
|
||||||
@@ -1860,12 +1895,75 @@ binder::Status IncrementalService::DataLoaderStub::onStatusChanged(MountId mount
|
|||||||
return binder::Status::ok();
|
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) {
|
void IncrementalService::DataLoaderStub::onDump(int fd) {
|
||||||
dprintf(fd, " dataLoader: {\n");
|
dprintf(fd, " dataLoader: {\n");
|
||||||
dprintf(fd, " currentStatus: %d\n", mCurrentStatus);
|
dprintf(fd, " currentStatus: %d\n", mCurrentStatus);
|
||||||
dprintf(fd, " targetStatus: %d\n", mTargetStatus);
|
dprintf(fd, " targetStatus: %d\n", mTargetStatus);
|
||||||
dprintf(fd, " targetStatusTs: %lldmcs\n",
|
dprintf(fd, " targetStatusTs: %lldmcs\n",
|
||||||
(long long)(elapsedMcs(mTargetStatusTs, Clock::now())));
|
(long long)(elapsedMcs(mTargetStatusTs, Clock::now())));
|
||||||
|
dprintf(fd, " earliestMissingPageTs: %lldmcs\n",
|
||||||
|
(long long)(elapsedMcs(mEarliestMissingPageTs, Clock::now())));
|
||||||
const auto& params = mParams;
|
const auto& params = mParams;
|
||||||
dprintf(fd, " dataLoaderParams: {\n");
|
dprintf(fd, " dataLoaderParams: {\n");
|
||||||
dprintf(fd, " type: %s\n", toString(params.type).c_str());
|
dprintf(fd, " type: %s\n", toString(params.type).c_str());
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include <android/content/pm/BnDataLoaderStatusListener.h>
|
#include <android/content/pm/BnDataLoaderStatusListener.h>
|
||||||
#include <android/content/pm/DataLoaderParamsParcel.h>
|
#include <android/content/pm/DataLoaderParamsParcel.h>
|
||||||
|
#include <android/content/pm/FileSystemControlParcel.h>
|
||||||
#include <android/content/pm/IDataLoaderStatusListener.h>
|
#include <android/content/pm/IDataLoaderStatusListener.h>
|
||||||
#include <android/os/incremental/BnIncrementalServiceConnector.h>
|
#include <android/os/incremental/BnIncrementalServiceConnector.h>
|
||||||
#include <binder/IAppOpsCallback.h>
|
#include <binder/IAppOpsCallback.h>
|
||||||
@@ -160,6 +161,7 @@ private:
|
|||||||
DataLoaderStub(IncrementalService& service, MountId id,
|
DataLoaderStub(IncrementalService& service, MountId id,
|
||||||
content::pm::DataLoaderParamsParcel&& params,
|
content::pm::DataLoaderParamsParcel&& params,
|
||||||
content::pm::FileSystemControlParcel&& control,
|
content::pm::FileSystemControlParcel&& control,
|
||||||
|
incfs::UniqueControl&& healthControl,
|
||||||
const DataLoaderStatusListener* externalListener);
|
const DataLoaderStatusListener* externalListener);
|
||||||
~DataLoaderStub();
|
~DataLoaderStub();
|
||||||
// Cleans up the internal state and invalidates DataLoaderStub. Any subsequent calls will
|
// Cleans up the internal state and invalidates DataLoaderStub. Any subsequent calls will
|
||||||
@@ -178,6 +180,10 @@ private:
|
|||||||
private:
|
private:
|
||||||
binder::Status onStatusChanged(MountId mount, int newStatus) final;
|
binder::Status onStatusChanged(MountId mount, int newStatus) final;
|
||||||
|
|
||||||
|
void addToCmdLooperLocked();
|
||||||
|
void removeFromCmdLooperLocked();
|
||||||
|
int onCmdLooperEvent();
|
||||||
|
|
||||||
bool isValid() const { return mId != kInvalidStorageId; }
|
bool isValid() const { return mId != kInvalidStorageId; }
|
||||||
sp<content::pm::IDataLoader> getDataLoader();
|
sp<content::pm::IDataLoader> getDataLoader();
|
||||||
|
|
||||||
@@ -197,12 +203,15 @@ private:
|
|||||||
MountId mId = kInvalidStorageId;
|
MountId mId = kInvalidStorageId;
|
||||||
content::pm::DataLoaderParamsParcel mParams;
|
content::pm::DataLoaderParamsParcel mParams;
|
||||||
content::pm::FileSystemControlParcel mControl;
|
content::pm::FileSystemControlParcel mControl;
|
||||||
|
incfs::UniqueControl mHealthControl;
|
||||||
DataLoaderStatusListener mListener;
|
DataLoaderStatusListener mListener;
|
||||||
|
|
||||||
std::condition_variable mStatusCondition;
|
std::condition_variable mStatusCondition;
|
||||||
int mCurrentStatus = content::pm::IDataLoaderStatusListener::DATA_LOADER_DESTROYED;
|
int mCurrentStatus = content::pm::IDataLoaderStatusListener::DATA_LOADER_DESTROYED;
|
||||||
int mTargetStatus = content::pm::IDataLoaderStatusListener::DATA_LOADER_DESTROYED;
|
int mTargetStatus = content::pm::IDataLoaderStatusListener::DATA_LOADER_DESTROYED;
|
||||||
TimePoint mTargetStatusTs = {};
|
TimePoint mTargetStatusTs = {};
|
||||||
|
|
||||||
|
TimePoint mEarliestMissingPageTs{Clock::duration::max()};
|
||||||
};
|
};
|
||||||
using DataLoaderStubPtr = sp<DataLoaderStub>;
|
using DataLoaderStubPtr = sp<DataLoaderStub>;
|
||||||
|
|
||||||
@@ -300,12 +309,15 @@ private:
|
|||||||
const incfs::FileId& libFileId, std::string_view targetLibPath,
|
const incfs::FileId& libFileId, std::string_view targetLibPath,
|
||||||
Clock::time_point scheduledTs);
|
Clock::time_point scheduledTs);
|
||||||
|
|
||||||
|
void runCmdLooper();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const std::unique_ptr<VoldServiceWrapper> mVold;
|
const std::unique_ptr<VoldServiceWrapper> mVold;
|
||||||
const std::unique_ptr<DataLoaderManagerWrapper> mDataLoaderManager;
|
const std::unique_ptr<DataLoaderManagerWrapper> mDataLoaderManager;
|
||||||
const std::unique_ptr<IncFsWrapper> mIncFs;
|
const std::unique_ptr<IncFsWrapper> mIncFs;
|
||||||
const std::unique_ptr<AppOpsManagerWrapper> mAppOpsManager;
|
const std::unique_ptr<AppOpsManagerWrapper> mAppOpsManager;
|
||||||
const std::unique_ptr<JniWrapper> mJni;
|
const std::unique_ptr<JniWrapper> mJni;
|
||||||
|
const std::unique_ptr<LooperWrapper> mLooper;
|
||||||
const std::string mIncrementalDir;
|
const std::string mIncrementalDir;
|
||||||
|
|
||||||
mutable std::mutex mLock;
|
mutable std::mutex mLock;
|
||||||
@@ -319,13 +331,16 @@ private:
|
|||||||
std::atomic_bool mSystemReady = false;
|
std::atomic_bool mSystemReady = false;
|
||||||
StorageId mNextId = 0;
|
StorageId mNextId = 0;
|
||||||
|
|
||||||
|
std::atomic_bool mRunning{true};
|
||||||
|
|
||||||
using Job = std::function<void()>;
|
using Job = std::function<void()>;
|
||||||
std::unordered_map<MountId, std::vector<Job>> mJobQueue;
|
std::unordered_map<MountId, std::vector<Job>> mJobQueue;
|
||||||
MountId mPendingJobsMount = kInvalidStorageId;
|
MountId mPendingJobsMount = kInvalidStorageId;
|
||||||
std::condition_variable mJobCondition;
|
std::condition_variable mJobCondition;
|
||||||
std::mutex mJobMutex;
|
std::mutex mJobMutex;
|
||||||
std::thread mJobProcessor;
|
std::thread mJobProcessor;
|
||||||
bool mRunning = true;
|
|
||||||
|
std::thread mCmdLooperThread;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace android::incremental
|
} // namespace android::incremental
|
||||||
|
|||||||
@@ -113,6 +113,23 @@ private:
|
|||||||
JavaVM* const mJvm;
|
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 {
|
class RealIncFs : public IncFsWrapper {
|
||||||
public:
|
public:
|
||||||
RealIncFs() = default;
|
RealIncFs() = default;
|
||||||
@@ -203,6 +220,10 @@ std::unique_ptr<JniWrapper> RealServiceManager::getJni() {
|
|||||||
return std::make_unique<RealJniWrapper>(mJvm);
|
return std::make_unique<RealJniWrapper>(mJvm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<LooperWrapper> RealServiceManager::getLooper() {
|
||||||
|
return std::make_unique<RealLooperWrapper>();
|
||||||
|
}
|
||||||
|
|
||||||
static JavaVM* getJavaVm(JNIEnv* env) {
|
static JavaVM* getJavaVm(JNIEnv* env) {
|
||||||
CHECK(env);
|
CHECK(env);
|
||||||
JavaVM* jvm = nullptr;
|
JavaVM* jvm = nullptr;
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
#include <binder/Status.h>
|
#include <binder/Status.h>
|
||||||
#include <incfs.h>
|
#include <incfs.h>
|
||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
|
#include <utils/Looper.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <span>
|
#include <span>
|
||||||
@@ -106,6 +107,16 @@ public:
|
|||||||
virtual void initializeForCurrentThread() const = 0;
|
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 {
|
class ServiceManagerWrapper {
|
||||||
public:
|
public:
|
||||||
virtual ~ServiceManagerWrapper() = default;
|
virtual ~ServiceManagerWrapper() = default;
|
||||||
@@ -114,6 +125,7 @@ public:
|
|||||||
virtual std::unique_ptr<IncFsWrapper> getIncFs() = 0;
|
virtual std::unique_ptr<IncFsWrapper> getIncFs() = 0;
|
||||||
virtual std::unique_ptr<AppOpsManagerWrapper> getAppOpsManager() = 0;
|
virtual std::unique_ptr<AppOpsManagerWrapper> getAppOpsManager() = 0;
|
||||||
virtual std::unique_ptr<JniWrapper> getJni() = 0;
|
virtual std::unique_ptr<JniWrapper> getJni() = 0;
|
||||||
|
virtual std::unique_ptr<LooperWrapper> getLooper() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Real stuff ---
|
// --- Real stuff ---
|
||||||
@@ -127,6 +139,7 @@ public:
|
|||||||
std::unique_ptr<IncFsWrapper> getIncFs() final;
|
std::unique_ptr<IncFsWrapper> getIncFs() final;
|
||||||
std::unique_ptr<AppOpsManagerWrapper> getAppOpsManager() final;
|
std::unique_ptr<AppOpsManagerWrapper> getAppOpsManager() final;
|
||||||
std::unique_ptr<JniWrapper> getJni() final;
|
std::unique_ptr<JniWrapper> getJni() final;
|
||||||
|
std::unique_ptr<LooperWrapper> getLooper() final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <class INTERFACE>
|
template <class INTERFACE>
|
||||||
|
|||||||
@@ -242,6 +242,9 @@ public:
|
|||||||
void setDataLoaderStatusDestroyed() {
|
void setDataLoaderStatusDestroyed() {
|
||||||
mListener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_DESTROYED);
|
mListener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_DESTROYED);
|
||||||
}
|
}
|
||||||
|
void setDataLoaderStatusUnavailable() {
|
||||||
|
mListener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_UNAVAILABLE);
|
||||||
|
}
|
||||||
binder::Status unbindFromDataLoaderOk(int32_t id) {
|
binder::Status unbindFromDataLoaderOk(int32_t id) {
|
||||||
if (mDataLoader) {
|
if (mDataLoader) {
|
||||||
if (auto status = mDataLoader->destroy(id); !status.isOk()) {
|
if (auto status = mDataLoader->destroy(id); !status.isOk()) {
|
||||||
@@ -286,6 +289,14 @@ public:
|
|||||||
|
|
||||||
void makeFileFails() { ON_CALL(*this, makeFile(_, _, _, _, _)).WillByDefault(Return(-1)); }
|
void makeFileFails() { ON_CALL(*this, makeFile(_, _, _, _, _)).WillByDefault(Return(-1)); }
|
||||||
void makeFileSuccess() { ON_CALL(*this, makeFile(_, _, _, _, _)).WillByDefault(Return(0)); }
|
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) {
|
RawMetadata getMountInfoMetadata(const Control& control, std::string_view path) {
|
||||||
metadata::Mount m;
|
metadata::Mount m;
|
||||||
@@ -346,7 +357,42 @@ class MockJniWrapper : public JniWrapper {
|
|||||||
public:
|
public:
|
||||||
MOCK_CONST_METHOD0(initializeForCurrentThread, void());
|
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 {
|
class MockServiceManager : public ServiceManagerWrapper {
|
||||||
@@ -355,12 +401,14 @@ public:
|
|||||||
std::unique_ptr<MockDataLoaderManager> dataLoaderManager,
|
std::unique_ptr<MockDataLoaderManager> dataLoaderManager,
|
||||||
std::unique_ptr<MockIncFs> incfs,
|
std::unique_ptr<MockIncFs> incfs,
|
||||||
std::unique_ptr<MockAppOpsManager> appOpsManager,
|
std::unique_ptr<MockAppOpsManager> appOpsManager,
|
||||||
std::unique_ptr<MockJniWrapper> jni)
|
std::unique_ptr<MockJniWrapper> jni,
|
||||||
|
std::unique_ptr<MockLooperWrapper> looper)
|
||||||
: mVold(std::move(vold)),
|
: mVold(std::move(vold)),
|
||||||
mDataLoaderManager(std::move(dataLoaderManager)),
|
mDataLoaderManager(std::move(dataLoaderManager)),
|
||||||
mIncFs(std::move(incfs)),
|
mIncFs(std::move(incfs)),
|
||||||
mAppOpsManager(std::move(appOpsManager)),
|
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<VoldServiceWrapper> getVoldService() final { return std::move(mVold); }
|
||||||
std::unique_ptr<DataLoaderManagerWrapper> getDataLoaderManager() final {
|
std::unique_ptr<DataLoaderManagerWrapper> getDataLoaderManager() final {
|
||||||
return std::move(mDataLoaderManager);
|
return std::move(mDataLoaderManager);
|
||||||
@@ -368,6 +416,7 @@ public:
|
|||||||
std::unique_ptr<IncFsWrapper> getIncFs() final { return std::move(mIncFs); }
|
std::unique_ptr<IncFsWrapper> getIncFs() final { return std::move(mIncFs); }
|
||||||
std::unique_ptr<AppOpsManagerWrapper> getAppOpsManager() final { return std::move(mAppOpsManager); }
|
std::unique_ptr<AppOpsManagerWrapper> getAppOpsManager() final { return std::move(mAppOpsManager); }
|
||||||
std::unique_ptr<JniWrapper> getJni() final { return std::move(mJni); }
|
std::unique_ptr<JniWrapper> getJni() final { return std::move(mJni); }
|
||||||
|
std::unique_ptr<LooperWrapper> getLooper() final { return std::move(mLooper); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<MockVoldService> mVold;
|
std::unique_ptr<MockVoldService> mVold;
|
||||||
@@ -375,6 +424,7 @@ private:
|
|||||||
std::unique_ptr<MockIncFs> mIncFs;
|
std::unique_ptr<MockIncFs> mIncFs;
|
||||||
std::unique_ptr<MockAppOpsManager> mAppOpsManager;
|
std::unique_ptr<MockAppOpsManager> mAppOpsManager;
|
||||||
std::unique_ptr<MockJniWrapper> mJni;
|
std::unique_ptr<MockJniWrapper> mJni;
|
||||||
|
std::unique_ptr<MockLooperWrapper> mLooper;
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- IncrementalServiceTest ---
|
// --- IncrementalServiceTest ---
|
||||||
@@ -394,13 +444,16 @@ public:
|
|||||||
mAppOpsManager = appOps.get();
|
mAppOpsManager = appOps.get();
|
||||||
auto jni = std::make_unique<NiceMock<MockJniWrapper>>();
|
auto jni = std::make_unique<NiceMock<MockJniWrapper>>();
|
||||||
mJni = jni.get();
|
mJni = jni.get();
|
||||||
|
auto looper = std::make_unique<NiceMock<MockLooperWrapper>>();
|
||||||
|
mLooper = looper.get();
|
||||||
mIncrementalService =
|
mIncrementalService =
|
||||||
std::make_unique<IncrementalService>(MockServiceManager(std::move(vold),
|
std::make_unique<IncrementalService>(MockServiceManager(std::move(vold),
|
||||||
std::move(
|
std::move(
|
||||||
dataloaderManager),
|
dataloaderManager),
|
||||||
std::move(incFs),
|
std::move(incFs),
|
||||||
std::move(appOps),
|
std::move(appOps),
|
||||||
std::move(jni)),
|
std::move(jni),
|
||||||
|
std::move(looper)),
|
||||||
mRootDir.path);
|
mRootDir.path);
|
||||||
mDataLoaderParcel.packageName = "com.test";
|
mDataLoaderParcel.packageName = "com.test";
|
||||||
mDataLoaderParcel.arguments = "uri";
|
mDataLoaderParcel.arguments = "uri";
|
||||||
@@ -430,12 +483,13 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
NiceMock<MockVoldService>* mVold;
|
NiceMock<MockVoldService>* mVold = nullptr;
|
||||||
NiceMock<MockIncFs>* mIncFs;
|
NiceMock<MockIncFs>* mIncFs = nullptr;
|
||||||
NiceMock<MockDataLoaderManager>* mDataLoaderManager;
|
NiceMock<MockDataLoaderManager>* mDataLoaderManager = nullptr;
|
||||||
NiceMock<MockAppOpsManager>* mAppOpsManager;
|
NiceMock<MockAppOpsManager>* mAppOpsManager = nullptr;
|
||||||
NiceMock<MockJniWrapper>* mJni;
|
NiceMock<MockJniWrapper>* mJni = nullptr;
|
||||||
NiceMock<MockDataLoader>* mDataLoader;
|
NiceMock<MockLooperWrapper>* mLooper = nullptr;
|
||||||
|
NiceMock<MockDataLoader>* mDataLoader = nullptr;
|
||||||
std::unique_ptr<IncrementalService> mIncrementalService;
|
std::unique_ptr<IncrementalService> mIncrementalService;
|
||||||
TemporaryDir mRootDir;
|
TemporaryDir mRootDir;
|
||||||
DataLoaderParamsParcel mDataLoaderParcel;
|
DataLoaderParamsParcel mDataLoaderParcel;
|
||||||
@@ -593,6 +647,54 @@ TEST_F(IncrementalServiceTest, testStartDataLoaderPendingStart) {
|
|||||||
mDataLoaderManager->setDataLoaderStatusCreated();
|
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) {
|
TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccess) {
|
||||||
mVold->mountIncFsSuccess();
|
mVold->mountIncFsSuccess();
|
||||||
mIncFs->makeFileSuccess();
|
mIncFs->makeFileSuccess();
|
||||||
|
|||||||
Reference in New Issue
Block a user