• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "utility.h"
38 
39 using namespace android::dm;
40 using namespace std::literals;
41 using android::base::unique_fd;
42 using android::fiemap::ImageManager;
43 using android::fiemap::IsSubdir;
44 using android::fs_mgr::BlockDeviceInfo;
45 using android::fs_mgr::PartitionOpener;
46 using android::fs_mgr::WaitForFile;
47 
48 static std::string gDataPath;
49 static std::string gDataMountPath;
50 static constexpr char kMetadataPath[] = "/metadata/gsi/test";
51 
52 static constexpr uint64_t kTestImageSize = 1024 * 1024;
53 
54 class TestPartitionOpener final : public PartitionOpener {
55   public:
Open(const std::string & partition_name,int flags) const56     android::base::unique_fd Open(const std::string& partition_name, int flags) const override {
57         return PartitionOpener::Open(GetPathForBlockDeviceName(partition_name), flags);
58     }
GetInfo(const std::string & partition_name,BlockDeviceInfo * info) const59     bool GetInfo(const std::string& partition_name, BlockDeviceInfo* info) const override {
60         return PartitionOpener::GetInfo(GetPathForBlockDeviceName(partition_name), info);
61     }
GetDeviceString(const std::string & partition_name) const62     std::string GetDeviceString(const std::string& partition_name) const override {
63         return PartitionOpener::GetDeviceString(GetPathForBlockDeviceName(partition_name));
64     }
65 
66   private:
GetPathForBlockDeviceName(const std::string & name)67     static std::string GetPathForBlockDeviceName(const std::string& name) {
68         if (android::base::StartsWith(name, "loop") || android::base::StartsWith(name, "dm-")) {
69             return "/dev/block/"s + name;
70         }
71         return name;
72     }
73 };
74 
75 // This fixture is for tests against the device's native configuration.
76 class NativeTest : public ::testing::Test {
77   protected:
SetUp()78     void SetUp() override {
79         manager_ = ImageManager::Open(kMetadataPath, gDataPath);
80         ASSERT_NE(manager_, nullptr);
81 
82         manager_->set_partition_opener(std::make_unique<TestPartitionOpener>());
83 
84         const ::testing::TestInfo* tinfo = ::testing::UnitTest::GetInstance()->current_test_info();
85         base_name_ = tinfo->name();
86     }
87 
TearDown()88     void TearDown() override {
89         manager_->UnmapImageDevice(base_name_);
90         manager_->DeleteBackingImage(base_name_);
91     }
92 
PropertyName()93     std::string PropertyName() { return "gsid.mapped_image." + base_name_; }
94 
95     std::unique_ptr<ImageManager> manager_;
96     std::string base_name_;
97 };
98 
TEST_F(NativeTest,CreateAndMap)99 TEST_F(NativeTest, CreateAndMap) {
100     ASSERT_TRUE(manager_->CreateBackingImage(base_name_, kTestImageSize, false, nullptr));
101 
102     std::string path;
103     ASSERT_TRUE(manager_->MapImageDevice(base_name_, 5s, &path));
104     ASSERT_TRUE(manager_->IsImageMapped(base_name_));
105     ASSERT_EQ(android::base::GetProperty(PropertyName(), ""), path);
106 
107     {
108         unique_fd fd(open(path.c_str(), O_RDWR | O_NOFOLLOW | O_CLOEXEC));
109         ASSERT_GE(fd, 0);
110         ASSERT_EQ(get_block_device_size(fd), kTestImageSize);
111     }
112 
113     ASSERT_TRUE(manager_->UnmapImageDevice(base_name_));
114     ASSERT_FALSE(manager_->IsImageMapped(base_name_));
115     ASSERT_EQ(android::base::GetProperty(PropertyName(), ""), "");
116 }
117 
TEST_F(NativeTest,DisableImage)118 TEST_F(NativeTest, DisableImage) {
119     ASSERT_TRUE(manager_->CreateBackingImage(base_name_, kTestImageSize, false, nullptr));
120     ASSERT_TRUE(manager_->BackingImageExists(base_name_));
121     ASSERT_TRUE(manager_->DisableImage(base_name_));
122     ASSERT_TRUE(manager_->IsImageDisabled(base_name_));
123     ASSERT_TRUE(manager_->RemoveDisabledImages());
124     ASSERT_TRUE(!manager_->BackingImageExists(base_name_));
125 }
126 
TEST_F(NativeTest,GetMappedImageDevice)127 TEST_F(NativeTest, GetMappedImageDevice) {
128     ASSERT_TRUE(manager_->CreateBackingImage(base_name_, kTestImageSize, false, nullptr));
129 
130     std::string path1, path2;
131     ASSERT_TRUE(manager_->MapImageDevice(base_name_, 5s, &path1));
132     ASSERT_TRUE(manager_->GetMappedImageDevice(base_name_, &path2));
133     EXPECT_EQ(path1, path2);
134 
135     ASSERT_TRUE(manager_->UnmapImageDevice(base_name_));
136 }
137 
138 namespace {
139 
140 struct IsSubdirTestParam {
141     std::string child;
142     std::string parent;
143     bool result;
144 };
145 
146 class IsSubdirTest : public ::testing::TestWithParam<IsSubdirTestParam> {};
147 
TEST_P(IsSubdirTest,Test)148 TEST_P(IsSubdirTest, Test) {
149     const auto& param = GetParam();
150     EXPECT_EQ(param.result, IsSubdir(param.child, param.parent))
151             << "IsSubdir(child=\"" << param.child << "\", parent=\"" << param.parent
152             << "\") != " << (param.result ? "true" : "false");
153 }
154 
IsSubdirTestValues()155 std::vector<IsSubdirTestParam> IsSubdirTestValues() {
156     // clang-format off
157     std::vector<IsSubdirTestParam> base_cases{
158             {"/foo/bar",     "/foo",     true},
159             {"/foo/bar/baz", "/foo",     true},
160             {"/foo",         "/foo",     true},
161             {"/foo",         "/",        true},
162             {"/",            "/",        true},
163             {"/foo",         "/foo/bar", false},
164             {"/foo",         "/bar",     false},
165             {"/foo-bar",     "/foo",     false},
166             {"/",            "/foo",     false},
167     };
168     // clang-format on
169     std::vector<IsSubdirTestParam> ret;
170     for (const auto& e : base_cases) {
171         ret.push_back(e);
172         ret.push_back({e.child + "/", e.parent, e.result});
173         ret.push_back({e.child, e.parent + "/", e.result});
174         ret.push_back({e.child + "/", e.parent + "/", e.result});
175     }
176     return ret;
177 }
178 
179 INSTANTIATE_TEST_SUITE_P(IsSubdirTest, IsSubdirTest, ::testing::ValuesIn(IsSubdirTestValues()));
180 
181 }  // namespace
182 
Mkdir(const std::string & path)183 bool Mkdir(const std::string& path) {
184     if (mkdir(path.c_str(), 0700) && errno != EEXIST) {
185         std::cerr << "Could not mkdir " << path << ": " << strerror(errno) << std::endl;
186         return false;
187     }
188     return true;
189 }
190 
main(int argc,char ** argv)191 int main(int argc, char** argv) {
192     ::testing::InitGoogleTest(&argc, argv);
193 
194     if (argc >= 2) {
195         gDataPath = argv[1];
196     } else {
197         gDataPath = "/data/gsi/test";
198     }
199     gDataMountPath = gDataPath + "/mnt"s;
200 
201     if (!Mkdir(gDataPath) || !Mkdir(kMetadataPath) || !Mkdir(gDataMountPath) ||
202         !Mkdir(kMetadataPath + "/mnt"s)) {
203         return 1;
204     }
205     return RUN_ALL_TESTS();
206 }
207