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