Home | History | Annotate | Download | only in runtime
      1 /*
      2  * Copyright (C) 2011 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 "dex_file.h"
     18 
     19 #include <memory>
     20 
     21 #include "base/stl_util.h"
     22 #include "base/unix_file/fd_file.h"
     23 #include "common_runtime_test.h"
     24 #include "dex_file-inl.h"
     25 #include "os.h"
     26 #include "scoped_thread_state_change.h"
     27 #include "thread-inl.h"
     28 
     29 namespace art {
     30 
     31 class DexFileTest : public CommonRuntimeTest {};
     32 
     33 TEST_F(DexFileTest, Open) {
     34   ScopedObjectAccess soa(Thread::Current());
     35   std::unique_ptr<const DexFile> dex(OpenTestDexFile("Nested"));
     36   ASSERT_TRUE(dex.get() != nullptr);
     37 }
     38 
     39 static const uint8_t kBase64Map[256] = {
     40   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
     41   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
     42   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
     43   255, 255, 255, 255, 255, 255, 255,  62, 255, 255, 255,  63,
     44   52,  53,  54,  55,  56,  57,  58,  59,  60,  61, 255, 255,
     45   255, 254, 255, 255, 255,   0,   1,   2,   3,   4,   5,   6,
     46     7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,  // NOLINT
     47    19,  20,  21,  22,  23,  24,  25, 255, 255, 255, 255, 255,  // NOLINT
     48   255,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,
     49    37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  // NOLINT
     50    49,  50,  51, 255, 255, 255, 255, 255, 255, 255, 255, 255,  // NOLINT
     51   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
     52   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
     53   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
     54   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
     55   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
     56   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
     57   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
     58   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
     59   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
     60   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
     61   255, 255, 255, 255
     62 };
     63 
     64 static inline uint8_t* DecodeBase64(const char* src, size_t* dst_size) {
     65   std::vector<uint8_t> tmp;
     66   uint32_t t = 0, y = 0;
     67   int g = 3;
     68   for (size_t i = 0; src[i] != '\0'; ++i) {
     69     uint8_t c = kBase64Map[src[i] & 0xFF];
     70     if (c == 255) continue;
     71     // the final = symbols are read and used to trim the remaining bytes
     72     if (c == 254) {
     73       c = 0;
     74       // prevent g < 0 which would potentially allow an overflow later
     75       if (--g < 0) {
     76         *dst_size = 0;
     77         return nullptr;
     78       }
     79     } else if (g != 3) {
     80       // we only allow = to be at the end
     81       *dst_size = 0;
     82       return nullptr;
     83     }
     84     t = (t << 6) | c;
     85     if (++y == 4) {
     86       tmp.push_back((t >> 16) & 255);
     87       if (g > 1) {
     88         tmp.push_back((t >> 8) & 255);
     89       }
     90       if (g > 2) {
     91         tmp.push_back(t & 255);
     92       }
     93       y = t = 0;
     94     }
     95   }
     96   if (y != 0) {
     97     *dst_size = 0;
     98     return nullptr;
     99   }
    100   std::unique_ptr<uint8_t[]> dst(new uint8_t[tmp.size()]);
    101   if (dst_size != nullptr) {
    102     *dst_size = tmp.size();
    103   } else {
    104     *dst_size = 0;
    105   }
    106   std::copy(tmp.begin(), tmp.end(), dst.get());
    107   return dst.release();
    108 }
    109 
    110 // Although this is the same content logically as the Nested test dex,
    111 // the DexFileHeader test is sensitive to subtle changes in the
    112 // contents due to the checksum etc, so we embed the exact input here.
    113 //
    114 // class Nested {
    115 //     class Inner {
    116 //     }
    117 // }
    118 static const char kRawDex[] =
    119   "ZGV4CjAzNQAQedgAe7gM1B/WHsWJ6L7lGAISGC7yjD2IAwAAcAAAAHhWNBIAAAAAAAAAAMQCAAAP"
    120   "AAAAcAAAAAcAAACsAAAAAgAAAMgAAAABAAAA4AAAAAMAAADoAAAAAgAAAAABAABIAgAAQAEAAK4B"
    121   "AAC2AQAAvQEAAM0BAADXAQAA+wEAABsCAAA+AgAAUgIAAF8CAABiAgAAZgIAAHMCAAB5AgAAgQIA"
    122   "AAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAkAAAAJAAAABgAAAAAAAAAKAAAABgAAAKgBAAAAAAEA"
    123   "DQAAAAAAAQAAAAAAAQAAAAAAAAAFAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAIAAAAiAEAAKsCAAAA"
    124   "AAAAAQAAAAAAAAAFAAAAAAAAAAgAAACYAQAAuAIAAAAAAAACAAAAlAIAAJoCAAABAAAAowIAAAIA"
    125   "AgABAAAAiAIAAAYAAABbAQAAcBACAAAADgABAAEAAQAAAI4CAAAEAAAAcBACAAAADgBAAQAAAAAA"
    126   "AAAAAAAAAAAATAEAAAAAAAAAAAAAAAAAAAEAAAABAAY8aW5pdD4ABUlubmVyAA5MTmVzdGVkJElu"
    127   "bmVyOwAITE5lc3RlZDsAIkxkYWx2aWsvYW5ub3RhdGlvbi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2"
    128   "aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAhTGRhbHZpay9hbm5vdGF0aW9uL01lbWJlckNsYXNz"
    129   "ZXM7ABJMamF2YS9sYW5nL09iamVjdDsAC05lc3RlZC5qYXZhAAFWAAJWTAALYWNjZXNzRmxhZ3MA"
    130   "BG5hbWUABnRoaXMkMAAFdmFsdWUAAgEABw4AAQAHDjwAAgIBDhgBAgMCCwQADBcBAgQBDhwBGAAA"
    131   "AQEAAJAgAICABNQCAAABAAGAgATwAgAAEAAAAAAAAAABAAAAAAAAAAEAAAAPAAAAcAAAAAIAAAAH"
    132   "AAAArAAAAAMAAAACAAAAyAAAAAQAAAABAAAA4AAAAAUAAAADAAAA6AAAAAYAAAACAAAAAAEAAAMQ"
    133   "AAACAAAAQAEAAAEgAAACAAAAVAEAAAYgAAACAAAAiAEAAAEQAAABAAAAqAEAAAIgAAAPAAAArgEA"
    134   "AAMgAAACAAAAiAIAAAQgAAADAAAAlAIAAAAgAAACAAAAqwIAAAAQAAABAAAAxAIAAA==";
    135 
    136 static std::unique_ptr<const DexFile> OpenDexFileBase64(const char* base64,
    137                                                         const char* location) {
    138   // decode base64
    139   CHECK(base64 != nullptr);
    140   size_t length;
    141   std::unique_ptr<uint8_t[]> dex_bytes(DecodeBase64(base64, &length));
    142   CHECK(dex_bytes.get() != nullptr);
    143 
    144   // write to provided file
    145   std::unique_ptr<File> file(OS::CreateEmptyFile(location));
    146   CHECK(file.get() != nullptr);
    147   if (!file->WriteFully(dex_bytes.get(), length)) {
    148     PLOG(FATAL) << "Failed to write base64 as dex file";
    149   }
    150   if (file->FlushCloseOrErase() != 0) {
    151     PLOG(FATAL) << "Could not flush and close test file.";
    152   }
    153   file.reset();
    154 
    155   // read dex file
    156   ScopedObjectAccess soa(Thread::Current());
    157   std::string error_msg;
    158   std::vector<std::unique_ptr<const DexFile>> tmp;
    159   bool success = DexFile::Open(location, location, &error_msg, &tmp);
    160   CHECK(success) << error_msg;
    161   EXPECT_EQ(1U, tmp.size());
    162   std::unique_ptr<const DexFile> dex_file = std::move(tmp[0]);
    163   EXPECT_EQ(PROT_READ, dex_file->GetPermissions());
    164   EXPECT_TRUE(dex_file->IsReadOnly());
    165   return dex_file;
    166 }
    167 
    168 TEST_F(DexFileTest, Header) {
    169   ScratchFile tmp;
    170   std::unique_ptr<const DexFile> raw(OpenDexFileBase64(kRawDex, tmp.GetFilename().c_str()));
    171   ASSERT_TRUE(raw.get() != nullptr);
    172 
    173   const DexFile::Header& header = raw->GetHeader();
    174   // TODO: header.magic_
    175   EXPECT_EQ(0x00d87910U, header.checksum_);
    176   // TODO: header.signature_
    177   EXPECT_EQ(904U, header.file_size_);
    178   EXPECT_EQ(112U, header.header_size_);
    179   EXPECT_EQ(0U, header.link_size_);
    180   EXPECT_EQ(0U, header.link_off_);
    181   EXPECT_EQ(15U, header.string_ids_size_);
    182   EXPECT_EQ(112U, header.string_ids_off_);
    183   EXPECT_EQ(7U, header.type_ids_size_);
    184   EXPECT_EQ(172U, header.type_ids_off_);
    185   EXPECT_EQ(2U, header.proto_ids_size_);
    186   EXPECT_EQ(200U, header.proto_ids_off_);
    187   EXPECT_EQ(1U, header.field_ids_size_);
    188   EXPECT_EQ(224U, header.field_ids_off_);
    189   EXPECT_EQ(3U, header.method_ids_size_);
    190   EXPECT_EQ(232U, header.method_ids_off_);
    191   EXPECT_EQ(2U, header.class_defs_size_);
    192   EXPECT_EQ(256U, header.class_defs_off_);
    193   EXPECT_EQ(584U, header.data_size_);
    194   EXPECT_EQ(320U, header.data_off_);
    195 
    196   EXPECT_EQ(header.checksum_, raw->GetLocationChecksum());
    197 }
    198 
    199 TEST_F(DexFileTest, GetLocationChecksum) {
    200   ScopedObjectAccess soa(Thread::Current());
    201   std::unique_ptr<const DexFile> raw(OpenTestDexFile("Main"));
    202   EXPECT_NE(raw->GetHeader().checksum_, raw->GetLocationChecksum());
    203 }
    204 
    205 TEST_F(DexFileTest, GetChecksum) {
    206   uint32_t checksum;
    207   ScopedObjectAccess soa(Thread::Current());
    208   std::string error_msg;
    209   EXPECT_TRUE(DexFile::GetChecksum(GetLibCoreDexFileName().c_str(), &checksum, &error_msg))
    210       << error_msg;
    211   EXPECT_EQ(java_lang_dex_file_->GetLocationChecksum(), checksum);
    212 }
    213 
    214 TEST_F(DexFileTest, ClassDefs) {
    215   ScopedObjectAccess soa(Thread::Current());
    216   std::unique_ptr<const DexFile> raw(OpenTestDexFile("Nested"));
    217   ASSERT_TRUE(raw.get() != nullptr);
    218   EXPECT_EQ(2U, raw->NumClassDefs());
    219 
    220   const DexFile::ClassDef& c0 = raw->GetClassDef(0);
    221   EXPECT_STREQ("LNested$Inner;", raw->GetClassDescriptor(c0));
    222 
    223   const DexFile::ClassDef& c1 = raw->GetClassDef(1);
    224   EXPECT_STREQ("LNested;", raw->GetClassDescriptor(c1));
    225 }
    226 
    227 TEST_F(DexFileTest, GetMethodSignature) {
    228   ScopedObjectAccess soa(Thread::Current());
    229   std::unique_ptr<const DexFile> raw(OpenTestDexFile("GetMethodSignature"));
    230   ASSERT_TRUE(raw.get() != nullptr);
    231   EXPECT_EQ(1U, raw->NumClassDefs());
    232 
    233   const DexFile::ClassDef& class_def = raw->GetClassDef(0);
    234   ASSERT_STREQ("LGetMethodSignature;", raw->GetClassDescriptor(class_def));
    235 
    236   const uint8_t* class_data = raw->GetClassData(class_def);
    237   ASSERT_TRUE(class_data != nullptr);
    238   ClassDataItemIterator it(*raw, class_data);
    239 
    240   EXPECT_EQ(1u, it.NumDirectMethods());
    241 
    242   // Check the signature for the static initializer.
    243   {
    244     ASSERT_EQ(1U, it.NumDirectMethods());
    245     const DexFile::MethodId& method_id = raw->GetMethodId(it.GetMemberIndex());
    246     const char* name = raw->StringDataByIdx(method_id.name_idx_);
    247     ASSERT_STREQ("<init>", name);
    248     std::string signature(raw->GetMethodSignature(method_id).ToString());
    249     ASSERT_EQ("()V", signature);
    250   }
    251 
    252   // Check both virtual methods.
    253   ASSERT_EQ(2U, it.NumVirtualMethods());
    254   {
    255     it.Next();
    256     const DexFile::MethodId& method_id = raw->GetMethodId(it.GetMemberIndex());
    257 
    258     const char* name = raw->StringDataByIdx(method_id.name_idx_);
    259     ASSERT_STREQ("m1", name);
    260 
    261     std::string signature(raw->GetMethodSignature(method_id).ToString());
    262     ASSERT_EQ("(IDJLjava/lang/Object;)Ljava/lang/Float;", signature);
    263   }
    264 
    265   {
    266     it.Next();
    267     const DexFile::MethodId& method_id = raw->GetMethodId(it.GetMemberIndex());
    268 
    269     const char* name = raw->StringDataByIdx(method_id.name_idx_);
    270     ASSERT_STREQ("m2", name);
    271 
    272     std::string signature(raw->GetMethodSignature(method_id).ToString());
    273     ASSERT_EQ("(ZSC)LGetMethodSignature;", signature);
    274   }
    275 }
    276 
    277 TEST_F(DexFileTest, FindStringId) {
    278   ScopedObjectAccess soa(Thread::Current());
    279   std::unique_ptr<const DexFile> raw(OpenTestDexFile("GetMethodSignature"));
    280   ASSERT_TRUE(raw.get() != nullptr);
    281   EXPECT_EQ(1U, raw->NumClassDefs());
    282 
    283   const char* strings[] = { "LGetMethodSignature;", "Ljava/lang/Float;", "Ljava/lang/Object;",
    284       "D", "I", "J", nullptr };
    285   for (size_t i = 0; strings[i] != nullptr; i++) {
    286     const char* str = strings[i];
    287     const DexFile::StringId* str_id = raw->FindStringId(str);
    288     const char* dex_str = raw->GetStringData(*str_id);
    289     EXPECT_STREQ(dex_str, str);
    290   }
    291 }
    292 
    293 TEST_F(DexFileTest, FindTypeId) {
    294   for (size_t i = 0; i < java_lang_dex_file_->NumTypeIds(); i++) {
    295     const char* type_str = java_lang_dex_file_->StringByTypeIdx(i);
    296     const DexFile::StringId* type_str_id = java_lang_dex_file_->FindStringId(type_str);
    297     ASSERT_TRUE(type_str_id != nullptr);
    298     uint32_t type_str_idx = java_lang_dex_file_->GetIndexForStringId(*type_str_id);
    299     const DexFile::TypeId* type_id = java_lang_dex_file_->FindTypeId(type_str_idx);
    300     ASSERT_TRUE(type_id != nullptr);
    301     EXPECT_EQ(java_lang_dex_file_->GetIndexForTypeId(*type_id), i);
    302   }
    303 }
    304 
    305 TEST_F(DexFileTest, FindProtoId) {
    306   for (size_t i = 0; i < java_lang_dex_file_->NumProtoIds(); i++) {
    307     const DexFile::ProtoId& to_find = java_lang_dex_file_->GetProtoId(i);
    308     const DexFile::TypeList* to_find_tl = java_lang_dex_file_->GetProtoParameters(to_find);
    309     std::vector<uint16_t> to_find_types;
    310     if (to_find_tl != nullptr) {
    311       for (size_t j = 0; j < to_find_tl->Size(); j++) {
    312         to_find_types.push_back(to_find_tl->GetTypeItem(j).type_idx_);
    313       }
    314     }
    315     const DexFile::ProtoId* found =
    316         java_lang_dex_file_->FindProtoId(to_find.return_type_idx_, to_find_types);
    317     ASSERT_TRUE(found != nullptr);
    318     EXPECT_EQ(java_lang_dex_file_->GetIndexForProtoId(*found), i);
    319   }
    320 }
    321 
    322 TEST_F(DexFileTest, FindMethodId) {
    323   for (size_t i = 0; i < java_lang_dex_file_->NumMethodIds(); i++) {
    324     const DexFile::MethodId& to_find = java_lang_dex_file_->GetMethodId(i);
    325     const DexFile::TypeId& klass = java_lang_dex_file_->GetTypeId(to_find.class_idx_);
    326     const DexFile::StringId& name = java_lang_dex_file_->GetStringId(to_find.name_idx_);
    327     const DexFile::ProtoId& signature = java_lang_dex_file_->GetProtoId(to_find.proto_idx_);
    328     const DexFile::MethodId* found = java_lang_dex_file_->FindMethodId(klass, name, signature);
    329     ASSERT_TRUE(found != nullptr) << "Didn't find method " << i << ": "
    330         << java_lang_dex_file_->StringByTypeIdx(to_find.class_idx_) << "."
    331         << java_lang_dex_file_->GetStringData(name)
    332         << java_lang_dex_file_->GetMethodSignature(to_find);
    333     EXPECT_EQ(java_lang_dex_file_->GetIndexForMethodId(*found), i);
    334   }
    335 }
    336 
    337 TEST_F(DexFileTest, FindFieldId) {
    338   for (size_t i = 0; i < java_lang_dex_file_->NumFieldIds(); i++) {
    339     const DexFile::FieldId& to_find = java_lang_dex_file_->GetFieldId(i);
    340     const DexFile::TypeId& klass = java_lang_dex_file_->GetTypeId(to_find.class_idx_);
    341     const DexFile::StringId& name = java_lang_dex_file_->GetStringId(to_find.name_idx_);
    342     const DexFile::TypeId& type = java_lang_dex_file_->GetTypeId(to_find.type_idx_);
    343     const DexFile::FieldId* found = java_lang_dex_file_->FindFieldId(klass, name, type);
    344     ASSERT_TRUE(found != nullptr) << "Didn't find field " << i << ": "
    345         << java_lang_dex_file_->StringByTypeIdx(to_find.type_idx_) << " "
    346         << java_lang_dex_file_->StringByTypeIdx(to_find.class_idx_) << "."
    347         << java_lang_dex_file_->GetStringData(name);
    348     EXPECT_EQ(java_lang_dex_file_->GetIndexForFieldId(*found), i);
    349   }
    350 }
    351 
    352 TEST_F(DexFileTest, GetMultiDexClassesDexName) {
    353   ASSERT_EQ("classes.dex", DexFile::GetMultiDexClassesDexName(0));
    354   ASSERT_EQ("classes2.dex", DexFile::GetMultiDexClassesDexName(1));
    355   ASSERT_EQ("classes3.dex", DexFile::GetMultiDexClassesDexName(2));
    356   ASSERT_EQ("classes100.dex", DexFile::GetMultiDexClassesDexName(99));
    357 }
    358 
    359 TEST_F(DexFileTest, GetMultiDexLocation) {
    360   std::string dex_location_str = "/system/app/framework.jar";
    361   const char* dex_location = dex_location_str.c_str();
    362   ASSERT_EQ("/system/app/framework.jar", DexFile::GetMultiDexLocation(0, dex_location));
    363   ASSERT_EQ("/system/app/framework.jar:classes2.dex",
    364             DexFile::GetMultiDexLocation(1, dex_location));
    365   ASSERT_EQ("/system/app/framework.jar:classes101.dex",
    366             DexFile::GetMultiDexLocation(100, dex_location));
    367 }
    368 
    369 TEST_F(DexFileTest, GetDexCanonicalLocation) {
    370   ScratchFile file;
    371   UniqueCPtr<const char[]> dex_location_real(realpath(file.GetFilename().c_str(), nullptr));
    372   std::string dex_location(dex_location_real.get());
    373 
    374   ASSERT_EQ(dex_location, DexFile::GetDexCanonicalLocation(dex_location.c_str()));
    375   std::string multidex_location = DexFile::GetMultiDexLocation(1, dex_location.c_str());
    376   ASSERT_EQ(multidex_location, DexFile::GetDexCanonicalLocation(multidex_location.c_str()));
    377 
    378   std::string dex_location_sym = dex_location + "symlink";
    379   ASSERT_EQ(0, symlink(dex_location.c_str(), dex_location_sym.c_str()));
    380 
    381   ASSERT_EQ(dex_location, DexFile::GetDexCanonicalLocation(dex_location_sym.c_str()));
    382 
    383   std::string multidex_location_sym = DexFile::GetMultiDexLocation(1, dex_location_sym.c_str());
    384   ASSERT_EQ(multidex_location, DexFile::GetDexCanonicalLocation(multidex_location_sym.c_str()));
    385 
    386   ASSERT_EQ(0, unlink(dex_location_sym.c_str()));
    387 }
    388 
    389 TEST(DexFileUtilsTest, GetBaseLocationAndMultiDexSuffix) {
    390   EXPECT_EQ("/foo/bar/baz.jar", DexFile::GetBaseLocation("/foo/bar/baz.jar"));
    391   EXPECT_EQ("/foo/bar/baz.jar", DexFile::GetBaseLocation("/foo/bar/baz.jar:classes2.dex"));
    392   EXPECT_EQ("/foo/bar/baz.jar", DexFile::GetBaseLocation("/foo/bar/baz.jar:classes8.dex"));
    393   EXPECT_EQ("", DexFile::GetMultiDexSuffix("/foo/bar/baz.jar"));
    394   EXPECT_EQ(":classes2.dex", DexFile::GetMultiDexSuffix("/foo/bar/baz.jar:classes2.dex"));
    395   EXPECT_EQ(":classes8.dex", DexFile::GetMultiDexSuffix("/foo/bar/baz.jar:classes8.dex"));
    396 }
    397 
    398 }  // namespace art
    399