blob: 1ef41de4410d1af14f66c7232d15d50e13b7f9cd [file] [log] [blame]
Ryan Mitchell9e4f52b2019-09-19 12:15:52 -07001/*
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#include <cstdio> // fclose
18#include <fstream>
19#include <memory>
20#include <sstream>
21#include <string>
22#include <utility>
23#include <vector>
24
25#include "TestHelpers.h"
26#include "gmock/gmock.h"
27#include "gtest/gtest.h"
28#include "idmap2/ResourceMapping.h"
29
30using android::idmap2::utils::ExtractOverlayManifestInfo;
31
32namespace android::idmap2 {
33
34#define ASSERT_RESULT(r) \
35 do { \
36 auto result = r; \
37 ASSERT_TRUE(result) << result.GetErrorMessage(); \
38 } while (0)
39
40Result<ResourceMapping> TestGetResourceMapping(const android::StringPiece& local_target_apk_path,
41 const android::StringPiece& local_overlay_apk_path,
42 const OverlayManifestInfo& overlay_info,
43 const PolicyBitmask& fulfilled_policies,
44 bool enforce_overlayable) {
45 const std::string target_apk_path(GetTestDataPath() + local_target_apk_path.data());
46 std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
47 if (!target_apk) {
48 return Error(R"(Failed to load target apk "%s")", target_apk_path.data());
49 }
50
51 const std::string overlay_apk_path(GetTestDataPath() + local_overlay_apk_path.data());
52 std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
53 if (!overlay_apk) {
54 return Error(R"(Failed to load overlay apk "%s")", overlay_apk_path.data());
55 }
56
57 return ResourceMapping::FromApkAssets(*target_apk, *overlay_apk, overlay_info, fulfilled_policies,
58 enforce_overlayable);
59}
60
61Result<ResourceMapping> TestGetResourceMapping(const android::StringPiece& local_target_apk_path,
62 const android::StringPiece& local_overlay_apk_path,
63 const PolicyBitmask& fulfilled_policies,
64 bool enforce_overlayable) {
65 auto overlay_info = ExtractOverlayManifestInfo(GetTestDataPath() + local_overlay_apk_path.data());
66 if (!overlay_info) {
67 return overlay_info.GetError();
68 }
69 return TestGetResourceMapping(local_target_apk_path, local_overlay_apk_path, *overlay_info,
70 fulfilled_policies, enforce_overlayable);
71}
72
73Result<Unit> MappingExists(const ResourceMapping& mapping, const ResourceId& target_resource,
74 const uint8_t type, const uint32_t value, bool rewrite) {
75 auto target_map = mapping.GetTargetToOverlayMap();
76 auto entry_map = target_map.find(target_resource);
77 if (entry_map == target_map.end()) {
78 return Error("Failed to find mapping for target resource");
79 }
80
81 if (entry_map->second.data_type != type) {
82 return Error(R"(Expected type: "0x%02x" Actual type: "0x%02x")", type,
83 entry_map->second.data_type);
84 }
85
86 if (entry_map->second.data_value != value) {
87 return Error(R"(Expected value: "0x%08x" Actual value: "0x%08x")", type,
88 entry_map->second.data_value);
89 }
90
91 auto overlay_map = mapping.GetOverlayToTargetMap();
92 auto overlay_iter = overlay_map.find(entry_map->second.data_value);
93 if ((overlay_iter != overlay_map.end()) != rewrite) {
94 return Error(R"(Expected rewriting: "%s")", rewrite ? "true" : "false");
95 }
96
97 return Result<Unit>({});
98}
99
100TEST(ResourceMappingTests, ResourcesFromApkAssetsLegacy) {
101 OverlayManifestInfo info{};
102 info.target_package = "test.target";
103 info.target_name = "TestResources";
104 info.resource_mapping = 0U; // no xml
105 auto resources = TestGetResourceMapping("/target/target.apk", "/overlay/overlay.apk", info,
106 PolicyFlags::POLICY_PUBLIC,
107 /* enforce_overlayable */ false);
108
109 ASSERT_TRUE(resources) << resources.GetErrorMessage();
110 auto& res = *resources;
111 ASSERT_EQ(res.GetTargetToOverlayMap().size(), 4U);
112 ASSERT_RESULT(MappingExists(res, 0x7f010000, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010000,
113 true /* rewrite */)); // integer/int1
114 ASSERT_RESULT(MappingExists(res, 0x7f02000c, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f020000,
115 true /* rewrite */)); // string/str1
116 ASSERT_RESULT(MappingExists(res, 0x7f02000e, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f020001,
117 true /* rewrite */)); // string/str3
118 ASSERT_RESULT(MappingExists(res, 0x7f02000f, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f020002,
119 true /* rewrite */)); // string/str4
120}
121
122TEST(ResourceMappingTests, ResourcesFromApkAssetsNonMatchingNames) {
123 OverlayManifestInfo info{};
124 info.target_package = "test.target";
125 info.target_name = "TestResources";
126 info.resource_mapping = 0x7f030003; // xml/overlays_swap
127 auto resources = TestGetResourceMapping("/target/target.apk", "/overlay/overlay.apk", info,
128 PolicyFlags::POLICY_PUBLIC,
129 /* enforce_overlayable */ false);
130
131 ASSERT_TRUE(resources) << resources.GetErrorMessage();
132 auto& res = *resources;
133 ASSERT_EQ(res.GetTargetToOverlayMap().size(), 3U);
134 ASSERT_RESULT(MappingExists(res, 0x7f02000c, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f020002,
135 true /* rewrite */)); // string/str1 -> string/str4
136 ASSERT_RESULT(MappingExists(res, 0x7f02000e, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f020000,
137 true /* rewrite */)); // string/str3 -> string/str1
138 ASSERT_RESULT(MappingExists(res, 0x7f02000f, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f020001,
139 true /* rewrite */)); // string/str4 -> string/str3
140}
141
142TEST(ResourceMappingTests, DoNotRewriteNonResourceMapping) {
143 OverlayManifestInfo info{};
144 info.target_package = "test.target";
145 info.target_name = "TestResources";
146 info.resource_mapping = 0x7f030001; // xml/overlays_different_packages
147 auto resources = TestGetResourceMapping("/target/target.apk", "/overlay/overlay.apk", info,
148 PolicyFlags::POLICY_PUBLIC,
149 /* enforce_overlayable */ false);
150
151 ASSERT_TRUE(resources) << resources.GetErrorMessage();
152 auto& res = *resources;
153 ASSERT_EQ(res.GetTargetToOverlayMap().size(), 2U);
154 ASSERT_EQ(res.GetOverlayToTargetMap().size(), 1U);
155 ASSERT_RESULT(MappingExists(res, 0x7f02000c, 0x01 /* Res_value::TYPE_REFERENCE */, 0x0104000a,
156 false /* rewrite */)); // string/str1 -> android:string/ok
157 ASSERT_RESULT(MappingExists(res, 0x7f02000e, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f020001,
158 true /* rewrite */)); // string/str3 -> string/str4
159}
160
161TEST(ResourceMappingTests, InlineResources) {
162 OverlayManifestInfo info{};
163 info.target_package = "test.target";
164 info.target_name = "TestResources";
165 info.resource_mapping = 0x7f030002; // xml/overlays_inline
166 auto resources = TestGetResourceMapping("/target/target.apk", "/overlay/overlay.apk", info,
167 PolicyFlags::POLICY_PUBLIC,
168 /* enforce_overlayable */ false);
169
170 constexpr size_t overlay_string_pool_size = 8U;
171 ASSERT_TRUE(resources) << resources.GetErrorMessage();
172 auto& res = *resources;
173 ASSERT_EQ(res.GetTargetToOverlayMap().size(), 2U);
174 ASSERT_EQ(res.GetOverlayToTargetMap().size(), 0U);
175 ASSERT_RESULT(MappingExists(res, 0x7f02000c, 0x03 /* Res_value::TYPE_STRING */,
176 overlay_string_pool_size + 0U,
177 false /* rewrite */)); // string/str1 -> "Hello World"
178 ASSERT_RESULT(MappingExists(res, 0x7f010000, 0x10 /* Res_value::TYPE_INT_DEC */, 73U,
179 false /* rewrite */)); // string/str1 -> "Hello World"
180}
181
182TEST(ResourceMappingTests, CreateIdmapFromApkAssetsPolicySystemPublic) {
183 auto resources =
184 TestGetResourceMapping("/target/target.apk", "/system-overlay/system-overlay.apk",
185 PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC,
186 /* enforce_overlayable */ true);
187
188 ASSERT_TRUE(resources) << resources.GetErrorMessage();
189 auto& res = *resources;
190 ASSERT_EQ(res.GetTargetToOverlayMap().size(), 3U);
191 ASSERT_RESULT(MappingExists(res, 0x7f020008, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010000,
192 true /* rewrite */)); // string/policy_public
193 ASSERT_RESULT(MappingExists(res, 0x7f02000a, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010001,
194 true /* rewrite */)); // string/policy_system
195 ASSERT_RESULT(MappingExists(res, 0x7f02000b, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010002,
196 true /* rewrite */)); // string/policy_system_vendor
197}
198
199// Resources that are not declared as overlayable and resources that a protected by policies the
200// overlay does not fulfill must not map to overlay resources.
201TEST(ResourceMappingTests, CreateIdmapFromApkAssetsPolicySystemPublicInvalid) {
202 auto resources = TestGetResourceMapping(
203 "/target/target.apk", "/system-overlay-invalid/system-overlay-invalid.apk",
204 PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC,
205 /* enforce_overlayable */ true);
206
207 ASSERT_TRUE(resources) << resources.GetErrorMessage();
208 auto& res = *resources;
209 ASSERT_EQ(res.GetTargetToOverlayMap().size(), 3U);
210 ASSERT_RESULT(MappingExists(res, 0x7f020008, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010005,
211 true /* rewrite */)); // string/policy_public
212 ASSERT_RESULT(MappingExists(res, 0x7f02000a, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010007,
213 true /* rewrite */)); // string/policy_system
214 ASSERT_RESULT(MappingExists(res, 0x7f02000b, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010008,
215 true /* rewrite */)); // string/policy_system_vendor
216}
217
218// Resources that are not declared as overlayable and resources that a protected by policies the
219// overlay does not fulfilled can map to overlay resources when overlayable enforcement is turned
220// off.
221TEST(ResourceMappingTests, ResourcesFromApkAssetsPolicySystemPublicInvalidIgnoreOverlayable) {
222 auto resources = TestGetResourceMapping(
223 "/target/target.apk", "/system-overlay-invalid/system-overlay-invalid.apk",
224 PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC,
225 /* enforce_overlayable */ false);
226
227 ASSERT_TRUE(resources) << resources.GetErrorMessage();
228 auto& res = *resources;
229 ASSERT_EQ(res.GetTargetToOverlayMap().size(), 9U);
230 ASSERT_RESULT(MappingExists(res, 0x7f020003, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010000,
231 true /* rewrite */)); // string/not_overlayable
232 ASSERT_RESULT(MappingExists(res, 0x7f020004, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010001,
233 true /* rewrite */)); // string/other
234 ASSERT_RESULT(MappingExists(res, 0x7f020005, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010002,
235 true /* rewrite */)); // string/policy_odm
236 ASSERT_RESULT(MappingExists(res, 0x7f020006, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010003,
237 true /* rewrite */)); // string/policy_oem
238 ASSERT_RESULT(MappingExists(res, 0x7f020007, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010004,
239 true /* rewrite */)); // string/policy_product
240 ASSERT_RESULT(MappingExists(res, 0x7f020008, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010005,
241 true /* rewrite */)); // string/policy_public
242 ASSERT_RESULT(MappingExists(res, 0x7f020009, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010006,
243 true /* rewrite */)); // string/policy_signature
244 ASSERT_RESULT(MappingExists(res, 0x7f02000a, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010007,
245 true /* rewrite */)); // string/policy_system
246 ASSERT_RESULT(MappingExists(res, 0x7f02000b, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010008,
247 true /* rewrite */)); // string/policy_system_vendor
248}
249
250// Overlays that do not target an <overlayable> tag can overlay resources defined within any
251// <overlayable> tag.
252TEST(ResourceMappingTests, ResourcesFromApkAssetsNoDefinedOverlayableAndNoTargetName) {
253 auto resources = TestGetResourceMapping("/target/target.apk", "/overlay/overlay-no-name.apk",
254 PolicyFlags::POLICY_PUBLIC,
255 /* enforce_overlayable */ false);
256
257 ASSERT_TRUE(resources) << resources.GetErrorMessage();
258 auto& res = *resources;
259 ASSERT_EQ(res.GetTargetToOverlayMap().size(), 4U);
260 ASSERT_RESULT(MappingExists(res, 0x7f010000, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010000,
261 true /* rewrite */)); // integer/int1
262 ASSERT_RESULT(MappingExists(res, 0x7f02000c, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f020000,
263 true /* rewrite */)); // string/str1
264 ASSERT_RESULT(MappingExists(res, 0x7f02000e, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f020001,
265 true /* rewrite */)); // string/str3
266 ASSERT_RESULT(MappingExists(res, 0x7f02000f, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f020002,
267 true /* rewrite */)); // string/str4
268}
269
270// Overlays that are neither pre-installed nor signed with the same signature as the target cannot
271// overlay packages that have not defined overlayable resources.
272TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPoliciesPublicFail) {
273 auto resources =
274 TestGetResourceMapping("/target/target-no-overlayable.apk", "/overlay/overlay-no-name.apk",
275 PolicyFlags::POLICY_PUBLIC,
276 /* enforce_overlayable */ true);
277
278 ASSERT_TRUE(resources) << resources.GetErrorMessage();
279 ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 0U);
280}
281
282// Overlays that are pre-installed or are signed with the same signature as the target can overlay
283// packages that have not defined overlayable resources.
284TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPolicies) {
285 auto CheckEntries = [&](const PolicyBitmask& fulfilled_policies) -> void {
286 auto resources = TestGetResourceMapping("/target/target-no-overlayable.apk",
287 "/system-overlay-invalid/system-overlay-invalid.apk",
288 fulfilled_policies,
289 /* enforce_overlayable */ true);
290
291 ASSERT_TRUE(resources) << resources.GetErrorMessage();
292 auto& res = *resources;
293 ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 9U);
294 ASSERT_RESULT(MappingExists(res, 0x7f020003, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010000,
295 true /* rewrite */)); // string/not_overlayable
296 ASSERT_RESULT(MappingExists(res, 0x7f020004, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010001,
297 true /* rewrite */)); // string/other
298 ASSERT_RESULT(MappingExists(res, 0x7f020005, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010002,
299 true /* rewrite */)); // string/policy_odm
300 ASSERT_RESULT(MappingExists(res, 0x7f020006, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010003,
301 true /* rewrite */)); // string/policy_oem
302 ASSERT_RESULT(MappingExists(res, 0x7f020007, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010004,
303 true /* rewrite */)); // string/policy_product
304 ASSERT_RESULT(MappingExists(res, 0x7f020008, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010005,
305 true /* rewrite */)); // string/policy_public
306 ASSERT_RESULT(MappingExists(res, 0x7f020009, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010006,
307 true /* rewrite */)); // string/policy_signature
308 ASSERT_RESULT(MappingExists(res, 0x7f02000a, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010007,
309 true /* rewrite */)); // string/policy_system
310 ASSERT_RESULT(MappingExists(res, 0x7f02000b, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010008,
311 true /* rewrite */)); // string/policy_system_vendor
312 };
313
314 CheckEntries(PolicyFlags::POLICY_SIGNATURE);
315 CheckEntries(PolicyFlags::POLICY_PRODUCT_PARTITION);
316 CheckEntries(PolicyFlags::POLICY_SYSTEM_PARTITION);
317 CheckEntries(PolicyFlags::POLICY_VENDOR_PARTITION);
318 CheckEntries(PolicyFlags::POLICY_ODM_PARTITION);
319 CheckEntries(PolicyFlags::POLICY_OEM_PARTITION);
320}
321
322} // namespace android::idmap2