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