Loading services/core/java/com/android/server/pm/DataLoaderManagerService.java +6 −0 Original line number Original line Diff line number Diff line Loading @@ -204,6 +204,12 @@ public class DataLoaderManagerService extends SystemService { @Override @Override public void onServiceDisconnected(ComponentName arg0) { public void onServiceDisconnected(ComponentName arg0) { if (mListener != null) { try { mListener.onStatusChanged(mId, IDataLoaderStatusListener.DATA_LOADER_DESTROYED); } catch (RemoteException ignored) { } } remove(); remove(); } } Loading services/incremental/IncrementalService.cpp +48 −24 Original line number Original line Diff line number Diff line Loading @@ -258,10 +258,6 @@ IncrementalService::IncrementalService(ServiceManagerWrapper&& sm, std::string_v mountExistingImages(); mountExistingImages(); } } FileId IncrementalService::idFromMetadata(std::span<const uint8_t> metadata) { return IncFs_FileIdFromMetadata({(const char*)metadata.data(), metadata.size()}); } IncrementalService::~IncrementalService() { IncrementalService::~IncrementalService() { { { std::lock_guard lock(mJobMutex); std::lock_guard lock(mJobMutex); Loading Loading @@ -1016,7 +1012,7 @@ bool IncrementalService::startLoading(StorageId storage) const { return false; return false; } } } } return dataLoaderStub->start(); return dataLoaderStub->requestStart(); } } void IncrementalService::mountExistingImages() { void IncrementalService::mountExistingImages() { Loading Loading @@ -1475,12 +1471,15 @@ void IncrementalService::onAppOpChanged(const std::string& packageName) { } } IncrementalService::DataLoaderStub::~DataLoaderStub() { IncrementalService::DataLoaderStub::~DataLoaderStub() { CHECK(mStatus == -1 || mStatus == IDataLoaderStatusListener::DATA_LOADER_DESTROYED) waitForDestroy(); << "Dataloader has to be destroyed prior to destructor: " << mId << ", status: " << mStatus; } } bool IncrementalService::DataLoaderStub::create() { bool IncrementalService::DataLoaderStub::create() { { std::unique_lock lock(mStatusMutex); mStartRequested = false; mDestroyRequested = false; } bool created = false; bool created = false; auto status = mService.mDataLoaderManager->initializeDataLoader(mId, mParams, mControl, this, auto status = mService.mDataLoaderManager->initializeDataLoader(mId, mParams, mControl, this, &created); &created); Loading @@ -1491,12 +1490,18 @@ bool IncrementalService::DataLoaderStub::create() { return true; return true; } } bool IncrementalService::DataLoaderStub::start() { bool IncrementalService::DataLoaderStub::requestStart() { if (mStatus != IDataLoaderStatusListener::DATA_LOADER_CREATED) { { std::unique_lock lock(mStatusMutex); mStartRequested = true; mStartRequested = true; if (mStatus != IDataLoaderStatusListener::DATA_LOADER_CREATED) { return true; return true; } } } return start(); } bool IncrementalService::DataLoaderStub::start() { sp<IDataLoader> dataloader; sp<IDataLoader> dataloader; auto status = mService.mDataLoaderManager->getDataLoader(mId, &dataloader); auto status = mService.mDataLoaderManager->getDataLoader(mId, &dataloader); if (!status.isOk()) { if (!status.isOk()) { Loading @@ -1513,8 +1518,21 @@ bool IncrementalService::DataLoaderStub::start() { } } void IncrementalService::DataLoaderStub::destroy() { void IncrementalService::DataLoaderStub::destroy() { { std::unique_lock lock(mStatusMutex); mDestroyRequested = true; mDestroyRequested = true; } mService.mDataLoaderManager->destroyDataLoader(mId); 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) { binder::Status IncrementalService::DataLoaderStub::onStatusChanged(MountId mountId, int newStatus) { Loading @@ -1523,34 +1541,36 @@ binder::Status IncrementalService::DataLoaderStub::onStatusChanged(MountId mount } } if (mListener) { if (mListener) { // Give an external listener a chance to act before we destroy something. mListener->onStatusChanged(mountId, newStatus); mListener->onStatusChanged(mountId, newStatus); } } bool startRequested; bool destroyRequested; { { std::unique_lock l(mService.mLock); std::unique_lock lock(mStatusMutex); const auto& ifs = mService.getIfsLocked(mountId); if (mStatus == newStatus) { if (!ifs) { LOG(WARNING) << "Received data loader status " << int(newStatus) << " for unknown mount " << mountId; return binder::Status::ok(); return binder::Status::ok(); } } mStatus = newStatus; if (!mDestroyRequested && newStatus == IDataLoaderStatusListener::DATA_LOADER_DESTROYED) { startRequested = mStartRequested; mService.deleteStorageLocked(*ifs, std::move(l)); destroyRequested = mDestroyRequested; return binder::Status::ok(); } mStatus = newStatus; } } switch (newStatus) { switch (newStatus) { case IDataLoaderStatusListener::DATA_LOADER_CREATED: { case IDataLoaderStatusListener::DATA_LOADER_CREATED: { if (mStartRequested) { if (startRequested) { LOG(WARNING) << "Start was requested, triggering, for mount: " << mountId; start(); start(); } } break; break; } } case IDataLoaderStatusListener::DATA_LOADER_DESTROYED: { case IDataLoaderStatusListener::DATA_LOADER_DESTROYED: { if (!destroyRequested) { LOG(WARNING) << "DataLoader destroyed, reconnecting, for mount: " << mountId; create(); } break; break; } } case IDataLoaderStatusListener::DATA_LOADER_STARTED: { case IDataLoaderStatusListener::DATA_LOADER_STARTED: { Loading Loading @@ -1589,4 +1609,8 @@ binder::Status IncrementalService::IncrementalServiceConnector::setStorageParams return binder::Status::ok(); 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 } // namespace android::incremental services/incremental/IncrementalService.h +9 −4 Original line number Original line Diff line number Diff line Loading @@ -180,27 +180,32 @@ private: ~DataLoaderStub(); ~DataLoaderStub(); bool create(); bool create(); bool start(); bool requestStart(); void destroy(); void destroy(); // accessors // accessors MountId id() const { return mId; } MountId id() const { return mId; } const DataLoaderParamsParcel& params() const { return mParams; } const DataLoaderParamsParcel& params() const { return mParams; } int status() const { return mStatus.load(); } int status() const { return mStatus; } bool startRequested() const { return mStartRequested; } bool startRequested() const { return mStartRequested; } private: private: binder::Status onStatusChanged(MountId mount, int newStatus) final; binder::Status onStatusChanged(MountId mount, int newStatus) final; bool start(); bool waitForDestroy(); IncrementalService& mService; IncrementalService& mService; MountId const mId; MountId const mId; DataLoaderParamsParcel const mParams; DataLoaderParamsParcel const mParams; FileSystemControlParcel const mControl; FileSystemControlParcel const mControl; DataLoaderStatusListener const mListener; 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 mStartRequested = false; bool mDestroyRequested = false; bool mDestroyRequested = true; }; }; using DataLoaderStubPtr = sp<DataLoaderStub>; using DataLoaderStubPtr = sp<DataLoaderStub>; Loading services/incremental/test/IncrementalServiceTest.cpp +95 −30 Original line number Original line Diff line number Diff line Loading @@ -103,25 +103,34 @@ private: TemporaryFile logFile; TemporaryFile logFile; }; }; class FakeDataLoader : public IDataLoader { class MockDataLoader : public IDataLoader { public: public: IBinder* onAsBinder() override { return nullptr; } MockDataLoader() { binder::Status create(int32_t, const DataLoaderParamsParcel&, const FileSystemControlParcel&, ON_CALL(*this, create(_, _, _, _)).WillByDefault(Return((binder::Status::ok()))); const sp<IDataLoaderStatusListener>&) override { ON_CALL(*this, start(_)).WillByDefault(Return((binder::Status::ok()))); return binder::Status::ok(); ON_CALL(*this, stop(_)).WillByDefault(Return((binder::Status::ok()))); } ON_CALL(*this, destroy(_)).WillByDefault(Return((binder::Status::ok()))); binder::Status start(int32_t) override { return binder::Status::ok(); } ON_CALL(*this, prepareImage(_, _, _)).WillByDefault(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(); } } IBinder* onAsBinder() override { return nullptr; } 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 { class MockDataLoaderManager : public DataLoaderManagerWrapper { public: public: MockDataLoaderManager(sp<IDataLoader> dataLoader) : mDataLoaderHolder(std::move(dataLoader)) { EXPECT_TRUE(mDataLoaderHolder != nullptr); } MOCK_CONST_METHOD5(initializeDataLoader, MOCK_CONST_METHOD5(initializeDataLoader, binder::Status(int32_t mountId, const DataLoaderParamsParcel& params, binder::Status(int32_t mountId, const DataLoaderParamsParcel& params, const FileSystemControlParcel& control, const FileSystemControlParcel& control, Loading @@ -144,9 +153,9 @@ public: ON_CALL(*this, getDataLoader(_, _)) ON_CALL(*this, getDataLoader(_, _)) .WillByDefault(Invoke(this, &MockDataLoaderManager::getDataLoaderOk)); .WillByDefault(Invoke(this, &MockDataLoaderManager::getDataLoaderOk)); } } void destroyDataLoaderOk() { void destroyDataLoaderSuccess() { ON_CALL(*this, destroyDataLoader(_)) ON_CALL(*this, destroyDataLoader(_)) .WillByDefault(Invoke(this, &MockDataLoaderManager::setDataLoaderStatusDestroyed)); .WillByDefault(Invoke(this, &MockDataLoaderManager::destroyDataLoaderOk)); } } binder::Status initializeDataLoaderOk(int32_t mountId, const DataLoaderParamsParcel& params, binder::Status initializeDataLoaderOk(int32_t mountId, const DataLoaderParamsParcel& params, const FileSystemControlParcel& control, const FileSystemControlParcel& control, Loading @@ -155,20 +164,30 @@ public: mId = mountId; mId = mountId; mListener = listener; mListener = listener; mServiceConnector = control.service; mServiceConnector = control.service; mDataLoader = mDataLoaderHolder; *_aidl_return = true; *_aidl_return = true; return binder::Status::ok(); return mDataLoader->create(mountId, params, control, listener); } } binder::Status getDataLoaderOk(int32_t mountId, sp<IDataLoader>* _aidl_return) { binder::Status getDataLoaderOk(int32_t mountId, sp<IDataLoader>* _aidl_return) { *_aidl_return = mDataLoader; *_aidl_return = mDataLoader; return binder::Status::ok(); return binder::Status::ok(); } } void setDataLoaderStatusNotReady() { void setDataLoaderStatusCreated() { mListener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_CREATED); } void setDataLoaderStatusStarted() { mListener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_STARTED); } void setDataLoaderStatusDestroyed() { mListener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_DESTROYED); mListener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_DESTROYED); } } void setDataLoaderStatusReady() { binder::Status destroyDataLoaderOk(int32_t id) { mListener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_CREATED); if (mDataLoader) { if (auto status = mDataLoader->destroy(id); !status.isOk()) { return status; } mDataLoader = nullptr; } } binder::Status setDataLoaderStatusDestroyed(int32_t id) { if (mListener) { if (mListener) { mListener->onStatusChanged(id, IDataLoaderStatusListener::DATA_LOADER_DESTROYED); mListener->onStatusChanged(id, IDataLoaderStatusListener::DATA_LOADER_DESTROYED); } } Loading @@ -185,7 +204,8 @@ private: int mId; int mId; sp<IDataLoaderStatusListener> mListener; sp<IDataLoaderStatusListener> mListener; sp<IIncrementalServiceConnector> mServiceConnector; sp<IIncrementalServiceConnector> mServiceConnector; sp<IDataLoader> mDataLoader = sp<IDataLoader>(new FakeDataLoader()); sp<IDataLoader> mDataLoader; sp<IDataLoader> mDataLoaderHolder; }; }; class MockIncFs : public IncFsWrapper { class MockIncFs : public IncFsWrapper { Loading Loading @@ -303,7 +323,9 @@ public: void SetUp() override { void SetUp() override { auto vold = std::make_unique<NiceMock<MockVoldService>>(); auto vold = std::make_unique<NiceMock<MockVoldService>>(); mVold = vold.get(); 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(); mDataLoaderManager = dataloaderManager.get(); auto incFs = std::make_unique<NiceMock<MockIncFs>>(); auto incFs = std::make_unique<NiceMock<MockIncFs>>(); mIncFs = incFs.get(); mIncFs = incFs.get(); Loading @@ -321,7 +343,7 @@ public: mRootDir.path); mRootDir.path); mDataLoaderParcel.packageName = "com.test"; mDataLoaderParcel.packageName = "com.test"; mDataLoaderParcel.arguments = "uri"; mDataLoaderParcel.arguments = "uri"; mDataLoaderManager->destroyDataLoaderOk(); mDataLoaderManager->destroyDataLoaderSuccess(); mIncrementalService->onSystemReady(); mIncrementalService->onSystemReady(); } } Loading Loading @@ -352,6 +374,7 @@ protected: NiceMock<MockDataLoaderManager>* mDataLoaderManager; NiceMock<MockDataLoaderManager>* mDataLoaderManager; NiceMock<MockAppOpsManager>* mAppOpsManager; NiceMock<MockAppOpsManager>* mAppOpsManager; NiceMock<MockJniWrapper>* mJni; NiceMock<MockJniWrapper>* mJni; NiceMock<MockDataLoader>* mDataLoader; std::unique_ptr<IncrementalService> mIncrementalService; std::unique_ptr<IncrementalService> mIncrementalService; TemporaryDir mRootDir; TemporaryDir mRootDir; DataLoaderParamsParcel mDataLoaderParcel; DataLoaderParamsParcel mDataLoaderParcel; Loading Loading @@ -410,7 +433,11 @@ TEST_F(IncrementalServiceTest, testCreateStoragePrepareDataLoaderFails) { mIncFs->makeFileSuccess(); mIncFs->makeFileSuccess(); mVold->bindMountSuccess(); mVold->bindMountSuccess(); mDataLoaderManager->initializeDataLoaderFails(); mDataLoaderManager->initializeDataLoaderFails(); EXPECT_CALL(*mDataLoaderManager, initializeDataLoader(_, _, _, _, _)).Times(1); EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_)).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); EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2); TemporaryDir tempDir; TemporaryDir tempDir; int storageId = int storageId = Loading @@ -424,46 +451,84 @@ TEST_F(IncrementalServiceTest, testDeleteStorageSuccess) { mIncFs->makeFileSuccess(); mIncFs->makeFileSuccess(); mVold->bindMountSuccess(); mVold->bindMountSuccess(); mDataLoaderManager->initializeDataLoaderSuccess(); mDataLoaderManager->initializeDataLoaderSuccess(); EXPECT_CALL(*mDataLoaderManager, initializeDataLoader(_, _, _, _, _)).Times(1); EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_)).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); EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2); TemporaryDir tempDir; TemporaryDir tempDir; int storageId = int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, IncrementalService::CreateOptions::CreateNew); IncrementalService::CreateOptions::CreateNew); ASSERT_GE(storageId, 0); ASSERT_GE(storageId, 0); mDataLoaderManager->setDataLoaderStatusCreated(); mIncrementalService->deleteStorage(storageId); mIncrementalService->deleteStorage(storageId); } } TEST_F(IncrementalServiceTest, testOnStatusNotReady) { TEST_F(IncrementalServiceTest, testDataLoaderDestroyed) { mVold->mountIncFsSuccess(); mVold->mountIncFsSuccess(); mIncFs->makeFileSuccess(); mIncFs->makeFileSuccess(); mVold->bindMountSuccess(); mVold->bindMountSuccess(); mDataLoaderManager->initializeDataLoaderSuccess(); mDataLoaderManager->initializeDataLoaderSuccess(); EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_)); mDataLoaderManager->getDataLoaderSuccess(); 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); EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2); TemporaryDir tempDir; TemporaryDir tempDir; int storageId = int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, IncrementalService::CreateOptions::CreateNew); IncrementalService::CreateOptions::CreateNew); ASSERT_GE(storageId, 0); ASSERT_GE(storageId, 0); mDataLoaderManager->setDataLoaderStatusNotReady(); mDataLoaderManager->setDataLoaderStatusCreated(); // Simulated crash/other connection breakage. mDataLoaderManager->setDataLoaderStatusDestroyed(); } } TEST_F(IncrementalServiceTest, testStartDataLoaderSuccess) { TEST_F(IncrementalServiceTest, testStartDataLoaderCreate) { mVold->mountIncFsSuccess(); mVold->mountIncFsSuccess(); mIncFs->makeFileSuccess(); mIncFs->makeFileSuccess(); mVold->bindMountSuccess(); mVold->bindMountSuccess(); mDataLoaderManager->initializeDataLoaderSuccess(); mDataLoaderManager->initializeDataLoaderSuccess(); mDataLoaderManager->getDataLoaderSuccess(); mDataLoaderManager->getDataLoaderSuccess(); EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_)); 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); EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2); TemporaryDir tempDir; TemporaryDir tempDir; int storageId = int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, IncrementalService::CreateOptions::CreateNew); IncrementalService::CreateOptions::CreateNew); ASSERT_GE(storageId, 0); ASSERT_GE(storageId, 0); mDataLoaderManager->setDataLoaderStatusReady(); ASSERT_TRUE(mIncrementalService->startLoading(storageId)); ASSERT_TRUE(mIncrementalService->startLoading(storageId)); mDataLoaderManager->setDataLoaderStatusCreated(); } } TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccess) { TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccess) { Loading Loading
services/core/java/com/android/server/pm/DataLoaderManagerService.java +6 −0 Original line number Original line Diff line number Diff line Loading @@ -204,6 +204,12 @@ public class DataLoaderManagerService extends SystemService { @Override @Override public void onServiceDisconnected(ComponentName arg0) { public void onServiceDisconnected(ComponentName arg0) { if (mListener != null) { try { mListener.onStatusChanged(mId, IDataLoaderStatusListener.DATA_LOADER_DESTROYED); } catch (RemoteException ignored) { } } remove(); remove(); } } Loading
services/incremental/IncrementalService.cpp +48 −24 Original line number Original line Diff line number Diff line Loading @@ -258,10 +258,6 @@ IncrementalService::IncrementalService(ServiceManagerWrapper&& sm, std::string_v mountExistingImages(); mountExistingImages(); } } FileId IncrementalService::idFromMetadata(std::span<const uint8_t> metadata) { return IncFs_FileIdFromMetadata({(const char*)metadata.data(), metadata.size()}); } IncrementalService::~IncrementalService() { IncrementalService::~IncrementalService() { { { std::lock_guard lock(mJobMutex); std::lock_guard lock(mJobMutex); Loading Loading @@ -1016,7 +1012,7 @@ bool IncrementalService::startLoading(StorageId storage) const { return false; return false; } } } } return dataLoaderStub->start(); return dataLoaderStub->requestStart(); } } void IncrementalService::mountExistingImages() { void IncrementalService::mountExistingImages() { Loading Loading @@ -1475,12 +1471,15 @@ void IncrementalService::onAppOpChanged(const std::string& packageName) { } } IncrementalService::DataLoaderStub::~DataLoaderStub() { IncrementalService::DataLoaderStub::~DataLoaderStub() { CHECK(mStatus == -1 || mStatus == IDataLoaderStatusListener::DATA_LOADER_DESTROYED) waitForDestroy(); << "Dataloader has to be destroyed prior to destructor: " << mId << ", status: " << mStatus; } } bool IncrementalService::DataLoaderStub::create() { bool IncrementalService::DataLoaderStub::create() { { std::unique_lock lock(mStatusMutex); mStartRequested = false; mDestroyRequested = false; } bool created = false; bool created = false; auto status = mService.mDataLoaderManager->initializeDataLoader(mId, mParams, mControl, this, auto status = mService.mDataLoaderManager->initializeDataLoader(mId, mParams, mControl, this, &created); &created); Loading @@ -1491,12 +1490,18 @@ bool IncrementalService::DataLoaderStub::create() { return true; return true; } } bool IncrementalService::DataLoaderStub::start() { bool IncrementalService::DataLoaderStub::requestStart() { if (mStatus != IDataLoaderStatusListener::DATA_LOADER_CREATED) { { std::unique_lock lock(mStatusMutex); mStartRequested = true; mStartRequested = true; if (mStatus != IDataLoaderStatusListener::DATA_LOADER_CREATED) { return true; return true; } } } return start(); } bool IncrementalService::DataLoaderStub::start() { sp<IDataLoader> dataloader; sp<IDataLoader> dataloader; auto status = mService.mDataLoaderManager->getDataLoader(mId, &dataloader); auto status = mService.mDataLoaderManager->getDataLoader(mId, &dataloader); if (!status.isOk()) { if (!status.isOk()) { Loading @@ -1513,8 +1518,21 @@ bool IncrementalService::DataLoaderStub::start() { } } void IncrementalService::DataLoaderStub::destroy() { void IncrementalService::DataLoaderStub::destroy() { { std::unique_lock lock(mStatusMutex); mDestroyRequested = true; mDestroyRequested = true; } mService.mDataLoaderManager->destroyDataLoader(mId); 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) { binder::Status IncrementalService::DataLoaderStub::onStatusChanged(MountId mountId, int newStatus) { Loading @@ -1523,34 +1541,36 @@ binder::Status IncrementalService::DataLoaderStub::onStatusChanged(MountId mount } } if (mListener) { if (mListener) { // Give an external listener a chance to act before we destroy something. mListener->onStatusChanged(mountId, newStatus); mListener->onStatusChanged(mountId, newStatus); } } bool startRequested; bool destroyRequested; { { std::unique_lock l(mService.mLock); std::unique_lock lock(mStatusMutex); const auto& ifs = mService.getIfsLocked(mountId); if (mStatus == newStatus) { if (!ifs) { LOG(WARNING) << "Received data loader status " << int(newStatus) << " for unknown mount " << mountId; return binder::Status::ok(); return binder::Status::ok(); } } mStatus = newStatus; if (!mDestroyRequested && newStatus == IDataLoaderStatusListener::DATA_LOADER_DESTROYED) { startRequested = mStartRequested; mService.deleteStorageLocked(*ifs, std::move(l)); destroyRequested = mDestroyRequested; return binder::Status::ok(); } mStatus = newStatus; } } switch (newStatus) { switch (newStatus) { case IDataLoaderStatusListener::DATA_LOADER_CREATED: { case IDataLoaderStatusListener::DATA_LOADER_CREATED: { if (mStartRequested) { if (startRequested) { LOG(WARNING) << "Start was requested, triggering, for mount: " << mountId; start(); start(); } } break; break; } } case IDataLoaderStatusListener::DATA_LOADER_DESTROYED: { case IDataLoaderStatusListener::DATA_LOADER_DESTROYED: { if (!destroyRequested) { LOG(WARNING) << "DataLoader destroyed, reconnecting, for mount: " << mountId; create(); } break; break; } } case IDataLoaderStatusListener::DATA_LOADER_STARTED: { case IDataLoaderStatusListener::DATA_LOADER_STARTED: { Loading Loading @@ -1589,4 +1609,8 @@ binder::Status IncrementalService::IncrementalServiceConnector::setStorageParams return binder::Status::ok(); 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 } // namespace android::incremental
services/incremental/IncrementalService.h +9 −4 Original line number Original line Diff line number Diff line Loading @@ -180,27 +180,32 @@ private: ~DataLoaderStub(); ~DataLoaderStub(); bool create(); bool create(); bool start(); bool requestStart(); void destroy(); void destroy(); // accessors // accessors MountId id() const { return mId; } MountId id() const { return mId; } const DataLoaderParamsParcel& params() const { return mParams; } const DataLoaderParamsParcel& params() const { return mParams; } int status() const { return mStatus.load(); } int status() const { return mStatus; } bool startRequested() const { return mStartRequested; } bool startRequested() const { return mStartRequested; } private: private: binder::Status onStatusChanged(MountId mount, int newStatus) final; binder::Status onStatusChanged(MountId mount, int newStatus) final; bool start(); bool waitForDestroy(); IncrementalService& mService; IncrementalService& mService; MountId const mId; MountId const mId; DataLoaderParamsParcel const mParams; DataLoaderParamsParcel const mParams; FileSystemControlParcel const mControl; FileSystemControlParcel const mControl; DataLoaderStatusListener const mListener; 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 mStartRequested = false; bool mDestroyRequested = false; bool mDestroyRequested = true; }; }; using DataLoaderStubPtr = sp<DataLoaderStub>; using DataLoaderStubPtr = sp<DataLoaderStub>; Loading
services/incremental/test/IncrementalServiceTest.cpp +95 −30 Original line number Original line Diff line number Diff line Loading @@ -103,25 +103,34 @@ private: TemporaryFile logFile; TemporaryFile logFile; }; }; class FakeDataLoader : public IDataLoader { class MockDataLoader : public IDataLoader { public: public: IBinder* onAsBinder() override { return nullptr; } MockDataLoader() { binder::Status create(int32_t, const DataLoaderParamsParcel&, const FileSystemControlParcel&, ON_CALL(*this, create(_, _, _, _)).WillByDefault(Return((binder::Status::ok()))); const sp<IDataLoaderStatusListener>&) override { ON_CALL(*this, start(_)).WillByDefault(Return((binder::Status::ok()))); return binder::Status::ok(); ON_CALL(*this, stop(_)).WillByDefault(Return((binder::Status::ok()))); } ON_CALL(*this, destroy(_)).WillByDefault(Return((binder::Status::ok()))); binder::Status start(int32_t) override { return binder::Status::ok(); } ON_CALL(*this, prepareImage(_, _, _)).WillByDefault(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(); } } IBinder* onAsBinder() override { return nullptr; } 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 { class MockDataLoaderManager : public DataLoaderManagerWrapper { public: public: MockDataLoaderManager(sp<IDataLoader> dataLoader) : mDataLoaderHolder(std::move(dataLoader)) { EXPECT_TRUE(mDataLoaderHolder != nullptr); } MOCK_CONST_METHOD5(initializeDataLoader, MOCK_CONST_METHOD5(initializeDataLoader, binder::Status(int32_t mountId, const DataLoaderParamsParcel& params, binder::Status(int32_t mountId, const DataLoaderParamsParcel& params, const FileSystemControlParcel& control, const FileSystemControlParcel& control, Loading @@ -144,9 +153,9 @@ public: ON_CALL(*this, getDataLoader(_, _)) ON_CALL(*this, getDataLoader(_, _)) .WillByDefault(Invoke(this, &MockDataLoaderManager::getDataLoaderOk)); .WillByDefault(Invoke(this, &MockDataLoaderManager::getDataLoaderOk)); } } void destroyDataLoaderOk() { void destroyDataLoaderSuccess() { ON_CALL(*this, destroyDataLoader(_)) ON_CALL(*this, destroyDataLoader(_)) .WillByDefault(Invoke(this, &MockDataLoaderManager::setDataLoaderStatusDestroyed)); .WillByDefault(Invoke(this, &MockDataLoaderManager::destroyDataLoaderOk)); } } binder::Status initializeDataLoaderOk(int32_t mountId, const DataLoaderParamsParcel& params, binder::Status initializeDataLoaderOk(int32_t mountId, const DataLoaderParamsParcel& params, const FileSystemControlParcel& control, const FileSystemControlParcel& control, Loading @@ -155,20 +164,30 @@ public: mId = mountId; mId = mountId; mListener = listener; mListener = listener; mServiceConnector = control.service; mServiceConnector = control.service; mDataLoader = mDataLoaderHolder; *_aidl_return = true; *_aidl_return = true; return binder::Status::ok(); return mDataLoader->create(mountId, params, control, listener); } } binder::Status getDataLoaderOk(int32_t mountId, sp<IDataLoader>* _aidl_return) { binder::Status getDataLoaderOk(int32_t mountId, sp<IDataLoader>* _aidl_return) { *_aidl_return = mDataLoader; *_aidl_return = mDataLoader; return binder::Status::ok(); return binder::Status::ok(); } } void setDataLoaderStatusNotReady() { void setDataLoaderStatusCreated() { mListener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_CREATED); } void setDataLoaderStatusStarted() { mListener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_STARTED); } void setDataLoaderStatusDestroyed() { mListener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_DESTROYED); mListener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_DESTROYED); } } void setDataLoaderStatusReady() { binder::Status destroyDataLoaderOk(int32_t id) { mListener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_CREATED); if (mDataLoader) { if (auto status = mDataLoader->destroy(id); !status.isOk()) { return status; } mDataLoader = nullptr; } } binder::Status setDataLoaderStatusDestroyed(int32_t id) { if (mListener) { if (mListener) { mListener->onStatusChanged(id, IDataLoaderStatusListener::DATA_LOADER_DESTROYED); mListener->onStatusChanged(id, IDataLoaderStatusListener::DATA_LOADER_DESTROYED); } } Loading @@ -185,7 +204,8 @@ private: int mId; int mId; sp<IDataLoaderStatusListener> mListener; sp<IDataLoaderStatusListener> mListener; sp<IIncrementalServiceConnector> mServiceConnector; sp<IIncrementalServiceConnector> mServiceConnector; sp<IDataLoader> mDataLoader = sp<IDataLoader>(new FakeDataLoader()); sp<IDataLoader> mDataLoader; sp<IDataLoader> mDataLoaderHolder; }; }; class MockIncFs : public IncFsWrapper { class MockIncFs : public IncFsWrapper { Loading Loading @@ -303,7 +323,9 @@ public: void SetUp() override { void SetUp() override { auto vold = std::make_unique<NiceMock<MockVoldService>>(); auto vold = std::make_unique<NiceMock<MockVoldService>>(); mVold = vold.get(); 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(); mDataLoaderManager = dataloaderManager.get(); auto incFs = std::make_unique<NiceMock<MockIncFs>>(); auto incFs = std::make_unique<NiceMock<MockIncFs>>(); mIncFs = incFs.get(); mIncFs = incFs.get(); Loading @@ -321,7 +343,7 @@ public: mRootDir.path); mRootDir.path); mDataLoaderParcel.packageName = "com.test"; mDataLoaderParcel.packageName = "com.test"; mDataLoaderParcel.arguments = "uri"; mDataLoaderParcel.arguments = "uri"; mDataLoaderManager->destroyDataLoaderOk(); mDataLoaderManager->destroyDataLoaderSuccess(); mIncrementalService->onSystemReady(); mIncrementalService->onSystemReady(); } } Loading Loading @@ -352,6 +374,7 @@ protected: NiceMock<MockDataLoaderManager>* mDataLoaderManager; NiceMock<MockDataLoaderManager>* mDataLoaderManager; NiceMock<MockAppOpsManager>* mAppOpsManager; NiceMock<MockAppOpsManager>* mAppOpsManager; NiceMock<MockJniWrapper>* mJni; NiceMock<MockJniWrapper>* mJni; NiceMock<MockDataLoader>* mDataLoader; std::unique_ptr<IncrementalService> mIncrementalService; std::unique_ptr<IncrementalService> mIncrementalService; TemporaryDir mRootDir; TemporaryDir mRootDir; DataLoaderParamsParcel mDataLoaderParcel; DataLoaderParamsParcel mDataLoaderParcel; Loading Loading @@ -410,7 +433,11 @@ TEST_F(IncrementalServiceTest, testCreateStoragePrepareDataLoaderFails) { mIncFs->makeFileSuccess(); mIncFs->makeFileSuccess(); mVold->bindMountSuccess(); mVold->bindMountSuccess(); mDataLoaderManager->initializeDataLoaderFails(); mDataLoaderManager->initializeDataLoaderFails(); EXPECT_CALL(*mDataLoaderManager, initializeDataLoader(_, _, _, _, _)).Times(1); EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_)).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); EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2); TemporaryDir tempDir; TemporaryDir tempDir; int storageId = int storageId = Loading @@ -424,46 +451,84 @@ TEST_F(IncrementalServiceTest, testDeleteStorageSuccess) { mIncFs->makeFileSuccess(); mIncFs->makeFileSuccess(); mVold->bindMountSuccess(); mVold->bindMountSuccess(); mDataLoaderManager->initializeDataLoaderSuccess(); mDataLoaderManager->initializeDataLoaderSuccess(); EXPECT_CALL(*mDataLoaderManager, initializeDataLoader(_, _, _, _, _)).Times(1); EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_)).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); EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2); TemporaryDir tempDir; TemporaryDir tempDir; int storageId = int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, IncrementalService::CreateOptions::CreateNew); IncrementalService::CreateOptions::CreateNew); ASSERT_GE(storageId, 0); ASSERT_GE(storageId, 0); mDataLoaderManager->setDataLoaderStatusCreated(); mIncrementalService->deleteStorage(storageId); mIncrementalService->deleteStorage(storageId); } } TEST_F(IncrementalServiceTest, testOnStatusNotReady) { TEST_F(IncrementalServiceTest, testDataLoaderDestroyed) { mVold->mountIncFsSuccess(); mVold->mountIncFsSuccess(); mIncFs->makeFileSuccess(); mIncFs->makeFileSuccess(); mVold->bindMountSuccess(); mVold->bindMountSuccess(); mDataLoaderManager->initializeDataLoaderSuccess(); mDataLoaderManager->initializeDataLoaderSuccess(); EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_)); mDataLoaderManager->getDataLoaderSuccess(); 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); EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2); TemporaryDir tempDir; TemporaryDir tempDir; int storageId = int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, IncrementalService::CreateOptions::CreateNew); IncrementalService::CreateOptions::CreateNew); ASSERT_GE(storageId, 0); ASSERT_GE(storageId, 0); mDataLoaderManager->setDataLoaderStatusNotReady(); mDataLoaderManager->setDataLoaderStatusCreated(); // Simulated crash/other connection breakage. mDataLoaderManager->setDataLoaderStatusDestroyed(); } } TEST_F(IncrementalServiceTest, testStartDataLoaderSuccess) { TEST_F(IncrementalServiceTest, testStartDataLoaderCreate) { mVold->mountIncFsSuccess(); mVold->mountIncFsSuccess(); mIncFs->makeFileSuccess(); mIncFs->makeFileSuccess(); mVold->bindMountSuccess(); mVold->bindMountSuccess(); mDataLoaderManager->initializeDataLoaderSuccess(); mDataLoaderManager->initializeDataLoaderSuccess(); mDataLoaderManager->getDataLoaderSuccess(); mDataLoaderManager->getDataLoaderSuccess(); EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_)); 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); EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2); TemporaryDir tempDir; TemporaryDir tempDir; int storageId = int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, IncrementalService::CreateOptions::CreateNew); IncrementalService::CreateOptions::CreateNew); ASSERT_GE(storageId, 0); ASSERT_GE(storageId, 0); mDataLoaderManager->setDataLoaderStatusReady(); ASSERT_TRUE(mIncrementalService->startLoading(storageId)); ASSERT_TRUE(mIncrementalService->startLoading(storageId)); mDataLoaderManager->setDataLoaderStatusCreated(); } } TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccess) { TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccess) { Loading