1 /*
2 * Copyright (C) 2016 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 "androidfw/LoadedArsc.h"
18
19 #include "android-base/file.h"
20 #include "androidfw/ResourceUtils.h"
21
22 #include "TestHelpers.h"
23 #include "data/basic/R.h"
24 #include "data/libclient/R.h"
25 #include "data/sparse/R.h"
26 #include "data/styles/R.h"
27
28 namespace app = com::android::app;
29 namespace basic = com::android::basic;
30 namespace libclient = com::android::libclient;
31 namespace sparse = com::android::sparse;
32
33 using ::android::base::ReadFileToString;
34 using ::testing::Eq;
35 using ::testing::Ge;
36 using ::testing::IsNull;
37 using ::testing::NotNull;
38 using ::testing::SizeIs;
39 using ::testing::StrEq;
40
41 namespace android {
42
TEST(LoadedArscTest,LoadSinglePackageArsc)43 TEST(LoadedArscTest, LoadSinglePackageArsc) {
44 std::string contents;
45 ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/styles/styles.apk", "resources.arsc",
46 &contents));
47
48 std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
49 ASSERT_THAT(loaded_arsc, NotNull());
50
51 const LoadedPackage* package =
52 loaded_arsc->GetPackageById(get_package_id(app::R::string::string_one));
53 ASSERT_THAT(package, NotNull());
54 EXPECT_THAT(package->GetPackageName(), StrEq("com.android.app"));
55 EXPECT_THAT(package->GetPackageId(), Eq(0x7f));
56
57 const uint8_t type_index = get_type_id(app::R::string::string_one) - 1;
58 const uint16_t entry_index = get_entry_id(app::R::string::string_one);
59
60 const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(type_index);
61 ASSERT_THAT(type_spec, NotNull());
62 ASSERT_THAT(type_spec->type_count, Ge(1u));
63
64 const ResTable_type* type = type_spec->types[0];
65 ASSERT_THAT(type, NotNull());
66 ASSERT_THAT(LoadedPackage::GetEntry(type, entry_index), NotNull());
67 }
68
TEST(LoadedArscTest,LoadSparseEntryApp)69 TEST(LoadedArscTest, LoadSparseEntryApp) {
70 std::string contents;
71 ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/sparse/sparse.apk", "resources.arsc",
72 &contents));
73
74 std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
75 ASSERT_THAT(loaded_arsc, NotNull());
76
77 const LoadedPackage* package =
78 loaded_arsc->GetPackageById(get_package_id(sparse::R::integer::foo_9));
79 ASSERT_THAT(package, NotNull());
80
81 const uint8_t type_index = get_type_id(sparse::R::integer::foo_9) - 1;
82 const uint16_t entry_index = get_entry_id(sparse::R::integer::foo_9);
83
84 const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(type_index);
85 ASSERT_THAT(type_spec, NotNull());
86 ASSERT_THAT(type_spec->type_count, Ge(1u));
87
88 const ResTable_type* type = type_spec->types[0];
89 ASSERT_THAT(type, NotNull());
90 ASSERT_THAT(LoadedPackage::GetEntry(type, entry_index), NotNull());
91 }
92
TEST(LoadedArscTest,LoadSharedLibrary)93 TEST(LoadedArscTest, LoadSharedLibrary) {
94 std::string contents;
95 ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/lib_one/lib_one.apk", "resources.arsc",
96 &contents));
97
98 std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
99 ASSERT_THAT(loaded_arsc, NotNull());
100
101 const auto& packages = loaded_arsc->GetPackages();
102 ASSERT_THAT(packages, SizeIs(1u));
103 EXPECT_TRUE(packages[0]->IsDynamic());
104 EXPECT_THAT(packages[0]->GetPackageName(), StrEq("com.android.lib_one"));
105 EXPECT_THAT(packages[0]->GetPackageId(), Eq(0));
106
107 const auto& dynamic_pkg_map = packages[0]->GetDynamicPackageMap();
108
109 // The library has no dependencies.
110 ASSERT_TRUE(dynamic_pkg_map.empty());
111 }
112
TEST(LoadedArscTest,LoadAppLinkedAgainstSharedLibrary)113 TEST(LoadedArscTest, LoadAppLinkedAgainstSharedLibrary) {
114 std::string contents;
115 ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/libclient/libclient.apk",
116 "resources.arsc", &contents));
117
118 std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
119 ASSERT_THAT(loaded_arsc, NotNull());
120
121 const auto& packages = loaded_arsc->GetPackages();
122 ASSERT_THAT(packages, SizeIs(1u));
123 EXPECT_FALSE(packages[0]->IsDynamic());
124 EXPECT_THAT(packages[0]->GetPackageName(), StrEq("com.android.libclient"));
125 EXPECT_THAT(packages[0]->GetPackageId(), Eq(0x7f));
126
127 const auto& dynamic_pkg_map = packages[0]->GetDynamicPackageMap();
128
129 // The library has two dependencies.
130 ASSERT_THAT(dynamic_pkg_map, SizeIs(2u));
131 EXPECT_THAT(dynamic_pkg_map[0].package_name, StrEq("com.android.lib_one"));
132 EXPECT_THAT(dynamic_pkg_map[0].package_id, Eq(0x02));
133
134 EXPECT_THAT(dynamic_pkg_map[1].package_name, StrEq("com.android.lib_two"));
135 EXPECT_THAT(dynamic_pkg_map[1].package_id, Eq(0x03));
136 }
137
TEST(LoadedArscTest,LoadAppAsSharedLibrary)138 TEST(LoadedArscTest, LoadAppAsSharedLibrary) {
139 std::string contents;
140 ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/appaslib/appaslib.apk",
141 "resources.arsc", &contents));
142
143 std::unique_ptr<const LoadedArsc> loaded_arsc =
144 LoadedArsc::Load(StringPiece(contents), nullptr /*loaded_idmap*/, false /*system*/,
145 true /*load_as_shared_library*/);
146 ASSERT_THAT(loaded_arsc, NotNull());
147
148 const auto& packages = loaded_arsc->GetPackages();
149 ASSERT_THAT(packages, SizeIs(1u));
150 EXPECT_TRUE(packages[0]->IsDynamic());
151 EXPECT_THAT(packages[0]->GetPackageId(), Eq(0x7f));
152 }
153
TEST(LoadedArscTest,LoadFeatureSplit)154 TEST(LoadedArscTest, LoadFeatureSplit) {
155 std::string contents;
156 ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/feature/feature.apk", "resources.arsc",
157 &contents));
158 std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
159 ASSERT_THAT(loaded_arsc, NotNull());
160
161 const LoadedPackage* package =
162 loaded_arsc->GetPackageById(get_package_id(basic::R::string::test3));
163 ASSERT_THAT(package, NotNull());
164
165 uint8_t type_index = get_type_id(basic::R::string::test3) - 1;
166 uint8_t entry_index = get_entry_id(basic::R::string::test3);
167
168 const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(type_index);
169 ASSERT_THAT(type_spec, NotNull());
170 ASSERT_THAT(type_spec->type_count, Ge(1u));
171 ASSERT_THAT(type_spec->types[0], NotNull());
172
173 size_t len;
174 const char16_t* type_name16 =
175 package->GetTypeStringPool()->stringAt(type_spec->type_spec->id - 1, &len);
176 ASSERT_THAT(type_name16, NotNull());
177 EXPECT_THAT(util::Utf16ToUtf8(StringPiece16(type_name16, len)), StrEq("string"));
178
179 ASSERT_THAT(LoadedPackage::GetEntry(type_spec->types[0], entry_index), NotNull());
180 }
181
182 // AAPT(2) generates resource tables with chunks in a certain order. The rule is that
183 // a RES_TABLE_TYPE_TYPE with id `i` must always be preceded by a RES_TABLE_TYPE_SPEC_TYPE with
184 // id `i`. The RES_TABLE_TYPE_SPEC_TYPE does not need to be directly preceding, however.
185 //
186 // AAPT(2) generates something like:
187 // RES_TABLE_TYPE_SPEC_TYPE id=1
188 // RES_TABLE_TYPE_TYPE id=1
189 // RES_TABLE_TYPE_SPEC_TYPE id=2
190 // RES_TABLE_TYPE_TYPE id=2
191 //
192 // But the following is valid too:
193 // RES_TABLE_TYPE_SPEC_TYPE id=1
194 // RES_TABLE_TYPE_SPEC_TYPE id=2
195 // RES_TABLE_TYPE_TYPE id=1
196 // RES_TABLE_TYPE_TYPE id=2
197 //
TEST(LoadedArscTest,LoadOutOfOrderTypeSpecs)198 TEST(LoadedArscTest, LoadOutOfOrderTypeSpecs) {
199 std::string contents;
200 ASSERT_TRUE(
201 ReadFileFromZipToString(GetTestDataPath() + "/out_of_order_types/out_of_order_types.apk",
202 "resources.arsc", &contents));
203
204 std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
205 ASSERT_THAT(loaded_arsc, NotNull());
206
207 ASSERT_THAT(loaded_arsc->GetPackages(), SizeIs(1u));
208 const auto& package = loaded_arsc->GetPackages()[0];
209 ASSERT_THAT(package, NotNull());
210
211 const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(0);
212 ASSERT_THAT(type_spec, NotNull());
213 ASSERT_THAT(type_spec->type_count, Ge(1u));
214 ASSERT_THAT(type_spec->types[0], NotNull());
215
216 type_spec = package->GetTypeSpecByTypeIndex(1);
217 ASSERT_THAT(type_spec, NotNull());
218 ASSERT_THAT(type_spec->type_count, Ge(1u));
219 ASSERT_THAT(type_spec->types[0], NotNull());
220 }
221
222 class MockLoadedIdmap : public LoadedIdmap {
223 public:
MockLoadedIdmap()224 MockLoadedIdmap() : LoadedIdmap() {
225 local_header_.magic = kIdmapMagic;
226 local_header_.version = kIdmapCurrentVersion;
227 local_header_.target_package_id = 0x08;
228 local_header_.type_count = 1;
229 header_ = &local_header_;
230
231 entry_header = util::unique_cptr<IdmapEntry_header>(
232 (IdmapEntry_header*)::malloc(sizeof(IdmapEntry_header) + sizeof(uint32_t)));
233 entry_header->target_type_id = 0x03;
234 entry_header->overlay_type_id = 0x02;
235 entry_header->entry_id_offset = 1;
236 entry_header->entry_count = 1;
237 entry_header->entries[0] = 0x00000000u;
238 type_map_[entry_header->overlay_type_id] = entry_header.get();
239 }
240
241 private:
242 Idmap_header local_header_;
243 util::unique_cptr<IdmapEntry_header> entry_header;
244 };
245
TEST(LoadedArscTest,LoadOverlay)246 TEST(LoadedArscTest, LoadOverlay) {
247 std::string contents;
248 ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/overlay/overlay.apk", "resources.arsc",
249 &contents));
250
251 MockLoadedIdmap loaded_idmap;
252
253 std::unique_ptr<const LoadedArsc> loaded_arsc =
254 LoadedArsc::Load(StringPiece(contents), &loaded_idmap);
255 ASSERT_THAT(loaded_arsc, NotNull());
256
257 const LoadedPackage* package = loaded_arsc->GetPackageById(0x08u);
258 ASSERT_THAT(package, NotNull());
259
260 const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(0x03u - 1);
261 ASSERT_THAT(type_spec, NotNull());
262 ASSERT_THAT(type_spec->type_count, Ge(1u));
263 ASSERT_THAT(type_spec->types[0], NotNull());
264
265 // The entry being overlaid doesn't exist at the original entry index.
266 ASSERT_THAT(LoadedPackage::GetEntry(type_spec->types[0], 0x0001u), IsNull());
267
268 // Since this is an overlay, the actual entry ID must be mapped.
269 ASSERT_THAT(type_spec->idmap_entries, NotNull());
270 uint16_t target_entry_id = 0u;
271 ASSERT_TRUE(LoadedIdmap::Lookup(type_spec->idmap_entries, 0x0001u, &target_entry_id));
272 ASSERT_THAT(target_entry_id, Eq(0x0u));
273 ASSERT_THAT(LoadedPackage::GetEntry(type_spec->types[0], 0x0000), NotNull());
274 }
275
276 // structs with size fields (like Res_value, ResTable_entry) should be
277 // backwards and forwards compatible (aka checking the size field against
278 // sizeof(Res_value) might not be backwards compatible.
TEST(LoadedArscTest,LoadingShouldBeForwardsAndBackwardsCompatible)279 TEST(LoadedArscTest, LoadingShouldBeForwardsAndBackwardsCompatible) { ASSERT_TRUE(false); }
280
281 } // namespace android
282