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 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 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 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 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 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 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 // 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: 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 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 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 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 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