1 /*
2 * Copyright (C) 2018 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 /*
18 * The tests in this file operate on a higher level than the tests in the other
19 * files. Here, all tests execute the idmap2 binary and only depend on
20 * libidmap2 to verify the output of idmap2.
21 */
22 #include <fcntl.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include <sys/wait.h>
26 #include <unistd.h>
27
28 #include <cerrno>
29 #include <cstdlib>
30 #include <cstring> // strerror
31 #include <fstream>
32 #include <memory>
33 #include <sstream>
34 #include <string>
35 #include <vector>
36
37 #include "R.h"
38 #include "TestConstants.h"
39 #include "TestHelpers.h"
40 #include "androidfw/PosixUtils.h"
41 #include "gmock/gmock.h"
42 #include "gtest/gtest.h"
43 #include "idmap2/FileUtils.h"
44 #include "idmap2/Idmap.h"
45 #include "private/android_filesystem_config.h"
46
47 using ::android::base::StringPrintf;
48 using ::android::util::ExecuteBinary;
49
50 namespace android::idmap2 {
51
52 class Idmap2BinaryTests : public Idmap2Tests {};
53
54 namespace {
55
AssertIdmap(const Idmap & idmap,const std::string & target_apk_path,const std::string & overlay_apk_path)56 void AssertIdmap(const Idmap& idmap, const std::string& target_apk_path,
57 const std::string& overlay_apk_path) {
58 // check that the idmap file looks reasonable (IdmapTests is responsible for
59 // more in-depth verification)
60 ASSERT_EQ(idmap.GetHeader()->GetMagic(), kIdmapMagic);
61 ASSERT_EQ(idmap.GetHeader()->GetVersion(), kIdmapCurrentVersion);
62 ASSERT_EQ(idmap.GetHeader()->GetTargetPath(), target_apk_path);
63 ASSERT_EQ(idmap.GetHeader()->GetOverlayPath(), overlay_apk_path);
64 ASSERT_EQ(idmap.GetData().size(), 1U);
65 }
66
67 #define ASSERT_IDMAP(idmap_ref, target_apk_path, overlay_apk_path) \
68 do { \
69 ASSERT_NO_FATAL_FAILURE(AssertIdmap(idmap_ref, target_apk_path, overlay_apk_path)); \
70 } while (0)
71
72 #ifdef __ANDROID__
73 #define SKIP_TEST_IF_CANT_EXEC_IDMAP2 \
74 do { \
75 const uid_t uid = getuid(); \
76 if (uid != AID_ROOT && uid != AID_SYSTEM) { \
77 GTEST_SKIP(); \
78 } \
79 } while (0)
80 #else
81 #define SKIP_TEST_IF_CANT_EXEC_IDMAP2
82 #endif
83
84 } // namespace
85
TEST_F(Idmap2BinaryTests,Create)86 TEST_F(Idmap2BinaryTests, Create) {
87 SKIP_TEST_IF_CANT_EXEC_IDMAP2;
88
89 // clang-format off
90 auto result = ExecuteBinary({"idmap2",
91 "create",
92 "--target-apk-path", GetTargetApkPath(),
93 "--overlay-apk-path", GetOverlayApkPath(),
94 "--overlay-name", TestConstants::OVERLAY_NAME_DEFAULT,
95 "--idmap-path", GetIdmapPath()});
96 // clang-format on
97 ASSERT_TRUE((bool)result);
98 ASSERT_EQ(result.status, EXIT_SUCCESS) << result.stderr_str;
99
100 struct stat st;
101 ASSERT_EQ(stat(GetIdmapPath().c_str(), &st), 0);
102
103 std::ifstream fin(GetIdmapPath());
104 const auto idmap = Idmap::FromBinaryStream(fin);
105 fin.close();
106
107 ASSERT_TRUE(idmap);
108 ASSERT_IDMAP(**idmap, GetTargetApkPath(), GetOverlayApkPath());
109
110 unlink(GetIdmapPath().c_str());
111 }
112
TEST_F(Idmap2BinaryTests,Dump)113 TEST_F(Idmap2BinaryTests, Dump) {
114 SKIP_TEST_IF_CANT_EXEC_IDMAP2;
115
116 // clang-format off
117 auto result = ExecuteBinary({"idmap2",
118 "create",
119 "--target-apk-path", GetTargetApkPath(),
120 "--overlay-apk-path", GetOverlayApkPath(),
121 "--overlay-name", TestConstants::OVERLAY_NAME_DEFAULT,
122 "--idmap-path", GetIdmapPath()});
123 // clang-format on
124 ASSERT_TRUE((bool)result);
125 ASSERT_EQ(result.status, EXIT_SUCCESS) << result.stderr_str;
126
127 // clang-format off
128 result = ExecuteBinary({"idmap2",
129 "dump",
130 "--idmap-path", GetIdmapPath()});
131 // clang-format on
132 ASSERT_TRUE((bool)result);
133 ASSERT_EQ(result.status, EXIT_SUCCESS) << result.stderr_str;
134
135 ASSERT_NE(result.stdout_str.find(StringPrintf("0x%08x -> 0x%08x", R::target::integer::int1,
136 R::overlay::integer::int1)),
137 std::string::npos)
138 << result.stdout_str;
139 ASSERT_NE(result.stdout_str.find(StringPrintf("0x%08x -> 0x%08x", R::target::string::str1,
140 R::overlay::string::str1)),
141 std::string::npos)
142 << result.stdout_str;
143 ASSERT_NE(result.stdout_str.find(StringPrintf("0x%08x -> 0x%08x", R::target::string::str3,
144 R::overlay::string::str3)),
145 std::string::npos)
146 << result.stdout_str;
147 ASSERT_NE(result.stdout_str.find(StringPrintf("0x%08x -> 0x%08x", R::target::string::str4,
148 R::overlay::string::str4)),
149 std::string::npos)
150 << result.stdout_str;
151
152 // clang-format off
153 result = ExecuteBinary({"idmap2",
154 "dump",
155 "--verbose",
156 "--idmap-path", GetIdmapPath()});
157 // clang-format on
158 ASSERT_TRUE((bool)result);
159 ASSERT_EQ(result.status, EXIT_SUCCESS) << result.stderr_str;
160 ASSERT_NE(result.stdout_str.find("00000000: 504d4449 magic"), std::string::npos);
161
162 // clang-format off
163 result = ExecuteBinary({"idmap2",
164 "dump",
165 "--verbose",
166 "--idmap-path", GetTestDataPath() + "/DOES-NOT-EXIST"});
167 // clang-format on
168 ASSERT_TRUE((bool)result);
169 ASSERT_NE(result.status, EXIT_SUCCESS);
170
171 unlink(GetIdmapPath().c_str());
172 }
173
TEST_F(Idmap2BinaryTests,Lookup)174 TEST_F(Idmap2BinaryTests, Lookup) {
175 SKIP_TEST_IF_CANT_EXEC_IDMAP2;
176
177 // clang-format off
178 auto result = ExecuteBinary({"idmap2",
179 "create",
180 "--target-apk-path", GetTargetApkPath(),
181 "--overlay-apk-path", GetOverlayApkPath(),
182 "--overlay-name", TestConstants::OVERLAY_NAME_DEFAULT,
183 "--idmap-path", GetIdmapPath()});
184 // clang-format on
185 ASSERT_TRUE((bool)result);
186 ASSERT_EQ(result.status, EXIT_SUCCESS) << result.stderr_str;
187
188 // clang-format off
189 result = ExecuteBinary({"idmap2",
190 "lookup",
191 "--idmap-path", GetIdmapPath(),
192 "--config", "",
193 "--resid", StringPrintf("0x%08x", R::target::string::str1)});
194 // clang-format on
195 ASSERT_TRUE((bool)result);
196 ASSERT_EQ(result.status, EXIT_SUCCESS) << result.stderr_str;
197 ASSERT_NE(result.stdout_str.find("overlay-1"), std::string::npos);
198 ASSERT_EQ(result.stdout_str.find("overlay-1-sv"), std::string::npos);
199
200 // clang-format off
201 result = ExecuteBinary({"idmap2",
202 "lookup",
203 "--idmap-path", GetIdmapPath(),
204 "--config", "",
205 "--resid", "test.target:string/str1"});
206 // clang-format on
207 ASSERT_TRUE((bool)result);
208 ASSERT_EQ(result.status, EXIT_SUCCESS) << result.stderr_str;
209 ASSERT_NE(result.stdout_str.find("overlay-1"), std::string::npos);
210 ASSERT_EQ(result.stdout_str.find("overlay-1-sv"), std::string::npos);
211
212 // clang-format off
213 result = ExecuteBinary({"idmap2",
214 "lookup",
215 "--idmap-path", GetIdmapPath(),
216 "--config", "sv",
217 "--resid", "test.target:string/str1"});
218 // clang-format on
219 ASSERT_TRUE((bool)result);
220 ASSERT_EQ(result.status, EXIT_SUCCESS) << result.stderr_str;
221 ASSERT_NE(result.stdout_str.find("overlay-1-sv"), std::string::npos);
222
223 unlink(GetIdmapPath().c_str());
224 }
225
TEST_F(Idmap2BinaryTests,InvalidCommandLineOptions)226 TEST_F(Idmap2BinaryTests, InvalidCommandLineOptions) {
227 SKIP_TEST_IF_CANT_EXEC_IDMAP2;
228
229 const std::string invalid_target_apk_path = GetTestDataPath() + "/DOES-NOT-EXIST";
230
231 // missing mandatory options
232 // clang-format off
233 auto result = ExecuteBinary({"idmap2",
234 "create"});
235 // clang-format on
236 ASSERT_TRUE((bool)result);
237 ASSERT_NE(result.status, EXIT_SUCCESS);
238
239 // missing argument to option
240 // clang-format off
241 result = ExecuteBinary({"idmap2",
242 "create",
243 "--target-apk-path", GetTargetApkPath(),
244 "--overlay-apk-path", GetOverlayApkPath(),
245 "--overlay-name", TestConstants::OVERLAY_NAME_DEFAULT,
246 "--idmap-path"});
247 // clang-format on
248 ASSERT_TRUE((bool)result);
249 ASSERT_NE(result.status, EXIT_SUCCESS);
250
251 // invalid target apk path
252 // clang-format off
253 result = ExecuteBinary({"idmap2",
254 "create",
255 "--target-apk-path", invalid_target_apk_path,
256 "--overlay-apk-path", GetOverlayApkPath(),
257 "--overlay-name", TestConstants::OVERLAY_NAME_DEFAULT,
258 "--idmap-path", GetIdmapPath()});
259 // clang-format on
260 ASSERT_TRUE((bool)result);
261 ASSERT_NE(result.status, EXIT_SUCCESS);
262
263 // unknown policy
264 // clang-format off
265 result = ExecuteBinary({"idmap2",
266 "create",
267 "--target-apk-path", GetTargetApkPath(),
268 "--overlay-apk-path", GetOverlayApkPath(),
269 "--overlay-name", TestConstants::OVERLAY_NAME_DEFAULT,
270 "--idmap-path", GetIdmapPath(),
271 "--policy", "this-does-not-exist"});
272 // clang-format on
273 ASSERT_TRUE((bool)result);
274 ASSERT_NE(result.status, EXIT_SUCCESS);
275 }
276
277 } // namespace android::idmap2
278