• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/overlayable/R.h"
26 #include "data/sparse/R.h"
27 #include "data/styles/R.h"
28 
29 namespace app = com::android::app;
30 namespace basic = com::android::basic;
31 namespace libclient = com::android::libclient;
32 namespace overlayable = com::android::overlayable;
33 namespace sparse = com::android::sparse;
34 
35 using ::android::base::ReadFileToString;
36 using ::testing::Eq;
37 using ::testing::Ge;
38 using ::testing::IsNull;
39 using ::testing::NotNull;
40 using ::testing::SizeIs;
41 using ::testing::StrEq;
42 
43 namespace android {
44 
TEST(LoadedArscTest,LoadSinglePackageArsc)45 TEST(LoadedArscTest, LoadSinglePackageArsc) {
46   std::string contents;
47   ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/styles/styles.apk", "resources.arsc",
48                                       &contents));
49 
50   std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
51   ASSERT_THAT(loaded_arsc, NotNull());
52 
53   const LoadedPackage* package =
54       loaded_arsc->GetPackageById(get_package_id(app::R::string::string_one));
55   ASSERT_THAT(package, NotNull());
56   EXPECT_THAT(package->GetPackageName(), StrEq("com.android.app"));
57   EXPECT_THAT(package->GetPackageId(), Eq(0x7f));
58 
59   const uint8_t type_index = get_type_id(app::R::string::string_one) - 1;
60   const uint16_t entry_index = get_entry_id(app::R::string::string_one);
61 
62   const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(type_index);
63   ASSERT_THAT(type_spec, NotNull());
64   ASSERT_THAT(type_spec->type_count, Ge(1u));
65 
66   const ResTable_type* type = type_spec->types[0];
67   ASSERT_THAT(type, NotNull());
68   ASSERT_THAT(LoadedPackage::GetEntry(type, entry_index), NotNull());
69 }
70 
TEST(LoadedArscTest,LoadSparseEntryApp)71 TEST(LoadedArscTest, LoadSparseEntryApp) {
72   std::string contents;
73   ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/sparse/sparse.apk", "resources.arsc",
74                                       &contents));
75 
76   std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
77   ASSERT_THAT(loaded_arsc, NotNull());
78 
79   const LoadedPackage* package =
80       loaded_arsc->GetPackageById(get_package_id(sparse::R::integer::foo_9));
81   ASSERT_THAT(package, NotNull());
82 
83   const uint8_t type_index = get_type_id(sparse::R::integer::foo_9) - 1;
84   const uint16_t entry_index = get_entry_id(sparse::R::integer::foo_9);
85 
86   const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(type_index);
87   ASSERT_THAT(type_spec, NotNull());
88   ASSERT_THAT(type_spec->type_count, Ge(1u));
89 
90   const ResTable_type* type = type_spec->types[0];
91   ASSERT_THAT(type, NotNull());
92   ASSERT_THAT(LoadedPackage::GetEntry(type, entry_index), NotNull());
93 }
94 
TEST(LoadedArscTest,LoadSharedLibrary)95 TEST(LoadedArscTest, LoadSharedLibrary) {
96   std::string contents;
97   ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/lib_one/lib_one.apk", "resources.arsc",
98                                       &contents));
99 
100   std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
101   ASSERT_THAT(loaded_arsc, NotNull());
102 
103   const auto& packages = loaded_arsc->GetPackages();
104   ASSERT_THAT(packages, SizeIs(1u));
105   EXPECT_TRUE(packages[0]->IsDynamic());
106   EXPECT_THAT(packages[0]->GetPackageName(), StrEq("com.android.lib_one"));
107   EXPECT_THAT(packages[0]->GetPackageId(), Eq(0));
108 
109   const auto& dynamic_pkg_map = packages[0]->GetDynamicPackageMap();
110 
111   // The library has no dependencies.
112   ASSERT_TRUE(dynamic_pkg_map.empty());
113 }
114 
TEST(LoadedArscTest,LoadAppLinkedAgainstSharedLibrary)115 TEST(LoadedArscTest, LoadAppLinkedAgainstSharedLibrary) {
116   std::string contents;
117   ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/libclient/libclient.apk",
118                                       "resources.arsc", &contents));
119 
120   std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
121   ASSERT_THAT(loaded_arsc, NotNull());
122 
123   const auto& packages = loaded_arsc->GetPackages();
124   ASSERT_THAT(packages, SizeIs(1u));
125   EXPECT_FALSE(packages[0]->IsDynamic());
126   EXPECT_THAT(packages[0]->GetPackageName(), StrEq("com.android.libclient"));
127   EXPECT_THAT(packages[0]->GetPackageId(), Eq(0x7f));
128 
129   const auto& dynamic_pkg_map = packages[0]->GetDynamicPackageMap();
130 
131   // The library has two dependencies.
132   ASSERT_THAT(dynamic_pkg_map, SizeIs(2u));
133   EXPECT_THAT(dynamic_pkg_map[0].package_name, StrEq("com.android.lib_one"));
134   EXPECT_THAT(dynamic_pkg_map[0].package_id, Eq(0x02));
135 
136   EXPECT_THAT(dynamic_pkg_map[1].package_name, StrEq("com.android.lib_two"));
137   EXPECT_THAT(dynamic_pkg_map[1].package_id, Eq(0x03));
138 }
139 
TEST(LoadedArscTest,LoadAppAsSharedLibrary)140 TEST(LoadedArscTest, LoadAppAsSharedLibrary) {
141   std::string contents;
142   ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/appaslib/appaslib.apk",
143                                       "resources.arsc", &contents));
144 
145   std::unique_ptr<const LoadedArsc> loaded_arsc =
146       LoadedArsc::Load(StringPiece(contents), nullptr /*loaded_idmap*/, false /*system*/,
147                        true /*load_as_shared_library*/);
148   ASSERT_THAT(loaded_arsc, NotNull());
149 
150   const auto& packages = loaded_arsc->GetPackages();
151   ASSERT_THAT(packages, SizeIs(1u));
152   EXPECT_TRUE(packages[0]->IsDynamic());
153   EXPECT_THAT(packages[0]->GetPackageId(), Eq(0x7f));
154 }
155 
TEST(LoadedArscTest,LoadFeatureSplit)156 TEST(LoadedArscTest, LoadFeatureSplit) {
157   std::string contents;
158   ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/feature/feature.apk", "resources.arsc",
159                                       &contents));
160   std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
161   ASSERT_THAT(loaded_arsc, NotNull());
162 
163   const LoadedPackage* package =
164       loaded_arsc->GetPackageById(get_package_id(basic::R::string::test3));
165   ASSERT_THAT(package, NotNull());
166 
167   uint8_t type_index = get_type_id(basic::R::string::test3) - 1;
168   uint8_t entry_index = get_entry_id(basic::R::string::test3);
169 
170   const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(type_index);
171   ASSERT_THAT(type_spec, NotNull());
172   ASSERT_THAT(type_spec->type_count, Ge(1u));
173   ASSERT_THAT(type_spec->types[0], NotNull());
174 
175   size_t len;
176   const char16_t* type_name16 =
177       package->GetTypeStringPool()->stringAt(type_spec->type_spec->id - 1, &len);
178   ASSERT_THAT(type_name16, NotNull());
179   EXPECT_THAT(util::Utf16ToUtf8(StringPiece16(type_name16, len)), StrEq("string"));
180 
181   ASSERT_THAT(LoadedPackage::GetEntry(type_spec->types[0], entry_index), NotNull());
182 }
183 
184 // AAPT(2) generates resource tables with chunks in a certain order. The rule is that
185 // a RES_TABLE_TYPE_TYPE with id `i` must always be preceded by a RES_TABLE_TYPE_SPEC_TYPE with
186 // id `i`. The RES_TABLE_TYPE_SPEC_TYPE does not need to be directly preceding, however.
187 //
188 // AAPT(2) generates something like:
189 //   RES_TABLE_TYPE_SPEC_TYPE id=1
190 //   RES_TABLE_TYPE_TYPE id=1
191 //   RES_TABLE_TYPE_SPEC_TYPE id=2
192 //   RES_TABLE_TYPE_TYPE id=2
193 //
194 // But the following is valid too:
195 //   RES_TABLE_TYPE_SPEC_TYPE id=1
196 //   RES_TABLE_TYPE_SPEC_TYPE id=2
197 //   RES_TABLE_TYPE_TYPE id=1
198 //   RES_TABLE_TYPE_TYPE id=2
199 //
TEST(LoadedArscTest,LoadOutOfOrderTypeSpecs)200 TEST(LoadedArscTest, LoadOutOfOrderTypeSpecs) {
201   std::string contents;
202   ASSERT_TRUE(
203       ReadFileFromZipToString(GetTestDataPath() + "/out_of_order_types/out_of_order_types.apk",
204                               "resources.arsc", &contents));
205 
206   std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
207   ASSERT_THAT(loaded_arsc, NotNull());
208 
209   ASSERT_THAT(loaded_arsc->GetPackages(), SizeIs(1u));
210   const auto& package = loaded_arsc->GetPackages()[0];
211   ASSERT_THAT(package, NotNull());
212 
213   const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(0);
214   ASSERT_THAT(type_spec, NotNull());
215   ASSERT_THAT(type_spec->type_count, Ge(1u));
216   ASSERT_THAT(type_spec->types[0], NotNull());
217 
218   type_spec = package->GetTypeSpecByTypeIndex(1);
219   ASSERT_THAT(type_spec, NotNull());
220   ASSERT_THAT(type_spec->type_count, Ge(1u));
221   ASSERT_THAT(type_spec->types[0], NotNull());
222 }
223 
224 class MockLoadedIdmap : public LoadedIdmap {
225  public:
MockLoadedIdmap()226   MockLoadedIdmap() : LoadedIdmap() {
227     local_header_.magic = kIdmapMagic;
228     local_header_.version = kIdmapCurrentVersion;
229     local_header_.target_package_id = 0x08;
230     local_header_.type_count = 1;
231     header_ = &local_header_;
232 
233     entry_header = util::unique_cptr<IdmapEntry_header>(
234         (IdmapEntry_header*)::malloc(sizeof(IdmapEntry_header) + sizeof(uint32_t)));
235     entry_header->target_type_id = 0x03;
236     entry_header->overlay_type_id = 0x02;
237     entry_header->entry_id_offset = 1;
238     entry_header->entry_count = 1;
239     entry_header->entries[0] = 0x00000000u;
240     type_map_[entry_header->overlay_type_id] = entry_header.get();
241   }
242 
243  private:
244   Idmap_header local_header_;
245   util::unique_cptr<IdmapEntry_header> entry_header;
246 };
247 
TEST(LoadedArscTest,LoadOverlay)248 TEST(LoadedArscTest, LoadOverlay) {
249   std::string contents;
250   ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/overlay/overlay.apk", "resources.arsc",
251                                       &contents));
252 
253   MockLoadedIdmap loaded_idmap;
254 
255   std::unique_ptr<const LoadedArsc> loaded_arsc =
256       LoadedArsc::Load(StringPiece(contents), &loaded_idmap);
257   ASSERT_THAT(loaded_arsc, NotNull());
258 
259   const LoadedPackage* package = loaded_arsc->GetPackageById(0x08u);
260   ASSERT_THAT(package, NotNull());
261 
262   const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(0x03u - 1);
263   ASSERT_THAT(type_spec, NotNull());
264   ASSERT_THAT(type_spec->type_count, Ge(1u));
265   ASSERT_THAT(type_spec->types[0], NotNull());
266 
267   // The entry being overlaid doesn't exist at the original entry index.
268   ASSERT_THAT(LoadedPackage::GetEntry(type_spec->types[0], 0x0001u), IsNull());
269 
270   // Since this is an overlay, the actual entry ID must be mapped.
271   ASSERT_THAT(type_spec->idmap_entries, NotNull());
272   uint16_t target_entry_id = 0u;
273   ASSERT_TRUE(LoadedIdmap::Lookup(type_spec->idmap_entries, 0x0001u, &target_entry_id));
274   ASSERT_THAT(target_entry_id, Eq(0x0u));
275   ASSERT_THAT(LoadedPackage::GetEntry(type_spec->types[0], 0x0000), NotNull());
276 }
277 
TEST(LoadedArscTest,LoadOverlayable)278 TEST(LoadedArscTest, LoadOverlayable) {
279   std::string contents;
280   ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/overlayable/overlayable.apk",
281                                       "resources.arsc", &contents));
282 
283   std::unique_ptr<const LoadedArsc> loaded_arsc =
284       LoadedArsc::Load(StringPiece(contents), nullptr /*loaded_idmap*/, false /*system*/,
285                        false /*load_as_shared_library*/);
286 
287   ASSERT_THAT(loaded_arsc, NotNull());
288   const LoadedPackage* package = loaded_arsc->GetPackageById(
289       get_package_id(overlayable::R::string::not_overlayable));
290 
291   const OverlayableInfo* info = package->GetOverlayableInfo(
292       overlayable::R::string::not_overlayable);
293   ASSERT_THAT(info, IsNull());
294 
295   info = package->GetOverlayableInfo(overlayable::R::string::overlayable1);
296   ASSERT_THAT(info, NotNull());
297   EXPECT_THAT(info->name, Eq("OverlayableResources1"));
298   EXPECT_THAT(info->actor, Eq("overlay://theme"));
299   EXPECT_THAT(info->policy_flags, Eq(ResTable_overlayable_policy_header::POLICY_PUBLIC));
300 
301   info = package->GetOverlayableInfo(overlayable::R::string::overlayable2);
302   ASSERT_THAT(info, NotNull());
303   EXPECT_THAT(info->name, Eq("OverlayableResources1"));
304   EXPECT_THAT(info->actor, Eq("overlay://theme"));
305   EXPECT_THAT(info->policy_flags,
306               Eq(ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION
307                  | ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION));
308 
309   info = package->GetOverlayableInfo(overlayable::R::string::overlayable3);
310   ASSERT_THAT(info, NotNull());
311   EXPECT_THAT(info->name, Eq("OverlayableResources2"));
312   EXPECT_THAT(info->actor, Eq("overlay://com.android.overlayable"));
313   EXPECT_THAT(info->policy_flags,
314               Eq(ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION
315                  | ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION));
316 
317   info = package->GetOverlayableInfo(overlayable::R::string::overlayable4);
318   EXPECT_THAT(info->name, Eq("OverlayableResources1"));
319   EXPECT_THAT(info->actor, Eq("overlay://theme"));
320   ASSERT_THAT(info, NotNull());
321   EXPECT_THAT(info->policy_flags, Eq(ResTable_overlayable_policy_header::POLICY_PUBLIC));
322 }
323 
TEST(LoadedArscTest,ResourceIdentifierIterator)324 TEST(LoadedArscTest, ResourceIdentifierIterator) {
325   std::string contents;
326   ASSERT_TRUE(
327       ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk", "resources.arsc", &contents));
328 
329   std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
330   ASSERT_NE(nullptr, loaded_arsc);
331 
332   const std::vector<std::unique_ptr<const LoadedPackage>>& packages = loaded_arsc->GetPackages();
333   ASSERT_EQ(1u, packages.size());
334   ASSERT_EQ(std::string("com.android.basic"), packages[0]->GetPackageName());
335 
336   const auto& loaded_package = packages[0];
337   auto iter = loaded_package->begin();
338   auto end = loaded_package->end();
339 
340   ASSERT_NE(end, iter);
341   ASSERT_EQ(0x7f010000u, *iter++);
342   ASSERT_EQ(0x7f010001u, *iter++);
343   ASSERT_EQ(0x7f020000u, *iter++);
344   ASSERT_EQ(0x7f020001u, *iter++);
345   ASSERT_EQ(0x7f030000u, *iter++);
346   ASSERT_EQ(0x7f030001u, *iter++);
347   ASSERT_EQ(0x7f030002u, *iter++);  // note: string without default, excluded by aapt2 dump
348   ASSERT_EQ(0x7f040000u, *iter++);
349   ASSERT_EQ(0x7f040001u, *iter++);
350   ASSERT_EQ(0x7f040002u, *iter++);
351   ASSERT_EQ(0x7f040003u, *iter++);
352   ASSERT_EQ(0x7f040004u, *iter++);
353   ASSERT_EQ(0x7f040005u, *iter++);
354   ASSERT_EQ(0x7f040006u, *iter++);
355   ASSERT_EQ(0x7f040007u, *iter++);
356   ASSERT_EQ(0x7f040008u, *iter++);
357   ASSERT_EQ(0x7f040009u, *iter++);
358   ASSERT_EQ(0x7f04000au, *iter++);
359   ASSERT_EQ(0x7f04000bu, *iter++);
360   ASSERT_EQ(0x7f04000cu, *iter++);
361   ASSERT_EQ(0x7f04000du, *iter++);
362   ASSERT_EQ(0x7f050000u, *iter++);
363   ASSERT_EQ(0x7f050001u, *iter++);
364   ASSERT_EQ(0x7f060000u, *iter++);
365   ASSERT_EQ(0x7f070000u, *iter++);
366   ASSERT_EQ(0x7f070001u, *iter++);
367   ASSERT_EQ(0x7f070002u, *iter++);
368   ASSERT_EQ(0x7f070003u, *iter++);
369   ASSERT_EQ(end, iter);
370 }
371 
TEST(LoadedArscTest,GetOverlayableMap)372 TEST(LoadedArscTest, GetOverlayableMap) {
373   std::string contents;
374   ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/overlayable/overlayable.apk",
375                                       "resources.arsc", &contents));
376 
377   std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
378   ASSERT_NE(nullptr, loaded_arsc);
379 
380   const std::vector<std::unique_ptr<const LoadedPackage>>& packages = loaded_arsc->GetPackages();
381   ASSERT_EQ(1u, packages.size());
382   ASSERT_EQ(std::string("com.android.overlayable"), packages[0]->GetPackageName());
383 
384   const auto map = packages[0]->GetOverlayableMap();
385   ASSERT_EQ(2, map.size());
386   ASSERT_EQ(map.at("OverlayableResources1"), "overlay://theme");
387   ASSERT_EQ(map.at("OverlayableResources2"), "overlay://com.android.overlayable");
388 }
389 
390 // structs with size fields (like Res_value, ResTable_entry) should be
391 // backwards and forwards compatible (aka checking the size field against
392 // sizeof(Res_value) might not be backwards compatible.
393 // TEST(LoadedArscTest, LoadingShouldBeForwardsAndBackwardsCompatible) { ASSERT_TRUE(false); }
394 
395 }  // namespace android
396