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 
28 namespace art {
29 
30 class DexFileTest : public CommonRuntimeTest {};
31 
TEST_F(DexFileTest,Open)32 TEST_F(DexFileTest, Open) {
33   ScopedObjectAccess soa(Thread::Current());
34   const DexFile* dex(OpenTestDexFile("Nested"));
35   ASSERT_TRUE(dex != NULL);
36 }
37 
38 static 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 
DecodeBase64(const char * src,size_t * dst_size)63 static 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 // }
117 static 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 
OpenDexFileBase64(const char * base64,const char * location)135 static 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 
TEST_F(DexFileTest,Header)167 TEST_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 
TEST_F(DexFileTest,GetLocationChecksum)198 TEST_F(DexFileTest, GetLocationChecksum) {
199   ScopedObjectAccess soa(Thread::Current());
200   const DexFile* raw(OpenTestDexFile("Main"));
201   EXPECT_NE(raw->GetHeader().checksum_, raw->GetLocationChecksum());
202 }
203 
TEST_F(DexFileTest,GetChecksum)204 TEST_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 
TEST_F(DexFileTest,ClassDefs)213 TEST_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 
TEST_F(DexFileTest,GetMethodSignature)226 TEST_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 
TEST_F(DexFileTest,FindStringId)276 TEST_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 
TEST_F(DexFileTest,FindTypeId)292 TEST_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 
TEST_F(DexFileTest,FindProtoId)304 TEST_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 
TEST_F(DexFileTest,FindMethodId)321 TEST_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 
TEST_F(DexFileTest,FindFieldId)336 TEST_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 
TEST_F(DexFileTest,GetMultiDexClassesDexName)351 TEST_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 
TEST_F(DexFileTest,GetDexCanonicalLocation)359 TEST_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