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  if (file->FlushCloseOrErase() != 0) {
150    PLOG(FATAL) << "Could not flush and close test file.";
151  }
152  file.reset();
153
154  // read dex file
155  ScopedObjectAccess soa(Thread::Current());
156  std::string error_msg;
157  std::vector<const DexFile*> tmp;
158  bool success = DexFile::Open(location, location, &error_msg, &tmp);
159  CHECK(success) << error_msg;
160  EXPECT_EQ(1U, tmp.size());
161  const DexFile* dex_file = tmp[0];
162  EXPECT_EQ(PROT_READ, dex_file->GetPermissions());
163  EXPECT_TRUE(dex_file->IsReadOnly());
164  return dex_file;
165}
166
167TEST_F(DexFileTest, Header) {
168  ScratchFile tmp;
169  std::unique_ptr<const DexFile> raw(OpenDexFileBase64(kRawDex, tmp.GetFilename().c_str()));
170  ASSERT_TRUE(raw.get() != NULL);
171
172  const DexFile::Header& header = raw->GetHeader();
173  // TODO: header.magic_
174  EXPECT_EQ(0x00d87910U, header.checksum_);
175  // TODO: header.signature_
176  EXPECT_EQ(904U, header.file_size_);
177  EXPECT_EQ(112U, header.header_size_);
178  EXPECT_EQ(0U, header.link_size_);
179  EXPECT_EQ(0U, header.link_off_);
180  EXPECT_EQ(15U, header.string_ids_size_);
181  EXPECT_EQ(112U, header.string_ids_off_);
182  EXPECT_EQ(7U, header.type_ids_size_);
183  EXPECT_EQ(172U, header.type_ids_off_);
184  EXPECT_EQ(2U, header.proto_ids_size_);
185  EXPECT_EQ(200U, header.proto_ids_off_);
186  EXPECT_EQ(1U, header.field_ids_size_);
187  EXPECT_EQ(224U, header.field_ids_off_);
188  EXPECT_EQ(3U, header.method_ids_size_);
189  EXPECT_EQ(232U, header.method_ids_off_);
190  EXPECT_EQ(2U, header.class_defs_size_);
191  EXPECT_EQ(256U, header.class_defs_off_);
192  EXPECT_EQ(584U, header.data_size_);
193  EXPECT_EQ(320U, header.data_off_);
194
195  EXPECT_EQ(header.checksum_, raw->GetLocationChecksum());
196}
197
198TEST_F(DexFileTest, GetLocationChecksum) {
199  ScopedObjectAccess soa(Thread::Current());
200  const DexFile* raw(OpenTestDexFile("Main"));
201  EXPECT_NE(raw->GetHeader().checksum_, raw->GetLocationChecksum());
202}
203
204TEST_F(DexFileTest, GetChecksum) {
205  uint32_t checksum;
206  ScopedObjectAccess soa(Thread::Current());
207  std::string error_msg;
208  EXPECT_TRUE(DexFile::GetChecksum(GetLibCoreDexFileName().c_str(), &checksum, &error_msg))
209      << error_msg;
210  EXPECT_EQ(java_lang_dex_file_->GetLocationChecksum(), checksum);
211}
212
213TEST_F(DexFileTest, ClassDefs) {
214  ScopedObjectAccess soa(Thread::Current());
215  const DexFile* raw(OpenTestDexFile("Nested"));
216  ASSERT_TRUE(raw != NULL);
217  EXPECT_EQ(2U, raw->NumClassDefs());
218
219  const DexFile::ClassDef& c0 = raw->GetClassDef(0);
220  EXPECT_STREQ("LNested$Inner;", raw->GetClassDescriptor(c0));
221
222  const DexFile::ClassDef& c1 = raw->GetClassDef(1);
223  EXPECT_STREQ("LNested;", raw->GetClassDescriptor(c1));
224}
225
226TEST_F(DexFileTest, GetMethodSignature) {
227  ScopedObjectAccess soa(Thread::Current());
228  const DexFile* raw(OpenTestDexFile("GetMethodSignature"));
229  ASSERT_TRUE(raw != NULL);
230  EXPECT_EQ(1U, raw->NumClassDefs());
231
232  const DexFile::ClassDef& class_def = raw->GetClassDef(0);
233  ASSERT_STREQ("LGetMethodSignature;", raw->GetClassDescriptor(class_def));
234
235  const byte* class_data = raw->GetClassData(class_def);
236  ASSERT_TRUE(class_data != NULL);
237  ClassDataItemIterator it(*raw, class_data);
238
239  EXPECT_EQ(1u, it.NumDirectMethods());
240
241  // Check the signature for the static initializer.
242  {
243    ASSERT_EQ(1U, it.NumDirectMethods());
244    const DexFile::MethodId& method_id = raw->GetMethodId(it.GetMemberIndex());
245    const char* name = raw->StringDataByIdx(method_id.name_idx_);
246    ASSERT_STREQ("<init>", name);
247    std::string signature(raw->GetMethodSignature(method_id).ToString());
248    ASSERT_EQ("()V", signature);
249  }
250
251  // Check both virtual methods.
252  ASSERT_EQ(2U, it.NumVirtualMethods());
253  {
254    it.Next();
255    const DexFile::MethodId& method_id = raw->GetMethodId(it.GetMemberIndex());
256
257    const char* name = raw->StringDataByIdx(method_id.name_idx_);
258    ASSERT_STREQ("m1", name);
259
260    std::string signature(raw->GetMethodSignature(method_id).ToString());
261    ASSERT_EQ("(IDJLjava/lang/Object;)Ljava/lang/Float;", signature);
262  }
263
264  {
265    it.Next();
266    const DexFile::MethodId& method_id = raw->GetMethodId(it.GetMemberIndex());
267
268    const char* name = raw->StringDataByIdx(method_id.name_idx_);
269    ASSERT_STREQ("m2", name);
270
271    std::string signature(raw->GetMethodSignature(method_id).ToString());
272    ASSERT_EQ("(ZSC)LGetMethodSignature;", signature);
273  }
274}
275
276TEST_F(DexFileTest, FindStringId) {
277  ScopedObjectAccess soa(Thread::Current());
278  const DexFile* raw(OpenTestDexFile("GetMethodSignature"));
279  ASSERT_TRUE(raw != NULL);
280  EXPECT_EQ(1U, raw->NumClassDefs());
281
282  const char* strings[] = { "LGetMethodSignature;", "Ljava/lang/Float;", "Ljava/lang/Object;",
283      "D", "I", "J", NULL };
284  for (size_t i = 0; strings[i] != NULL; i++) {
285    const char* str = strings[i];
286    const DexFile::StringId* str_id = raw->FindStringId(str);
287    const char* dex_str = raw->GetStringData(*str_id);
288    EXPECT_STREQ(dex_str, str);
289  }
290}
291
292TEST_F(DexFileTest, FindTypeId) {
293  for (size_t i = 0; i < java_lang_dex_file_->NumTypeIds(); i++) {
294    const char* type_str = java_lang_dex_file_->StringByTypeIdx(i);
295    const DexFile::StringId* type_str_id = java_lang_dex_file_->FindStringId(type_str);
296    ASSERT_TRUE(type_str_id != NULL);
297    uint32_t type_str_idx = java_lang_dex_file_->GetIndexForStringId(*type_str_id);
298    const DexFile::TypeId* type_id = java_lang_dex_file_->FindTypeId(type_str_idx);
299    ASSERT_TRUE(type_id != NULL);
300    EXPECT_EQ(java_lang_dex_file_->GetIndexForTypeId(*type_id), i);
301  }
302}
303
304TEST_F(DexFileTest, FindProtoId) {
305  for (size_t i = 0; i < java_lang_dex_file_->NumProtoIds(); i++) {
306    const DexFile::ProtoId& to_find = java_lang_dex_file_->GetProtoId(i);
307    const DexFile::TypeList* to_find_tl = java_lang_dex_file_->GetProtoParameters(to_find);
308    std::vector<uint16_t> to_find_types;
309    if (to_find_tl != NULL) {
310      for (size_t j = 0; j < to_find_tl->Size(); j++) {
311        to_find_types.push_back(to_find_tl->GetTypeItem(j).type_idx_);
312      }
313    }
314    const DexFile::ProtoId* found =
315        java_lang_dex_file_->FindProtoId(to_find.return_type_idx_, to_find_types);
316    ASSERT_TRUE(found != NULL);
317    EXPECT_EQ(java_lang_dex_file_->GetIndexForProtoId(*found), i);
318  }
319}
320
321TEST_F(DexFileTest, FindMethodId) {
322  for (size_t i = 0; i < java_lang_dex_file_->NumMethodIds(); i++) {
323    const DexFile::MethodId& to_find = java_lang_dex_file_->GetMethodId(i);
324    const DexFile::TypeId& klass = java_lang_dex_file_->GetTypeId(to_find.class_idx_);
325    const DexFile::StringId& name = java_lang_dex_file_->GetStringId(to_find.name_idx_);
326    const DexFile::ProtoId& signature = java_lang_dex_file_->GetProtoId(to_find.proto_idx_);
327    const DexFile::MethodId* found = java_lang_dex_file_->FindMethodId(klass, name, signature);
328    ASSERT_TRUE(found != NULL) << "Didn't find method " << i << ": "
329        << java_lang_dex_file_->StringByTypeIdx(to_find.class_idx_) << "."
330        << java_lang_dex_file_->GetStringData(name)
331        << java_lang_dex_file_->GetMethodSignature(to_find);
332    EXPECT_EQ(java_lang_dex_file_->GetIndexForMethodId(*found), i);
333  }
334}
335
336TEST_F(DexFileTest, FindFieldId) {
337  for (size_t i = 0; i < java_lang_dex_file_->NumFieldIds(); i++) {
338    const DexFile::FieldId& to_find = java_lang_dex_file_->GetFieldId(i);
339    const DexFile::TypeId& klass = java_lang_dex_file_->GetTypeId(to_find.class_idx_);
340    const DexFile::StringId& name = java_lang_dex_file_->GetStringId(to_find.name_idx_);
341    const DexFile::TypeId& type = java_lang_dex_file_->GetTypeId(to_find.type_idx_);
342    const DexFile::FieldId* found = java_lang_dex_file_->FindFieldId(klass, name, type);
343    ASSERT_TRUE(found != NULL) << "Didn't find field " << i << ": "
344        << java_lang_dex_file_->StringByTypeIdx(to_find.type_idx_) << " "
345        << java_lang_dex_file_->StringByTypeIdx(to_find.class_idx_) << "."
346        << java_lang_dex_file_->GetStringData(name);
347    EXPECT_EQ(java_lang_dex_file_->GetIndexForFieldId(*found), i);
348  }
349}
350
351TEST_F(DexFileTest, GetMultiDexClassesDexName) {
352  std::string dex_location_str = "/system/app/framework.jar";
353  const char* dex_location = dex_location_str.c_str();
354  ASSERT_EQ("/system/app/framework.jar", DexFile::GetMultiDexClassesDexName(0, dex_location));
355  ASSERT_EQ("/system/app/framework.jar:classes2.dex", DexFile::GetMultiDexClassesDexName(1, dex_location));
356  ASSERT_EQ("/system/app/framework.jar:classes101.dex", DexFile::GetMultiDexClassesDexName(100, dex_location));
357}
358
359TEST_F(DexFileTest, GetDexCanonicalLocation) {
360  ScratchFile file;
361  UniqueCPtr<const char[]> dex_location_real(realpath(file.GetFilename().c_str(), nullptr));
362  std::string dex_location(dex_location_real.get());
363
364  ASSERT_EQ(dex_location, DexFile::GetDexCanonicalLocation(dex_location.c_str()));
365  std::string multidex_location = DexFile::GetMultiDexClassesDexName(1, dex_location.c_str());
366  ASSERT_EQ(multidex_location, DexFile::GetDexCanonicalLocation(multidex_location.c_str()));
367
368  std::string dex_location_sym = dex_location + "symlink";
369  ASSERT_EQ(0, symlink(dex_location.c_str(), dex_location_sym.c_str()));
370
371  ASSERT_EQ(dex_location, DexFile::GetDexCanonicalLocation(dex_location_sym.c_str()));
372
373  std::string multidex_location_sym = DexFile::GetMultiDexClassesDexName(1, dex_location_sym.c_str());
374  ASSERT_EQ(multidex_location, DexFile::GetDexCanonicalLocation(multidex_location_sym.c_str()));
375
376  ASSERT_EQ(0, unlink(dex_location_sym.c_str()));
377}
378
379}  // namespace art
380