Home | History | Annotate | Download | only in tests
      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