DataLoader lifecycle.
- mark disconnected DataLoaders as non-existent (destroyed),
- remove storage destroy on DataLoader destroy,
- more robust destroy on destruct handling,
- less race-conditions.
Bug: b/153874006
Test: atest PackageManagerShellCommandTest PackageManagerShellCommandIncrementalTest IncrementalServiceTest
Change-Id: Ib77302aac546d66ce40c5345417c7b424a1d601b
diff --git a/services/core/java/com/android/server/pm/DataLoaderManagerService.java b/services/core/java/com/android/server/pm/DataLoaderManagerService.java
index 09baf6e..ae9c384 100644
--- a/services/core/java/com/android/server/pm/DataLoaderManagerService.java
+++ b/services/core/java/com/android/server/pm/DataLoaderManagerService.java
@@ -204,6 +204,12 @@
@Override
public void onServiceDisconnected(ComponentName arg0) {
+ if (mListener != null) {
+ try {
+ mListener.onStatusChanged(mId, IDataLoaderStatusListener.DATA_LOADER_DESTROYED);
+ } catch (RemoteException ignored) {
+ }
+ }
remove();
}
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index 149dfa6..8d084cd 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -258,10 +258,6 @@
mountExistingImages();
}
-FileId IncrementalService::idFromMetadata(std::span<const uint8_t> metadata) {
- return IncFs_FileIdFromMetadata({(const char*)metadata.data(), metadata.size()});
-}
-
IncrementalService::~IncrementalService() {
{
std::lock_guard lock(mJobMutex);
@@ -1016,7 +1012,7 @@
return false;
}
}
- return dataLoaderStub->start();
+ return dataLoaderStub->requestStart();
}
void IncrementalService::mountExistingImages() {
@@ -1475,12 +1471,15 @@
}
IncrementalService::DataLoaderStub::~DataLoaderStub() {
- CHECK(mStatus == -1 || mStatus == IDataLoaderStatusListener::DATA_LOADER_DESTROYED)
- << "Dataloader has to be destroyed prior to destructor: " << mId
- << ", status: " << mStatus;
+ waitForDestroy();
}
bool IncrementalService::DataLoaderStub::create() {
+ {
+ std::unique_lock lock(mStatusMutex);
+ mStartRequested = false;
+ mDestroyRequested = false;
+ }
bool created = false;
auto status = mService.mDataLoaderManager->initializeDataLoader(mId, mParams, mControl, this,
&created);
@@ -1491,12 +1490,18 @@
return true;
}
-bool IncrementalService::DataLoaderStub::start() {
- if (mStatus != IDataLoaderStatusListener::DATA_LOADER_CREATED) {
+bool IncrementalService::DataLoaderStub::requestStart() {
+ {
+ std::unique_lock lock(mStatusMutex);
mStartRequested = true;
- return true;
+ if (mStatus != IDataLoaderStatusListener::DATA_LOADER_CREATED) {
+ return true;
+ }
}
+ return start();
+}
+bool IncrementalService::DataLoaderStub::start() {
sp<IDataLoader> dataloader;
auto status = mService.mDataLoaderManager->getDataLoader(mId, &dataloader);
if (!status.isOk()) {
@@ -1513,8 +1518,21 @@
}
void IncrementalService::DataLoaderStub::destroy() {
- mDestroyRequested = true;
+ {
+ std::unique_lock lock(mStatusMutex);
+ mDestroyRequested = true;
+ }
mService.mDataLoaderManager->destroyDataLoader(mId);
+
+ waitForDestroy();
+}
+
+bool IncrementalService::DataLoaderStub::waitForDestroy() {
+ auto now = std::chrono::steady_clock::now();
+ std::unique_lock lock(mStatusMutex);
+ return mStatusCondition.wait_until(lock, now + 60s, [this] {
+ return mStatus == IDataLoaderStatusListener::DATA_LOADER_DESTROYED;
+ });
}
binder::Status IncrementalService::DataLoaderStub::onStatusChanged(MountId mountId, int newStatus) {
@@ -1523,34 +1541,36 @@
}
if (mListener) {
- // Give an external listener a chance to act before we destroy something.
mListener->onStatusChanged(mountId, newStatus);
}
+ bool startRequested;
+ bool destroyRequested;
{
- std::unique_lock l(mService.mLock);
- const auto& ifs = mService.getIfsLocked(mountId);
- if (!ifs) {
- LOG(WARNING) << "Received data loader status " << int(newStatus)
- << " for unknown mount " << mountId;
+ std::unique_lock lock(mStatusMutex);
+ if (mStatus == newStatus) {
return binder::Status::ok();
}
- mStatus = newStatus;
- if (!mDestroyRequested && newStatus == IDataLoaderStatusListener::DATA_LOADER_DESTROYED) {
- mService.deleteStorageLocked(*ifs, std::move(l));
- return binder::Status::ok();
- }
+ startRequested = mStartRequested;
+ destroyRequested = mDestroyRequested;
+
+ mStatus = newStatus;
}
switch (newStatus) {
case IDataLoaderStatusListener::DATA_LOADER_CREATED: {
- if (mStartRequested) {
+ if (startRequested) {
+ LOG(WARNING) << "Start was requested, triggering, for mount: " << mountId;
start();
}
break;
}
case IDataLoaderStatusListener::DATA_LOADER_DESTROYED: {
+ if (!destroyRequested) {
+ LOG(WARNING) << "DataLoader destroyed, reconnecting, for mount: " << mountId;
+ create();
+ }
break;
}
case IDataLoaderStatusListener::DATA_LOADER_STARTED: {
@@ -1589,4 +1609,8 @@
return binder::Status::ok();
}
+FileId IncrementalService::idFromMetadata(std::span<const uint8_t> metadata) {
+ return IncFs_FileIdFromMetadata({(const char*)metadata.data(), metadata.size()});
+}
+
} // namespace android::incremental
diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h
index c016bab..8c79d77 100644
--- a/services/incremental/IncrementalService.h
+++ b/services/incremental/IncrementalService.h
@@ -180,27 +180,32 @@
~DataLoaderStub();
bool create();
- bool start();
+ bool requestStart();
void destroy();
// accessors
MountId id() const { return mId; }
const DataLoaderParamsParcel& params() const { return mParams; }
- int status() const { return mStatus.load(); }
+ int status() const { return mStatus; }
bool startRequested() const { return mStartRequested; }
private:
binder::Status onStatusChanged(MountId mount, int newStatus) final;
+ bool start();
+ bool waitForDestroy();
+
IncrementalService& mService;
MountId const mId;
DataLoaderParamsParcel const mParams;
FileSystemControlParcel const mControl;
DataLoaderStatusListener const mListener;
- std::atomic<int> mStatus = -1;
+ std::mutex mStatusMutex;
+ std::condition_variable mStatusCondition;
+ int mStatus = IDataLoaderStatusListener::DATA_LOADER_DESTROYED;
bool mStartRequested = false;
- bool mDestroyRequested = false;
+ bool mDestroyRequested = true;
};
using DataLoaderStubPtr = sp<DataLoaderStub>;
diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp
index 117dca8..f9737fe 100644
--- a/services/incremental/test/IncrementalServiceTest.cpp
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -103,25 +103,34 @@
TemporaryFile logFile;
};
-class FakeDataLoader : public IDataLoader {
+class MockDataLoader : public IDataLoader {
public:
+ MockDataLoader() {
+ ON_CALL(*this, create(_, _, _, _)).WillByDefault(Return((binder::Status::ok())));
+ ON_CALL(*this, start(_)).WillByDefault(Return((binder::Status::ok())));
+ ON_CALL(*this, stop(_)).WillByDefault(Return((binder::Status::ok())));
+ ON_CALL(*this, destroy(_)).WillByDefault(Return((binder::Status::ok())));
+ ON_CALL(*this, prepareImage(_, _, _)).WillByDefault(Return((binder::Status::ok())));
+ }
IBinder* onAsBinder() override { return nullptr; }
- binder::Status create(int32_t, const DataLoaderParamsParcel&, const FileSystemControlParcel&,
- const sp<IDataLoaderStatusListener>&) override {
- return binder::Status::ok();
- }
- binder::Status start(int32_t) override { return binder::Status::ok(); }
- binder::Status stop(int32_t) override { return binder::Status::ok(); }
- binder::Status destroy(int32_t) override { return binder::Status::ok(); }
- binder::Status prepareImage(int32_t,
- const std::vector<InstallationFileParcel>&,
- const std::vector<std::string>&) override {
- return binder::Status::ok();
- }
+ MOCK_METHOD4(create,
+ binder::Status(int32_t id, const DataLoaderParamsParcel& params,
+ const FileSystemControlParcel& control,
+ const sp<IDataLoaderStatusListener>& listener));
+ MOCK_METHOD1(start, binder::Status(int32_t id));
+ MOCK_METHOD1(stop, binder::Status(int32_t id));
+ MOCK_METHOD1(destroy, binder::Status(int32_t id));
+ MOCK_METHOD3(prepareImage,
+ binder::Status(int32_t id, const std::vector<InstallationFileParcel>& addedFiles,
+ const std::vector<std::string>& removedFiles));
};
class MockDataLoaderManager : public DataLoaderManagerWrapper {
public:
+ MockDataLoaderManager(sp<IDataLoader> dataLoader) : mDataLoaderHolder(std::move(dataLoader)) {
+ EXPECT_TRUE(mDataLoaderHolder != nullptr);
+ }
+
MOCK_CONST_METHOD5(initializeDataLoader,
binder::Status(int32_t mountId, const DataLoaderParamsParcel& params,
const FileSystemControlParcel& control,
@@ -144,9 +153,9 @@
ON_CALL(*this, getDataLoader(_, _))
.WillByDefault(Invoke(this, &MockDataLoaderManager::getDataLoaderOk));
}
- void destroyDataLoaderOk() {
+ void destroyDataLoaderSuccess() {
ON_CALL(*this, destroyDataLoader(_))
- .WillByDefault(Invoke(this, &MockDataLoaderManager::setDataLoaderStatusDestroyed));
+ .WillByDefault(Invoke(this, &MockDataLoaderManager::destroyDataLoaderOk));
}
binder::Status initializeDataLoaderOk(int32_t mountId, const DataLoaderParamsParcel& params,
const FileSystemControlParcel& control,
@@ -155,20 +164,30 @@
mId = mountId;
mListener = listener;
mServiceConnector = control.service;
+ mDataLoader = mDataLoaderHolder;
*_aidl_return = true;
- return binder::Status::ok();
+ return mDataLoader->create(mountId, params, control, listener);
}
binder::Status getDataLoaderOk(int32_t mountId, sp<IDataLoader>* _aidl_return) {
*_aidl_return = mDataLoader;
return binder::Status::ok();
}
- void setDataLoaderStatusNotReady() {
- mListener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_DESTROYED);
- }
- void setDataLoaderStatusReady() {
+ void setDataLoaderStatusCreated() {
mListener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_CREATED);
}
- binder::Status setDataLoaderStatusDestroyed(int32_t id) {
+ void setDataLoaderStatusStarted() {
+ mListener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_STARTED);
+ }
+ void setDataLoaderStatusDestroyed() {
+ mListener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_DESTROYED);
+ }
+ binder::Status destroyDataLoaderOk(int32_t id) {
+ if (mDataLoader) {
+ if (auto status = mDataLoader->destroy(id); !status.isOk()) {
+ return status;
+ }
+ mDataLoader = nullptr;
+ }
if (mListener) {
mListener->onStatusChanged(id, IDataLoaderStatusListener::DATA_LOADER_DESTROYED);
}
@@ -185,7 +204,8 @@
int mId;
sp<IDataLoaderStatusListener> mListener;
sp<IIncrementalServiceConnector> mServiceConnector;
- sp<IDataLoader> mDataLoader = sp<IDataLoader>(new FakeDataLoader());
+ sp<IDataLoader> mDataLoader;
+ sp<IDataLoader> mDataLoaderHolder;
};
class MockIncFs : public IncFsWrapper {
@@ -303,7 +323,9 @@
void SetUp() override {
auto vold = std::make_unique<NiceMock<MockVoldService>>();
mVold = vold.get();
- auto dataloaderManager = std::make_unique<NiceMock<MockDataLoaderManager>>();
+ sp<NiceMock<MockDataLoader>> dataLoader{new NiceMock<MockDataLoader>};
+ mDataLoader = dataLoader.get();
+ auto dataloaderManager = std::make_unique<NiceMock<MockDataLoaderManager>>(dataLoader);
mDataLoaderManager = dataloaderManager.get();
auto incFs = std::make_unique<NiceMock<MockIncFs>>();
mIncFs = incFs.get();
@@ -321,7 +343,7 @@
mRootDir.path);
mDataLoaderParcel.packageName = "com.test";
mDataLoaderParcel.arguments = "uri";
- mDataLoaderManager->destroyDataLoaderOk();
+ mDataLoaderManager->destroyDataLoaderSuccess();
mIncrementalService->onSystemReady();
}
@@ -352,6 +374,7 @@
NiceMock<MockDataLoaderManager>* mDataLoaderManager;
NiceMock<MockAppOpsManager>* mAppOpsManager;
NiceMock<MockJniWrapper>* mJni;
+ NiceMock<MockDataLoader>* mDataLoader;
std::unique_ptr<IncrementalService> mIncrementalService;
TemporaryDir mRootDir;
DataLoaderParamsParcel mDataLoaderParcel;
@@ -410,7 +433,11 @@
mIncFs->makeFileSuccess();
mVold->bindMountSuccess();
mDataLoaderManager->initializeDataLoaderFails();
+ EXPECT_CALL(*mDataLoaderManager, initializeDataLoader(_, _, _, _, _)).Times(1);
EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_)).Times(1);
+ EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(0);
+ EXPECT_CALL(*mDataLoader, start(_)).Times(0);
+ EXPECT_CALL(*mDataLoader, destroy(_)).Times(0);
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
TemporaryDir tempDir;
int storageId =
@@ -424,46 +451,84 @@
mIncFs->makeFileSuccess();
mVold->bindMountSuccess();
mDataLoaderManager->initializeDataLoaderSuccess();
+ EXPECT_CALL(*mDataLoaderManager, initializeDataLoader(_, _, _, _, _)).Times(1);
EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_)).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->setDataLoaderStatusCreated();
mIncrementalService->deleteStorage(storageId);
}
-TEST_F(IncrementalServiceTest, testOnStatusNotReady) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mVold->bindMountSuccess();
- mDataLoaderManager->initializeDataLoaderSuccess();
- EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_));
- 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->setDataLoaderStatusNotReady();
-}
-
-TEST_F(IncrementalServiceTest, testStartDataLoaderSuccess) {
+TEST_F(IncrementalServiceTest, testDataLoaderDestroyed) {
mVold->mountIncFsSuccess();
mIncFs->makeFileSuccess();
mVold->bindMountSuccess();
mDataLoaderManager->initializeDataLoaderSuccess();
mDataLoaderManager->getDataLoaderSuccess();
- EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_));
+ EXPECT_CALL(*mDataLoaderManager, initializeDataLoader(_, _, _, _, _)).Times(2);
+ EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_)).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);
TemporaryDir tempDir;
int storageId =
mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
IncrementalService::CreateOptions::CreateNew);
ASSERT_GE(storageId, 0);
- mDataLoaderManager->setDataLoaderStatusReady();
+ mDataLoaderManager->setDataLoaderStatusCreated();
+ // Simulated crash/other connection breakage.
+ mDataLoaderManager->setDataLoaderStatusDestroyed();
+}
+
+TEST_F(IncrementalServiceTest, testStartDataLoaderCreate) {
+ mVold->mountIncFsSuccess();
+ mIncFs->makeFileSuccess();
+ mVold->bindMountSuccess();
+ mDataLoaderManager->initializeDataLoaderSuccess();
+ mDataLoaderManager->getDataLoaderSuccess();
+ EXPECT_CALL(*mDataLoaderManager, initializeDataLoader(_, _, _, _, _)).Times(1);
+ EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_)).Times(1);
+ EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(1);
+ EXPECT_CALL(*mDataLoader, start(_)).Times(1);
+ 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->setDataLoaderStatusCreated();
ASSERT_TRUE(mIncrementalService->startLoading(storageId));
+ mDataLoaderManager->setDataLoaderStatusStarted();
+}
+
+TEST_F(IncrementalServiceTest, testStartDataLoaderPendingStart) {
+ mVold->mountIncFsSuccess();
+ mIncFs->makeFileSuccess();
+ mVold->bindMountSuccess();
+ mDataLoaderManager->initializeDataLoaderSuccess();
+ mDataLoaderManager->getDataLoaderSuccess();
+ EXPECT_CALL(*mDataLoaderManager, initializeDataLoader(_, _, _, _, _)).Times(1);
+ EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_)).Times(1);
+ EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(1);
+ EXPECT_CALL(*mDataLoader, start(_)).Times(1);
+ 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);
+ ASSERT_TRUE(mIncrementalService->startLoading(storageId));
+ mDataLoaderManager->setDataLoaderStatusCreated();
}
TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccess) {