blob: ca1e1a97204789c57cea2fbfa730af2922f9e5d5 [file] [log] [blame]
Songchun Fan3c82a302019-11-29 14:23:45 -08001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <android-base/file.h>
18#include <android-base/logging.h>
19#include <android-base/unique_fd.h>
20#include <binder/ParcelFileDescriptor.h>
21#include <gmock/gmock.h>
22#include <gtest/gtest.h>
23#include <utils/Log.h>
24
25#include <future>
26
27#include "IncrementalService.h"
28#include "Metadata.pb.h"
29#include "ServiceWrappers.h"
30
31using namespace testing;
32using namespace android::incremental;
33using namespace std::literals;
34using testing::_;
35using testing::Invoke;
36using testing::NiceMock;
37
38#undef LOG_TAG
39#define LOG_TAG "IncrementalServiceTest"
40
41using namespace android::incfs;
42using namespace android::content::pm;
43
44namespace android::os::incremental {
45
46class MockVoldService : public VoldServiceWrapper {
47public:
48 MOCK_CONST_METHOD4(mountIncFs,
49 binder::Status(const std::string& imagePath, const std::string& targetDir,
50 int32_t flags,
51 IncrementalFileSystemControlParcel* _aidl_return));
52 MOCK_CONST_METHOD1(unmountIncFs, binder::Status(const std::string& dir));
53 MOCK_CONST_METHOD2(bindMount,
54 binder::Status(const std::string& sourceDir, const std::string& argetDir));
55
56 void mountIncFsFails() {
57 ON_CALL(*this, mountIncFs(_, _, _, _))
58 .WillByDefault(
59 Return(binder::Status::fromExceptionCode(1, String8("failed to mount"))));
60 }
61 void mountIncFsInvalidControlParcel() {
62 ON_CALL(*this, mountIncFs(_, _, _, _))
63 .WillByDefault(Invoke(this, &MockVoldService::getInvalidControlParcel));
64 }
65 void mountIncFsSuccess() {
66 ON_CALL(*this, mountIncFs(_, _, _, _))
67 .WillByDefault(Invoke(this, &MockVoldService::incFsSuccess));
68 }
69 void bindMountFails() {
70 ON_CALL(*this, bindMount(_, _))
71 .WillByDefault(Return(
72 binder::Status::fromExceptionCode(1, String8("failed to bind-mount"))));
73 }
74 void bindMountSuccess() {
75 ON_CALL(*this, bindMount(_, _)).WillByDefault(Return(binder::Status::ok()));
76 }
77 binder::Status getInvalidControlParcel(const std::string& imagePath,
78 const std::string& targetDir, int32_t flags,
79 IncrementalFileSystemControlParcel* _aidl_return) {
80 _aidl_return->cmd = nullptr;
81 _aidl_return->log = nullptr;
82 return binder::Status::ok();
83 }
84 binder::Status incFsSuccess(const std::string& imagePath, const std::string& targetDir,
85 int32_t flags, IncrementalFileSystemControlParcel* _aidl_return) {
86 _aidl_return->cmd = std::make_unique<os::ParcelFileDescriptor>(std::move(cmdFd));
87 _aidl_return->log = std::make_unique<os::ParcelFileDescriptor>(std::move(logFd));
88 return binder::Status::ok();
89 }
90
91private:
92 TemporaryFile cmdFile;
93 TemporaryFile logFile;
94 base::unique_fd cmdFd;
95 base::unique_fd logFd;
96};
97
98class MockIncrementalManager : public IncrementalManagerWrapper {
99public:
100 MOCK_CONST_METHOD5(prepareDataLoader,
101 binder::Status(int32_t mountId, const FileSystemControlParcel& control,
102 const DataLoaderParamsParcel& params,
103 const sp<IDataLoaderStatusListener>& listener,
104 bool* _aidl_return));
105 MOCK_CONST_METHOD2(startDataLoader, binder::Status(int32_t mountId, bool* _aidl_return));
106 MOCK_CONST_METHOD1(destroyDataLoader, binder::Status(int32_t mountId));
107 MOCK_CONST_METHOD3(newFileForDataLoader,
108 binder::Status(int32_t mountId, int64_t inode,
109 const ::std::vector<uint8_t>& metadata));
110 MOCK_CONST_METHOD1(showHealthBlockedUI, binder::Status(int32_t mountId));
111
112 binder::Status prepareDataLoaderOk(int32_t mountId, const FileSystemControlParcel& control,
113 const DataLoaderParamsParcel& params,
114 const sp<IDataLoaderStatusListener>& listener,
115 bool* _aidl_return) {
116 mId = mountId;
117 mListener = listener;
118 *_aidl_return = true;
119 return binder::Status::ok();
120 }
121
122 binder::Status startDataLoaderOk(int32_t mountId, bool* _aidl_return) {
123 *_aidl_return = true;
124 return binder::Status::ok();
125 }
126
127 void prepareDataLoaderFails() {
128 ON_CALL(*this, prepareDataLoader(_, _, _, _, _))
129 .WillByDefault(Return(
130 (binder::Status::fromExceptionCode(1, String8("failed to prepare")))));
131 }
132 void prepareDataLoaderSuccess() {
133 ON_CALL(*this, prepareDataLoader(_, _, _, _, _))
134 .WillByDefault(Invoke(this, &MockIncrementalManager::prepareDataLoaderOk));
135 }
136 void startDataLoaderSuccess() {
137 ON_CALL(*this, startDataLoader(_, _))
138 .WillByDefault(Invoke(this, &MockIncrementalManager::startDataLoaderOk));
139 }
140 void setDataLoaderStatusNotReady() {
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800141 mListener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_DESTROYED);
Songchun Fan3c82a302019-11-29 14:23:45 -0800142 }
143 void setDataLoaderStatusReady() {
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800144 mListener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_CREATED);
Songchun Fan3c82a302019-11-29 14:23:45 -0800145 }
146
147private:
148 int mId;
149 sp<IDataLoaderStatusListener> mListener;
150};
151
152class MockIncFs : public IncFsWrapper {
153public:
154 MOCK_CONST_METHOD5(makeFile,
155 Inode(Control control, std::string_view name, Inode parent, Size size,
156 std::string_view metadata));
157 MOCK_CONST_METHOD5(makeDir,
158 Inode(Control control, std::string_view name, Inode parent,
159 std::string_view metadata, int mode));
160 MOCK_CONST_METHOD2(getMetadata, RawMetadata(Control control, Inode inode));
161 MOCK_CONST_METHOD4(link,
162 ErrorCode(Control control, Inode item, Inode targetParent,
163 std::string_view name));
164 MOCK_CONST_METHOD3(unlink, ErrorCode(Control control, Inode parent, std::string_view name));
165 MOCK_CONST_METHOD3(writeBlocks,
166 ErrorCode(Control control, const incfs_new_data_block blocks[],
167 int blocksCount));
168
169 void makeFileFails() { ON_CALL(*this, makeFile(_, _, _, _, _)).WillByDefault(Return(-1)); }
170 void makeFileSuccess() { ON_CALL(*this, makeFile(_, _, _, _, _)).WillByDefault(Return(0)); }
171 RawMetadata getMountInfoMetadata(Control control, Inode inode) {
172 metadata::Mount m;
173 m.mutable_storage()->set_id(100);
174 m.mutable_loader()->set_package_name("com.test");
175 m.mutable_loader()->set_arguments("com.uri");
176 const auto metadata = m.SerializeAsString();
177 m.mutable_loader()->release_arguments();
178 m.mutable_loader()->release_package_name();
179 return std::vector<char>(metadata.begin(), metadata.end());
180 }
181 RawMetadata getStorageMetadata(Control control, Inode inode) {
182 metadata::Storage st;
183 st.set_id(100);
184 auto metadata = st.SerializeAsString();
185 return std::vector<char>(metadata.begin(), metadata.end());
186 }
187 RawMetadata getBindPointMetadata(Control control, Inode inode) {
188 metadata::BindPoint bp;
189 std::string destPath = "dest";
190 std::string srcPath = "src";
191 bp.set_storage_id(100);
192 bp.set_allocated_dest_path(&destPath);
193 bp.set_allocated_source_subdir(&srcPath);
194 const auto metadata = bp.SerializeAsString();
195 bp.release_source_subdir();
196 bp.release_dest_path();
197 return std::vector<char>(metadata.begin(), metadata.end());
198 }
199};
200
201class MockServiceManager : public ServiceManagerWrapper {
202public:
203 MockServiceManager(std::shared_ptr<MockVoldService> vold,
204 std::shared_ptr<MockIncrementalManager> manager,
205 std::shared_ptr<MockIncFs> incfs)
206 : mVold(vold), mIncrementalManager(manager), mIncFs(incfs) {}
207 std::shared_ptr<VoldServiceWrapper> getVoldService() const override { return mVold; }
208 std::shared_ptr<IncrementalManagerWrapper> getIncrementalManager() const override {
209 return mIncrementalManager;
210 }
211 std::shared_ptr<IncFsWrapper> getIncFs() const override { return mIncFs; }
212
213private:
214 std::shared_ptr<MockVoldService> mVold;
215 std::shared_ptr<MockIncrementalManager> mIncrementalManager;
216 std::shared_ptr<MockIncFs> mIncFs;
217};
218
219// --- IncrementalServiceTest ---
220
221static Inode inode(std::string_view path) {
222 struct stat st;
223 if (::stat(path::c_str(path), &st)) {
224 return -1;
225 }
226 return st.st_ino;
227}
228
229class IncrementalServiceTest : public testing::Test {
230public:
231 void SetUp() override {
232 mVold = std::make_shared<NiceMock<MockVoldService>>();
233 mIncrementalManager = std::make_shared<NiceMock<MockIncrementalManager>>();
234 mIncFs = std::make_shared<NiceMock<MockIncFs>>();
235 MockServiceManager serviceManager = MockServiceManager(mVold, mIncrementalManager, mIncFs);
236 mIncrementalService = std::make_unique<IncrementalService>(serviceManager, mRootDir.path);
237 mDataLoaderParcel.packageName = "com.test";
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800238 mDataLoaderParcel.arguments = "uri";
Songchun Fan3c82a302019-11-29 14:23:45 -0800239 mIncrementalService->onSystemReady();
240 }
241
242 void setUpExistingMountDir(const std::string& rootDir) {
243 const auto dir = rootDir + "/dir1";
244 const auto mountDir = dir + "/mount";
245 const auto backingDir = dir + "/backing_store";
246 const auto storageDir = mountDir + "/st0";
247 ASSERT_EQ(0, mkdir(dir.c_str(), 0755));
248 ASSERT_EQ(0, mkdir(mountDir.c_str(), 0755));
249 ASSERT_EQ(0, mkdir(backingDir.c_str(), 0755));
250 ASSERT_EQ(0, mkdir(storageDir.c_str(), 0755));
251 const auto mountInfoFile = rootDir + "/dir1/mount/.info";
252 const auto mountPointsFile = rootDir + "/dir1/mount/.mountpoint.abcd";
253 ASSERT_TRUE(base::WriteStringToFile("info", mountInfoFile));
254 ASSERT_TRUE(base::WriteStringToFile("mounts", mountPointsFile));
255 ASSERT_GE(inode(mountInfoFile), 0);
256 ASSERT_GE(inode(mountPointsFile), 0);
257 ON_CALL(*mIncFs, getMetadata(_, inode(mountInfoFile)))
258 .WillByDefault(Invoke(mIncFs.get(), &MockIncFs::getMountInfoMetadata));
259 ON_CALL(*mIncFs, getMetadata(_, inode(mountPointsFile)))
260 .WillByDefault(Invoke(mIncFs.get(), &MockIncFs::getBindPointMetadata));
261 ON_CALL(*mIncFs, getMetadata(_, inode(rootDir + "/dir1/mount/st0")))
262 .WillByDefault(Invoke(mIncFs.get(), &MockIncFs::getStorageMetadata));
263 }
264
265protected:
266 std::shared_ptr<NiceMock<MockVoldService>> mVold;
267 std::shared_ptr<NiceMock<MockIncFs>> mIncFs;
268 std::shared_ptr<NiceMock<MockIncrementalManager>> mIncrementalManager;
269 std::unique_ptr<IncrementalService> mIncrementalService;
270 TemporaryDir mRootDir;
271 DataLoaderParamsParcel mDataLoaderParcel;
272};
273
274/*
275TEST_F(IncrementalServiceTest, testBootMountExistingImagesSuccess) {
276 TemporaryDir tempDir;
277 setUpExistingMountDir(tempDir.path);
278 mVold->mountIncFsSuccess();
279 mVold->bindMountSuccess();
280 mIncrementalManager->prepareDataLoaderSuccess();
281 ON_CALL(*mIncrementalManager, destroyDataLoader(_)).WillByDefault(Return(binder::Status::ok()));
282
283 EXPECT_CALL(*mVold, mountIncFs(_, _, _, _)).Times(1);
284 EXPECT_CALL(*mIncrementalManager, prepareDataLoader(_, _, _, _, _)).Times(1);
285
286 MockServiceManager serviceManager = MockServiceManager(mVold, mIncrementalManager, mIncFs);
287 std::unique_ptr<IncrementalService> incrementalService =
288 std::make_unique<IncrementalService>(serviceManager, tempDir.path);
289 auto finished = incrementalService->onSystemReady();
290 if (finished) {
291 finished->wait();
292 }
293}
294*/
295
296TEST_F(IncrementalServiceTest, testCreateStorageMountIncFsFails) {
297 mVold->mountIncFsFails();
298 EXPECT_CALL(*mIncrementalManager, prepareDataLoader(_, _, _, _, _)).Times(0);
299 TemporaryDir tempDir;
300 int storageId =
301 mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
302 IncrementalService::CreateOptions::CreateNew);
303 ASSERT_LT(storageId, 0);
304}
305
306TEST_F(IncrementalServiceTest, testCreateStorageMountIncFsInvalidControlParcel) {
307 mVold->mountIncFsInvalidControlParcel();
308 EXPECT_CALL(*mIncrementalManager, prepareDataLoader(_, _, _, _, _)).Times(0);
309 TemporaryDir tempDir;
310 int storageId =
311 mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
312 IncrementalService::CreateOptions::CreateNew);
313 ASSERT_LT(storageId, 0);
314}
315
316TEST_F(IncrementalServiceTest, testCreateStorageMakeFileFails) {
317 mVold->mountIncFsSuccess();
318 mIncFs->makeFileFails();
319 EXPECT_CALL(*mIncrementalManager, prepareDataLoader(_, _, _, _, _)).Times(0);
320 EXPECT_CALL(*mIncrementalManager, destroyDataLoader(_));
321 EXPECT_CALL(*mVold, unmountIncFs(_));
322 TemporaryDir tempDir;
323 int storageId =
324 mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
325 IncrementalService::CreateOptions::CreateNew);
326 ASSERT_LT(storageId, 0);
327}
328
329TEST_F(IncrementalServiceTest, testCreateStorageBindMountFails) {
330 mVold->mountIncFsSuccess();
331 mIncFs->makeFileSuccess();
332 mVold->bindMountFails();
333 EXPECT_CALL(*mIncrementalManager, prepareDataLoader(_, _, _, _, _)).Times(0);
334 EXPECT_CALL(*mIncrementalManager, destroyDataLoader(_));
335 EXPECT_CALL(*mVold, unmountIncFs(_));
336 TemporaryDir tempDir;
337 int storageId =
338 mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
339 IncrementalService::CreateOptions::CreateNew);
340 ASSERT_LT(storageId, 0);
341}
342
343TEST_F(IncrementalServiceTest, testCreateStoragePrepareDataLoaderFails) {
344 mVold->mountIncFsSuccess();
345 mIncFs->makeFileSuccess();
346 mVold->bindMountSuccess();
347 mIncrementalManager->prepareDataLoaderFails();
348 EXPECT_CALL(*mIncrementalManager, destroyDataLoader(_));
349 EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
350 TemporaryDir tempDir;
351 int storageId =
352 mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
353 IncrementalService::CreateOptions::CreateNew);
354 ASSERT_LT(storageId, 0);
355}
356
357TEST_F(IncrementalServiceTest, testDeleteStorageSuccess) {
358 mVold->mountIncFsSuccess();
359 mIncFs->makeFileSuccess();
360 mVold->bindMountSuccess();
361 mIncrementalManager->prepareDataLoaderSuccess();
362 EXPECT_CALL(*mIncrementalManager, destroyDataLoader(_));
363 EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
364 TemporaryDir tempDir;
365 int storageId =
366 mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
367 IncrementalService::CreateOptions::CreateNew);
368 ASSERT_GE(storageId, 0);
369 mIncrementalService->deleteStorage(storageId);
370}
371
372TEST_F(IncrementalServiceTest, testOnStatusNotReady) {
373 mVold->mountIncFsSuccess();
374 mIncFs->makeFileSuccess();
375 mVold->bindMountSuccess();
376 mIncrementalManager->prepareDataLoaderSuccess();
377 EXPECT_CALL(*mIncrementalManager, destroyDataLoader(_));
378 EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
379 TemporaryDir tempDir;
380 int storageId =
381 mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
382 IncrementalService::CreateOptions::CreateNew);
383 ASSERT_GE(storageId, 0);
384 mIncrementalManager->setDataLoaderStatusNotReady();
385}
386
387TEST_F(IncrementalServiceTest, testStartDataLoaderSuccess) {
388 mVold->mountIncFsSuccess();
389 mIncFs->makeFileSuccess();
390 mVold->bindMountSuccess();
391 mIncrementalManager->prepareDataLoaderSuccess();
392 mIncrementalManager->startDataLoaderSuccess();
393 EXPECT_CALL(*mIncrementalManager, destroyDataLoader(_));
394 EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
395 TemporaryDir tempDir;
396 int storageId =
397 mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
398 IncrementalService::CreateOptions::CreateNew);
399 ASSERT_GE(storageId, 0);
400 mIncrementalManager->setDataLoaderStatusReady();
401 ASSERT_TRUE(mIncrementalService->startLoading(storageId));
402}
403
404TEST_F(IncrementalServiceTest, testMakeDirectory) {
405 mVold->mountIncFsSuccess();
406 mIncFs->makeFileSuccess();
407 mVold->bindMountSuccess();
408 mIncrementalManager->prepareDataLoaderSuccess();
409 mIncrementalManager->startDataLoaderSuccess();
410 TemporaryDir tempDir;
411 int storageId =
412 mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
413 IncrementalService::CreateOptions::CreateNew);
414 std::string_view dir_path("test");
415 EXPECT_CALL(*mIncFs, makeDir(_, dir_path, _, _, _));
416 int fileIno = mIncrementalService->makeDir(storageId, dir_path, "");
417 ASSERT_GE(fileIno, 0);
418}
419
420TEST_F(IncrementalServiceTest, testMakeDirectoryNoParent) {
421 mVold->mountIncFsSuccess();
422 mIncFs->makeFileSuccess();
423 mVold->bindMountSuccess();
424 mIncrementalManager->prepareDataLoaderSuccess();
425 mIncrementalManager->startDataLoaderSuccess();
426 TemporaryDir tempDir;
427 int storageId =
428 mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
429 IncrementalService::CreateOptions::CreateNew);
430 std::string_view first("first");
431 std::string_view second("second");
432 std::string dir_path = std::string(first) + "/" + std::string(second);
433 EXPECT_CALL(*mIncFs, makeDir(_, first, _, _, _)).Times(0);
434 EXPECT_CALL(*mIncFs, makeDir(_, second, _, _, _)).Times(0);
435 int fileIno = mIncrementalService->makeDir(storageId, dir_path, "");
436 ASSERT_LT(fileIno, 0);
437}
438
439TEST_F(IncrementalServiceTest, testMakeDirectories) {
440 mVold->mountIncFsSuccess();
441 mIncFs->makeFileSuccess();
442 mVold->bindMountSuccess();
443 mIncrementalManager->prepareDataLoaderSuccess();
444 mIncrementalManager->startDataLoaderSuccess();
445 TemporaryDir tempDir;
446 int storageId =
447 mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
448 IncrementalService::CreateOptions::CreateNew);
449 std::string_view first("first");
450 std::string_view second("second");
451 std::string_view third("third");
452 InSequence seq;
453 EXPECT_CALL(*mIncFs, makeDir(_, first, _, _, _));
454 EXPECT_CALL(*mIncFs, makeDir(_, second, _, _, _));
455 EXPECT_CALL(*mIncFs, makeDir(_, third, _, _, _));
456 std::string dir_path =
457 std::string(first) + "/" + std::string(second) + "/" + std::string(third);
458 int fileIno = mIncrementalService->makeDirs(storageId, dir_path, "");
459 ASSERT_GE(fileIno, 0);
460}
461} // namespace android::os::incremental