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(GetLibCoreDexFileNames()[0].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_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
306TEST_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
323TEST_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
338TEST_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
353TEST_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
360TEST_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
370TEST_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
390TEST(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