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
29namespace art {
30
31class DexFileTest : public CommonRuntimeTest {};
32
33TEST_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
39static 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
64static 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// }
118static 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
136static 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
168TEST_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
199TEST_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
205TEST_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
214TEST_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
227TEST_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
277TEST_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
293TEST_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
305TEST_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
322TEST_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
337TEST_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
352TEST_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
359TEST_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
369TEST_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
389TEST(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