blob: c8823ab131fa7fe015601de0777bef4c2f9d1e81 [file] [log] [blame]
David Brazdil7b49e6c2016-09-01 11:06:18 +01001/*
2 * Copyright (C) 2016 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#ifndef ART_RUNTIME_VDEX_FILE_H_
18#define ART_RUNTIME_VDEX_FILE_H_
19
20#include <stdint.h>
21#include <string>
22
Nicolas Geoffraye70dd562016-10-30 21:03:35 +000023#include "base/array_ref.h"
David Brazdil7b49e6c2016-09-01 11:06:18 +010024#include "base/macros.h"
David Sehr79e26072018-04-06 17:58:50 -070025#include "base/mem_map.h"
David Sehrc431b9d2018-03-02 12:01:51 -080026#include "base/os.h"
Mathieu Chartier2daa1342018-02-20 16:19:28 -080027#include "dex/compact_offset_table.h"
David Brazdil35a3f6a2019-03-04 15:59:06 +000028#include "dex/dex_file.h"
Mathieu Chartier210531f2018-01-12 10:15:51 -080029#include "quicken_info.h"
David Brazdil7b49e6c2016-09-01 11:06:18 +010030
31namespace art {
32
David Brazdil35a3f6a2019-03-04 15:59:06 +000033class ClassLoaderContext;
34
35namespace verifier {
36class VerifierDeps;
37} // namespace verifier
David Sehrbeca4fe2017-03-30 17:50:24 -070038
David Brazdil7b49e6c2016-09-01 11:06:18 +010039// VDEX files contain extracted DEX files. The VdexFile class maps the file to
40// memory and provides tools for accessing its individual sections.
41//
Nicolas Geoffray07b62e32020-11-07 15:54:08 +000042// In the description below, D is the number of dex files.
43//
David Brazdil7b49e6c2016-09-01 11:06:18 +010044// File format:
Nicolas Geoffray3a293552018-03-02 10:52:16 +000045// VdexFile::VerifierDepsHeader fixed-length header
46// Dex file checksums
David Brazdil7b49e6c2016-09-01 11:06:18 +010047//
Nicolas Geoffray3a293552018-03-02 10:52:16 +000048// Optionally:
49// VdexFile::DexSectionHeader fixed-length header
50//
51// quicken_table_off[0] offset into QuickeningInfo section for offset table for DEX[0].
52// DEX[0] array of the input DEX files, the bytecode may have been quickened.
53// quicken_table_off[1]
54// DEX[1]
55// ...
Nicolas Geoffray07b62e32020-11-07 15:54:08 +000056// DEX[D-1]
Nicolas Geoffray3a293552018-03-02 10:52:16 +000057//
Nicolas Geoffrayb4c6acb2017-11-10 12:48:14 +000058// VerifierDeps
Nicolas Geoffray07b62e32020-11-07 15:54:08 +000059// 4-byte alignment
60// uint32[D] DexFileDeps offsets for each dex file
61// DexFileDeps[D][] verification dependencies
62// 4-byte alignment
63// uint32[class_def_size] TypeAssignability offsets (kNotVerifiedMarker for a class
64// that isn't verified)
65// uint32 Offset of end of AssignabilityType sets
66// uint8[] AssignabilityType sets
67// 4-byte alignment
68// uint32 Number of strings
69// uint32[] String data offsets for each string
70// uint8[] String data
71//
Nicolas Geoffray3a293552018-03-02 10:52:16 +000072//
73// Optionally:
74// QuickeningInfo
75// uint8[D][] quickening data
76// uint32[D][] quickening data offset tables
David Brazdil7b49e6c2016-09-01 11:06:18 +010077
78class VdexFile {
79 public:
David Brazdil35a3f6a2019-03-04 15:59:06 +000080 using VdexChecksum = uint32_t;
81 using QuickeningTableOffsetType = uint32_t;
82
Nicolas Geoffray3a293552018-03-02 10:52:16 +000083 struct VerifierDepsHeader {
David Brazdil7b49e6c2016-09-01 11:06:18 +010084 public:
Nicolas Geoffray3a293552018-03-02 10:52:16 +000085 VerifierDepsHeader(uint32_t number_of_dex_files_,
86 uint32_t verifier_deps_size,
David Brazdil35a3f6a2019-03-04 15:59:06 +000087 bool has_dex_section,
88 uint32_t bootclasspath_checksums_size = 0,
89 uint32_t class_loader_context_size = 0);
David Brazdil7b49e6c2016-09-01 11:06:18 +010090
Nicolas Geoffraye70dd562016-10-30 21:03:35 +000091 const char* GetMagic() const { return reinterpret_cast<const char*>(magic_); }
Nicolas Geoffray3a293552018-03-02 10:52:16 +000092 const char* GetVerifierDepsVersion() const {
93 return reinterpret_cast<const char*>(verifier_deps_version_);
David Brazdil93592f52017-12-08 10:53:27 +000094 }
Nicolas Geoffray3a293552018-03-02 10:52:16 +000095 const char* GetDexSectionVersion() const {
96 return reinterpret_cast<const char*>(dex_section_version_);
97 }
98 bool IsMagicValid() const;
99 bool IsVerifierDepsVersionValid() const;
100 bool IsDexSectionVersionValid() const;
101 bool IsValid() const {
102 return IsMagicValid() && IsVerifierDepsVersionValid() && IsDexSectionVersionValid();
103 }
104 bool HasDexSection() const;
105
106 uint32_t GetVerifierDepsSize() const { return verifier_deps_size_; }
107 uint32_t GetNumberOfDexFiles() const { return number_of_dex_files_; }
David Brazdil35a3f6a2019-03-04 15:59:06 +0000108 uint32_t GetBootClassPathChecksumStringSize() const { return bootclasspath_checksums_size_; }
109 uint32_t GetClassLoaderContextStringSize() const { return class_loader_context_size_; }
David Brazdil93592f52017-12-08 10:53:27 +0000110
111 size_t GetSizeOfChecksumsSection() const {
112 return sizeof(VdexChecksum) * GetNumberOfDexFiles();
113 }
114
David Brazdil35a3f6a2019-03-04 15:59:06 +0000115 const VdexChecksum* GetDexChecksumsArray() const {
116 return reinterpret_cast<const VdexChecksum*>(
117 reinterpret_cast<const uint8_t*>(this) + sizeof(VerifierDepsHeader));
118 }
119
120 VdexChecksum GetDexChecksumAtOffset(size_t idx) const {
121 DCHECK_LT(idx, GetNumberOfDexFiles());
122 return GetDexChecksumsArray()[idx];
123 }
124
Nicolas Geoffray36930ec2017-05-09 13:23:34 +0100125 static constexpr uint8_t kVdexInvalidMagic[] = { 'w', 'd', 'e', 'x' };
126
David Brazdil7b49e6c2016-09-01 11:06:18 +0100127 private:
128 static constexpr uint8_t kVdexMagic[] = { 'v', 'd', 'e', 'x' };
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000129
130 // The format version of the verifier deps header and the verifier deps.
Nicolas Geoffray07b62e32020-11-07 15:54:08 +0000131 // Last update: Fast per-class access.
132 static constexpr uint8_t kVerifierDepsVersion[] = { '0', '2', '6', '\0' };
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000133
134 // The format version of the dex section header and the dex section, containing
135 // both the dex code and the quickening data.
Mathieu Chartierc17b7d82018-03-14 14:00:04 -0700136 // Last update: Add owned section for CompactDex.
137 static constexpr uint8_t kDexSectionVersion[] = { '0', '0', '2', '\0' };
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000138
139 // If the .vdex file has no dex section (hence no dex code nor quickening data),
140 // we encode this magic version.
141 static constexpr uint8_t kDexSectionVersionEmpty[] = { '0', '0', '0', '\0' };
David Brazdil7b49e6c2016-09-01 11:06:18 +0100142
143 uint8_t magic_[4];
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000144 uint8_t verifier_deps_version_[4];
145 uint8_t dex_section_version_[4];
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000146 uint32_t number_of_dex_files_;
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000147 uint32_t verifier_deps_size_;
David Brazdil35a3f6a2019-03-04 15:59:06 +0000148 uint32_t bootclasspath_checksums_size_;
149 uint32_t class_loader_context_size_;
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000150 };
151
152 struct DexSectionHeader {
153 public:
154 DexSectionHeader(uint32_t dex_size,
155 uint32_t dex_shared_data_size,
156 uint32_t quickening_info_size);
157
158 uint32_t GetDexSize() const { return dex_size_; }
159 uint32_t GetDexSharedDataSize() const { return dex_shared_data_size_; }
160 uint32_t GetQuickeningInfoSize() const { return quickening_info_size_; }
161
162 size_t GetDexSectionSize() const {
163 return sizeof(DexSectionHeader) +
164 GetDexSize() +
165 GetDexSharedDataSize();
166 }
167
168 private:
David Brazdil5d5a36b2016-09-14 15:34:10 +0100169 uint32_t dex_size_;
Mathieu Chartierc3a22aa2018-01-19 18:58:34 -0800170 uint32_t dex_shared_data_size_;
Nicolas Geoffray4acefd32016-10-24 13:14:58 +0100171 uint32_t quickening_info_size_;
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +0100172
David Brazdil35a3f6a2019-03-04 15:59:06 +0000173 friend class VdexFile; // For updating quickening_info_size_.
David Brazdil7b49e6c2016-09-01 11:06:18 +0100174 };
175
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000176 size_t GetComputedFileSize() const {
177 size_t size = sizeof(VerifierDepsHeader);
178 const VerifierDepsHeader& header = GetVerifierDepsHeader();
179 size += header.GetVerifierDepsSize();
180 size += header.GetSizeOfChecksumsSection();
181 if (header.HasDexSection()) {
182 size += GetDexSectionHeader().GetDexSectionSize();
183 size += GetDexSectionHeader().GetQuickeningInfoSize();
184 }
David Brazdil35a3f6a2019-03-04 15:59:06 +0000185 size += header.GetBootClassPathChecksumStringSize();
186 size += header.GetClassLoaderContextStringSize();
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000187 return size;
188 }
189
Nicolas Geoffraybaeaa9b2018-01-26 14:31:17 +0000190 // Note: The file is called "primary" to match the naming with profiles.
191 static const constexpr char* kVdexNameInDmFile = "primary.vdex";
192
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100193 explicit VdexFile(MemMap&& mmap) : mmap_(std::move(mmap)) {}
Anestis Bechtsoudisa1f56a82017-10-08 23:37:10 +0300194
Richard Uhlerb8ab63a2017-01-31 11:27:37 +0000195 // Returns nullptr if the vdex file cannot be opened or is not valid.
David Srbeckyec2cdf42017-12-08 16:21:25 +0000196 // The mmap_* parameters can be left empty (nullptr/0/false) to allocate at random address.
197 static std::unique_ptr<VdexFile> OpenAtAddress(uint8_t* mmap_addr,
198 size_t mmap_size,
199 bool mmap_reuse,
200 const std::string& vdex_filename,
201 bool writable,
202 bool low_4gb,
203 bool unquicken,
204 std::string* error_msg);
205
206 // Returns nullptr if the vdex file cannot be opened or is not valid.
207 // The mmap_* parameters can be left empty (nullptr/0/false) to allocate at random address.
208 static std::unique_ptr<VdexFile> OpenAtAddress(uint8_t* mmap_addr,
209 size_t mmap_size,
210 bool mmap_reuse,
211 int file_fd,
212 size_t vdex_length,
213 const std::string& vdex_filename,
214 bool writable,
215 bool low_4gb,
216 bool unquicken,
217 std::string* error_msg);
218
219 // Returns nullptr if the vdex file cannot be opened or is not valid.
Richard Uhlerb8ab63a2017-01-31 11:27:37 +0000220 static std::unique_ptr<VdexFile> Open(const std::string& vdex_filename,
221 bool writable,
222 bool low_4gb,
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +0100223 bool unquicken,
David Srbeckyec2cdf42017-12-08 16:21:25 +0000224 std::string* error_msg) {
225 return OpenAtAddress(nullptr,
226 0,
227 false,
228 vdex_filename,
229 writable,
230 low_4gb,
231 unquicken,
232 error_msg);
233 }
David Brazdil7b49e6c2016-09-01 11:06:18 +0100234
Richard Uhlerb8ab63a2017-01-31 11:27:37 +0000235 // Returns nullptr if the vdex file cannot be opened or is not valid.
236 static std::unique_ptr<VdexFile> Open(int file_fd,
237 size_t vdex_length,
238 const std::string& vdex_filename,
239 bool writable,
240 bool low_4gb,
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +0100241 bool unquicken,
David Srbeckyec2cdf42017-12-08 16:21:25 +0000242 std::string* error_msg) {
243 return OpenAtAddress(nullptr,
244 0,
245 false,
246 file_fd,
247 vdex_length,
248 vdex_filename,
249 writable,
250 low_4gb,
251 unquicken,
252 error_msg);
253 }
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000254
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100255 const uint8_t* Begin() const { return mmap_.Begin(); }
256 const uint8_t* End() const { return mmap_.End(); }
257 size_t Size() const { return mmap_.Size(); }
David Brazdil7b49e6c2016-09-01 11:06:18 +0100258
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000259 const VerifierDepsHeader& GetVerifierDepsHeader() const {
260 return *reinterpret_cast<const VerifierDepsHeader*>(Begin());
261 }
262
263 uint32_t GetDexSectionHeaderOffset() const {
264 return sizeof(VerifierDepsHeader) + GetVerifierDepsHeader().GetSizeOfChecksumsSection();
265 }
266
267 const DexSectionHeader& GetDexSectionHeader() const {
268 DCHECK(GetVerifierDepsHeader().HasDexSection());
269 return *reinterpret_cast<const DexSectionHeader*>(Begin() + GetDexSectionHeaderOffset());
270 }
271
272 const uint8_t* GetVerifierDepsStart() const {
273 const uint8_t* result = Begin() + GetDexSectionHeaderOffset();
274 if (GetVerifierDepsHeader().HasDexSection()) {
275 // When there is a dex section, the verifier deps are after it, but before the quickening.
276 return result + GetDexSectionHeader().GetDexSectionSize();
277 } else {
278 // When there is no dex section, the verifier deps are just after the header.
279 return result;
280 }
Nicolas Geoffraye70dd562016-10-30 21:03:35 +0000281 }
282
283 ArrayRef<const uint8_t> GetVerifierDepsData() const {
284 return ArrayRef<const uint8_t>(
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000285 GetVerifierDepsStart(),
286 GetVerifierDepsHeader().GetVerifierDepsSize());
Nicolas Geoffraye70dd562016-10-30 21:03:35 +0000287 }
288
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000289 ArrayRef<const uint8_t> GetQuickeningInfo() const {
David Brazdil35a3f6a2019-03-04 15:59:06 +0000290 return ArrayRef<const uint8_t>(
291 GetVerifierDepsData().end(),
292 GetVerifierDepsHeader().HasDexSection()
293 ? GetDexSectionHeader().GetQuickeningInfoSize() : 0);
294 }
295
296 ArrayRef<const uint8_t> GetBootClassPathChecksumData() const {
297 return ArrayRef<const uint8_t>(
298 GetQuickeningInfo().end(),
299 GetVerifierDepsHeader().GetBootClassPathChecksumStringSize());
300 }
301
302 ArrayRef<const uint8_t> GetClassLoaderContextData() const {
303 return ArrayRef<const uint8_t>(
304 GetBootClassPathChecksumData().end(),
305 GetVerifierDepsHeader().GetClassLoaderContextStringSize());
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000306 }
307
308 bool IsValid() const {
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100309 return mmap_.Size() >= sizeof(VerifierDepsHeader) && GetVerifierDepsHeader().IsValid();
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000310 }
311
312 // This method is for iterating over the dex files in the vdex. If `cursor` is null,
313 // the first dex file is returned. If `cursor` is not null, it must point to a dex
314 // file and this method returns the next dex file if there is one, or null if there
315 // is none.
316 const uint8_t* GetNextDexFileData(const uint8_t* cursor) const;
317
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000318 // Get the location checksum of the dex file number `dex_file_index`.
319 uint32_t GetLocationChecksum(uint32_t dex_file_index) const {
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000320 DCHECK_LT(dex_file_index, GetVerifierDepsHeader().GetNumberOfDexFiles());
321 return reinterpret_cast<const uint32_t*>(Begin() + sizeof(VerifierDepsHeader))[dex_file_index];
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000322 }
323
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100324 // Open all the dex files contained in this vdex file.
David Sehrbeca4fe2017-03-30 17:50:24 -0700325 bool OpenAllDexFiles(std::vector<std::unique_ptr<const DexFile>>* dex_files,
Alex Lightabd8f052019-12-06 10:49:17 -0800326 std::string* error_msg) const;
David Sehrbeca4fe2017-03-30 17:50:24 -0700327
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +0100328 // In-place unquicken the given `dex_files` based on `quickening_info`.
Anestis Bechtsoudisa1f56a82017-10-08 23:37:10 +0300329 // `decompile_return_instruction` controls if RETURN_VOID_BARRIER instructions are
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -0700330 // decompiled to RETURN_VOID instructions using the slower ClassAccessor instead of the faster
331 // QuickeningInfoIterator.
Mathieu Chartier210531f2018-01-12 10:15:51 -0800332 // Always unquickens using the vdex dex files as the source for quicken tables.
333 void Unquicken(const std::vector<const DexFile*>& target_dex_files,
334 bool decompile_return_instruction) const;
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +0100335
Alex Lightabd8f052019-12-06 10:49:17 -0800336 void UnquickenInPlace(bool decompile_return_instruction) const;
337
Nicolas Geoffrayb4c6acb2017-11-10 12:48:14 +0000338 // Fully unquicken `target_dex_file` based on `quickening_info`.
Mathieu Chartier210531f2018-01-12 10:15:51 -0800339 void UnquickenDexFile(const DexFile& target_dex_file,
340 const DexFile& source_dex_file,
341 bool decompile_return_instruction) const;
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100342
Mathieu Chartier210531f2018-01-12 10:15:51 -0800343 // Return the quickening info of a given method index (or null if it's empty).
344 ArrayRef<const uint8_t> GetQuickenedInfoOf(const DexFile& dex_file,
345 uint32_t dex_method_idx) const;
Nicolas Geoffrayb4c6acb2017-11-10 12:48:14 +0000346
Nicolas Geoffraybc177272018-01-24 14:55:32 +0000347 bool HasDexSection() const {
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000348 return GetVerifierDepsHeader().HasDexSection();
Nicolas Geoffraybc177272018-01-24 14:55:32 +0000349 }
350
David Brazdil35a3f6a2019-03-04 15:59:06 +0000351 // Writes a vdex into `path` and returns true on success.
352 // The vdex will not contain a dex section but will store checksums of `dex_files`,
353 // encoded `verifier_deps`, as well as the current boot class path cheksum and
354 // encoded `class_loader_context`.
355 static bool WriteToDisk(const std::string& path,
356 const std::vector<const DexFile*>& dex_files,
357 const verifier::VerifierDeps& verifier_deps,
358 const std::string& class_loader_context,
359 std::string* error_msg);
360
David Brazdil7126c5b2019-03-05 00:02:51 +0000361 // Returns true if the dex file checksums stored in the vdex header match
362 // the checksums in `dex_headers`. Both the number of dex files and their
363 // order must match too.
364 bool MatchesDexFileChecksums(const std::vector<const DexFile::Header*>& dex_headers) const;
365
366 // Returns true if the boot class path checksum stored in the vdex matches
367 // the checksum of boot class path in the current runtime.
368 bool MatchesBootClassPathChecksums() const;
369
370 // Returns true if the class loader context stored in the vdex matches `context`.
371 bool MatchesClassLoaderContext(const ClassLoaderContext& context) const;
372
Alex Lightabd8f052019-12-06 10:49:17 -0800373 // Make the Vdex file & underlying dex-files RW or RO. Should only be used for in-place
374 // dequickening.
375 void AllowWriting(bool value) const;
376
David Brazdil7b49e6c2016-09-01 11:06:18 +0100377 private:
Mathieu Chartier210531f2018-01-12 10:15:51 -0800378 uint32_t GetQuickeningInfoTableOffset(const uint8_t* source_dex_begin) const;
379
380 // Source dex must be the in the vdex file.
381 void UnquickenDexFile(const DexFile& target_dex_file,
382 const uint8_t* source_dex_begin,
383 bool decompile_return_instruction) const;
384
Mathieu Chartier2daa1342018-02-20 16:19:28 -0800385 CompactOffsetTable::Accessor GetQuickenInfoOffsetTable(
Mathieu Chartier210531f2018-01-12 10:15:51 -0800386 const DexFile& dex_file,
387 const ArrayRef<const uint8_t>& quickening_info) const;
388
Mathieu Chartier2daa1342018-02-20 16:19:28 -0800389 CompactOffsetTable::Accessor GetQuickenInfoOffsetTable(
Mathieu Chartier210531f2018-01-12 10:15:51 -0800390 const uint8_t* source_dex_begin,
Mathieu Chartier210531f2018-01-12 10:15:51 -0800391 const ArrayRef<const uint8_t>& quickening_info) const;
392
Mathieu Chartier210531f2018-01-12 10:15:51 -0800393 bool ContainsDexFile(const DexFile& dex_file) const;
394
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000395 const uint8_t* DexBegin() const {
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000396 DCHECK(HasDexSection());
397 return Begin() + GetDexSectionHeaderOffset() + sizeof(DexSectionHeader);
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000398 }
399
400 const uint8_t* DexEnd() const {
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000401 DCHECK(HasDexSection());
402 return DexBegin() + GetDexSectionHeader().GetDexSize();
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000403 }
404
Alex Lightabd8f052019-12-06 10:49:17 -0800405 // mutable for AllowWriting()
406 mutable MemMap mmap_;
David Brazdil7b49e6c2016-09-01 11:06:18 +0100407
408 DISALLOW_COPY_AND_ASSIGN(VdexFile);
409};
410
411} // namespace art
412
413#endif // ART_RUNTIME_VDEX_FILE_H_