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