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(GetLibCoreDexFileNames()[0].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_EQ(type_id, java_lang_dex_file_->FindTypeId(type_str));
    301     ASSERT_TRUE(type_id != nullptr);
    302     EXPECT_EQ(java_lang_dex_file_->GetIndexForTypeId(*type_id), i);
    303   }
    304 }
    305 
    306 TEST_F(DexFileTest, FindProtoId) {
    307   for (size_t i = 0; i < java_lang_dex_file_->NumProtoIds(); i++) {
    308     const DexFile::ProtoId& to_find = java_lang_dex_file_->GetProtoId(i);
    309     const DexFile::TypeList* to_find_tl = java_lang_dex_file_->GetProtoParameters(to_find);
    310     std::vector<uint16_t> to_find_types;
    311     if (to_find_tl != nullptr) {
    312       for (size_t j = 0; j < to_find_tl->Size(); j++) {
    313         to_find_types.push_back(to_find_tl->GetTypeItem(j).type_idx_);
    314       }
    315     }
    316     const DexFile::ProtoId* found =
    317         java_lang_dex_file_->FindProtoId(to_find.return_type_idx_, to_find_types);
    318     ASSERT_TRUE(found != nullptr);
    319     EXPECT_EQ(java_lang_dex_file_->GetIndexForProtoId(*found), i);
    320   }
    321 }
    322 
    323 TEST_F(DexFileTest, FindMethodId) {
    324   for (size_t i = 0; i < java_lang_dex_file_->NumMethodIds(); i++) {
    325     const DexFile::MethodId& to_find = java_lang_dex_file_->GetMethodId(i);
    326     const DexFile::TypeId& klass = java_lang_dex_file_->GetTypeId(to_find.class_idx_);
    327     const DexFile::StringId& name = java_lang_dex_file_->GetStringId(to_find.name_idx_);
    328     const DexFile::ProtoId& signature = java_lang_dex_file_->GetProtoId(to_find.proto_idx_);
    329     const DexFile::MethodId* found = java_lang_dex_file_->FindMethodId(klass, name, signature);
    330     ASSERT_TRUE(found != nullptr) << "Didn't find method " << i << ": "
    331         << java_lang_dex_file_->StringByTypeIdx(to_find.class_idx_) << "."
    332         << java_lang_dex_file_->GetStringData(name)
    333         << java_lang_dex_file_->GetMethodSignature(to_find);
    334     EXPECT_EQ(java_lang_dex_file_->GetIndexForMethodId(*found), i);
    335   }
    336 }
    337 
    338 TEST_F(DexFileTest, FindFieldId) {
    339   for (size_t i = 0; i < java_lang_dex_file_->NumFieldIds(); i++) {
    340     const DexFile::FieldId& to_find = java_lang_dex_file_->GetFieldId(i);
    341     const DexFile::TypeId& klass = java_lang_dex_file_->GetTypeId(to_find.class_idx_);
    342     const DexFile::StringId& name = java_lang_dex_file_->GetStringId(to_find.name_idx_);
    343     const DexFile::TypeId& type = java_lang_dex_file_->GetTypeId(to_find.type_idx_);
    344     const DexFile::FieldId* found = java_lang_dex_file_->FindFieldId(klass, name, type);
    345     ASSERT_TRUE(found != nullptr) << "Didn't find field " << i << ": "
    346         << java_lang_dex_file_->StringByTypeIdx(to_find.type_idx_) << " "
    347         << java_lang_dex_file_->StringByTypeIdx(to_find.class_idx_) << "."
    348         << java_lang_dex_file_->GetStringData(name);
    349     EXPECT_EQ(java_lang_dex_file_->GetIndexForFieldId(*found), i);
    350   }
    351 }
    352 
    353 TEST_F(DexFileTest, GetMultiDexClassesDexName) {
    354   ASSERT_EQ("classes.dex", DexFile::GetMultiDexClassesDexName(0));
    355   ASSERT_EQ("classes2.dex", DexFile::GetMultiDexClassesDexName(1));
    356   ASSERT_EQ("classes3.dex", DexFile::GetMultiDexClassesDexName(2));
    357   ASSERT_EQ("classes100.dex", DexFile::GetMultiDexClassesDexName(99));
    358 }
    359 
    360 TEST_F(DexFileTest, GetMultiDexLocation) {
    361   std::string dex_location_str = "/system/app/framework.jar";
    362   const char* dex_location = dex_location_str.c_str();
    363   ASSERT_EQ("/system/app/framework.jar", DexFile::GetMultiDexLocation(0, dex_location));
    364   ASSERT_EQ("/system/app/framework.jar:classes2.dex",
    365             DexFile::GetMultiDexLocation(1, dex_location));
    366   ASSERT_EQ("/system/app/framework.jar:classes101.dex",
    367             DexFile::GetMultiDexLocation(100, dex_location));
    368 }
    369 
    370 TEST_F(DexFileTest, GetDexCanonicalLocation) {
    371   ScratchFile file;
    372   UniqueCPtr<const char[]> dex_location_real(realpath(file.GetFilename().c_str(), nullptr));
    373   std::string dex_location(dex_location_real.get());
    374 
    375   ASSERT_EQ(dex_location, DexFile::GetDexCanonicalLocation(dex_location.c_str()));
    376   std::string multidex_location = DexFile::GetMultiDexLocation(1, dex_location.c_str());
    377   ASSERT_EQ(multidex_location, DexFile::GetDexCanonicalLocation(multidex_location.c_str()));
    378 
    379   std::string dex_location_sym = dex_location + "symlink";
    380   ASSERT_EQ(0, symlink(dex_location.c_str(), dex_location_sym.c_str()));
    381 
    382   ASSERT_EQ(dex_location, DexFile::GetDexCanonicalLocation(dex_location_sym.c_str()));
    383 
    384   std::string multidex_location_sym = DexFile::GetMultiDexLocation(1, dex_location_sym.c_str());
    385   ASSERT_EQ(multidex_location, DexFile::GetDexCanonicalLocation(multidex_location_sym.c_str()));
    386 
    387   ASSERT_EQ(0, unlink(dex_location_sym.c_str()));
    388 }
    389 
    390 TEST(DexFileUtilsTest, GetBaseLocationAndMultiDexSuffix) {
    391   EXPECT_EQ("/foo/bar/baz.jar", DexFile::GetBaseLocation("/foo/bar/baz.jar"));
    392   EXPECT_EQ("/foo/bar/baz.jar", DexFile::GetBaseLocation("/foo/bar/baz.jar:classes2.dex"));
    393   EXPECT_EQ("/foo/bar/baz.jar", DexFile::GetBaseLocation("/foo/bar/baz.jar:classes8.dex"));
    394   EXPECT_EQ("", DexFile::GetMultiDexSuffix("/foo/bar/baz.jar"));
    395   EXPECT_EQ(":classes2.dex", DexFile::GetMultiDexSuffix("/foo/bar/baz.jar:classes2.dex"));
    396   EXPECT_EQ(":classes8.dex", DexFile::GetMultiDexSuffix("/foo/bar/baz.jar:classes8.dex"));
    397 }
    398 
    399 }  // namespace art
    400