1 //
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 <stdlib.h>
18 #include <string.h>
19 #include <sys/mount.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22
23 #include <chrono>
24 #include <iostream>
25 #include <thread>
26
27 #include <android-base/file.h>
28 #include <android-base/properties.h>
29 #include <android-base/strings.h>
30 #include <android-base/unique_fd.h>
31 #include <ext4_utils/ext4_utils.h>
32 #include <fs_mgr/file_wait.h>
33 #include <gtest/gtest.h>
34 #include <libdm/dm.h>
35 #include <libfiemap/image_manager.h>
36
37 using namespace android::dm;
38 using namespace std::literals;
39 using android::base::unique_fd;
40 using android::fiemap::ImageManager;
41 using android::fs_mgr::BlockDeviceInfo;
42 using android::fs_mgr::PartitionOpener;
43 using android::fs_mgr::WaitForFile;
44
45 static std::string gDataPath;
46 static std::string gDataMountPath;
47 static constexpr char kMetadataPath[] = "/metadata/gsi/test";
48
49 static constexpr uint64_t kTestImageSize = 1024 * 1024;
50
51 class TestPartitionOpener final : public PartitionOpener {
52 public:
Open(const std::string & partition_name,int flags) const53 android::base::unique_fd Open(const std::string& partition_name, int flags) const override {
54 return PartitionOpener::Open(GetPathForBlockDeviceName(partition_name), flags);
55 }
GetInfo(const std::string & partition_name,BlockDeviceInfo * info) const56 bool GetInfo(const std::string& partition_name, BlockDeviceInfo* info) const override {
57 return PartitionOpener::GetInfo(GetPathForBlockDeviceName(partition_name), info);
58 }
GetDeviceString(const std::string & partition_name) const59 std::string GetDeviceString(const std::string& partition_name) const override {
60 return PartitionOpener::GetDeviceString(GetPathForBlockDeviceName(partition_name));
61 }
62
63 private:
GetPathForBlockDeviceName(const std::string & name)64 static std::string GetPathForBlockDeviceName(const std::string& name) {
65 if (android::base::StartsWith(name, "loop") || android::base::StartsWith(name, "dm-")) {
66 return "/dev/block/"s + name;
67 }
68 return name;
69 }
70 };
71
72 // This fixture is for tests against the device's native configuration.
73 class NativeTest : public ::testing::Test {
74 protected:
SetUp()75 void SetUp() override {
76 manager_ = ImageManager::Open(kMetadataPath, gDataPath);
77 ASSERT_NE(manager_, nullptr);
78
79 manager_->set_partition_opener(std::make_unique<TestPartitionOpener>());
80
81 const ::testing::TestInfo* tinfo = ::testing::UnitTest::GetInstance()->current_test_info();
82 base_name_ = tinfo->name();
83 }
84
TearDown()85 void TearDown() override {
86 manager_->UnmapImageDevice(base_name_);
87 manager_->DeleteBackingImage(base_name_);
88 }
89
PropertyName()90 std::string PropertyName() { return "gsid.mapped_image." + base_name_; }
91
92 std::unique_ptr<ImageManager> manager_;
93 std::string base_name_;
94 };
95
TEST_F(NativeTest,CreateAndMap)96 TEST_F(NativeTest, CreateAndMap) {
97 ASSERT_TRUE(manager_->CreateBackingImage(base_name_, kTestImageSize, false, nullptr));
98
99 std::string path;
100 ASSERT_TRUE(manager_->MapImageDevice(base_name_, 5s, &path));
101 ASSERT_TRUE(manager_->IsImageMapped(base_name_));
102 ASSERT_EQ(android::base::GetProperty(PropertyName(), ""), path);
103
104 {
105 unique_fd fd(open(path.c_str(), O_RDWR | O_NOFOLLOW | O_CLOEXEC));
106 ASSERT_GE(fd, 0);
107 ASSERT_EQ(get_block_device_size(fd), kTestImageSize);
108 }
109
110 ASSERT_TRUE(manager_->UnmapImageDevice(base_name_));
111 ASSERT_FALSE(manager_->IsImageMapped(base_name_));
112 ASSERT_EQ(android::base::GetProperty(PropertyName(), ""), "");
113 }
114
TEST_F(NativeTest,DisableImage)115 TEST_F(NativeTest, DisableImage) {
116 ASSERT_TRUE(manager_->CreateBackingImage(base_name_, kTestImageSize, false, nullptr));
117 ASSERT_TRUE(manager_->BackingImageExists(base_name_));
118 ASSERT_TRUE(manager_->DisableImage(base_name_));
119 ASSERT_TRUE(manager_->RemoveDisabledImages());
120 ASSERT_TRUE(!manager_->BackingImageExists(base_name_));
121 }
122
TEST_F(NativeTest,GetMappedImageDevice)123 TEST_F(NativeTest, GetMappedImageDevice) {
124 ASSERT_TRUE(manager_->CreateBackingImage(base_name_, kTestImageSize, false, nullptr));
125
126 std::string path1, path2;
127 ASSERT_TRUE(manager_->MapImageDevice(base_name_, 5s, &path1));
128 ASSERT_TRUE(manager_->GetMappedImageDevice(base_name_, &path2));
129 EXPECT_EQ(path1, path2);
130
131 ASSERT_TRUE(manager_->UnmapImageDevice(base_name_));
132 }
133
Mkdir(const std::string & path)134 bool Mkdir(const std::string& path) {
135 if (mkdir(path.c_str(), 0700) && errno != EEXIST) {
136 std::cerr << "Could not mkdir " << path << ": " << strerror(errno) << std::endl;
137 return false;
138 }
139 return true;
140 }
141
main(int argc,char ** argv)142 int main(int argc, char** argv) {
143 ::testing::InitGoogleTest(&argc, argv);
144
145 if (argc >= 2) {
146 gDataPath = argv[1];
147 } else {
148 gDataPath = "/data/gsi/test";
149 }
150 gDataMountPath = gDataPath + "/mnt"s;
151
152 if (!Mkdir(gDataPath) || !Mkdir(kMetadataPath) || !Mkdir(gDataMountPath) ||
153 !Mkdir(kMetadataPath + "/mnt"s)) {
154 return 1;
155 }
156 return RUN_ALL_TESTS();
157 }
158