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