• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
23 #include "base/array_ref.h"
24 #include "base/macros.h"
25 #include "base/mem_map.h"
26 #include "base/os.h"
27 #include "dex/compact_offset_table.h"
28 #include "dex/dex_file.h"
29 #include "quicken_info.h"
30 
31 namespace art {
32 
33 class ClassLoaderContext;
34 
35 namespace verifier {
36 class VerifierDeps;
37 }  // namespace verifier
38 
39 // VDEX files contain extracted DEX files. The VdexFile class maps the file to
40 // memory and provides tools for accessing its individual sections.
41 //
42 // File format:
43 //   VdexFile::VerifierDepsHeader    fixed-length header
44 //      Dex file checksums
45 //
46 //   Optionally:
47 //      VdexFile::DexSectionHeader   fixed-length header
48 //
49 //      quicken_table_off[0]  offset into QuickeningInfo section for offset table for DEX[0].
50 //      DEX[0]                array of the input DEX files, the bytecode may have been quickened.
51 //      quicken_table_off[1]
52 //      DEX[1]
53 //      ...
54 //      DEX[D]
55 //
56 //   VerifierDeps
57 //      uint8[D][]                 verification dependencies
58 //
59 //   Optionally:
60 //      QuickeningInfo
61 //        uint8[D][]                  quickening data
62 //        uint32[D][]                 quickening data offset tables
63 
64 class VdexFile {
65  public:
66   using VdexChecksum = uint32_t;
67   using QuickeningTableOffsetType = uint32_t;
68 
69   struct VerifierDepsHeader {
70    public:
71     VerifierDepsHeader(uint32_t number_of_dex_files_,
72                        uint32_t verifier_deps_size,
73                        bool has_dex_section,
74                        uint32_t bootclasspath_checksums_size = 0,
75                        uint32_t class_loader_context_size = 0);
76 
GetMagicVerifierDepsHeader77     const char* GetMagic() const { return reinterpret_cast<const char*>(magic_); }
GetVerifierDepsVersionVerifierDepsHeader78     const char* GetVerifierDepsVersion() const {
79       return reinterpret_cast<const char*>(verifier_deps_version_);
80     }
GetDexSectionVersionVerifierDepsHeader81     const char* GetDexSectionVersion() const {
82       return reinterpret_cast<const char*>(dex_section_version_);
83     }
84     bool IsMagicValid() const;
85     bool IsVerifierDepsVersionValid() const;
86     bool IsDexSectionVersionValid() const;
IsValidVerifierDepsHeader87     bool IsValid() const {
88       return IsMagicValid() && IsVerifierDepsVersionValid() && IsDexSectionVersionValid();
89     }
90     bool HasDexSection() const;
91 
GetVerifierDepsSizeVerifierDepsHeader92     uint32_t GetVerifierDepsSize() const { return verifier_deps_size_; }
GetNumberOfDexFilesVerifierDepsHeader93     uint32_t GetNumberOfDexFiles() const { return number_of_dex_files_; }
GetBootClassPathChecksumStringSizeVerifierDepsHeader94     uint32_t GetBootClassPathChecksumStringSize() const { return bootclasspath_checksums_size_; }
GetClassLoaderContextStringSizeVerifierDepsHeader95     uint32_t GetClassLoaderContextStringSize() const { return class_loader_context_size_; }
96 
GetSizeOfChecksumsSectionVerifierDepsHeader97     size_t GetSizeOfChecksumsSection() const {
98       return sizeof(VdexChecksum) * GetNumberOfDexFiles();
99     }
100 
GetDexChecksumsArrayVerifierDepsHeader101     const VdexChecksum* GetDexChecksumsArray() const {
102       return reinterpret_cast<const VdexChecksum*>(
103           reinterpret_cast<const uint8_t*>(this) + sizeof(VerifierDepsHeader));
104     }
105 
GetDexChecksumAtOffsetVerifierDepsHeader106     VdexChecksum GetDexChecksumAtOffset(size_t idx) const {
107       DCHECK_LT(idx, GetNumberOfDexFiles());
108       return GetDexChecksumsArray()[idx];
109     }
110 
111     static constexpr uint8_t kVdexInvalidMagic[] = { 'w', 'd', 'e', 'x' };
112 
113    private:
114     static constexpr uint8_t kVdexMagic[] = { 'v', 'd', 'e', 'x' };
115 
116     // The format version of the verifier deps header and the verifier deps.
117     // Last update: Add boot checksum, class loader context.
118     static constexpr uint8_t kVerifierDepsVersion[] = { '0', '2', '1', '\0' };
119 
120     // The format version of the dex section header and the dex section, containing
121     // both the dex code and the quickening data.
122     // Last update: Add owned section for CompactDex.
123     static constexpr uint8_t kDexSectionVersion[] = { '0', '0', '2', '\0' };
124 
125     // If the .vdex file has no dex section (hence no dex code nor quickening data),
126     // we encode this magic version.
127     static constexpr uint8_t kDexSectionVersionEmpty[] = { '0', '0', '0', '\0' };
128 
129     uint8_t magic_[4];
130     uint8_t verifier_deps_version_[4];
131     uint8_t dex_section_version_[4];
132     uint32_t number_of_dex_files_;
133     uint32_t verifier_deps_size_;
134     uint32_t bootclasspath_checksums_size_;
135     uint32_t class_loader_context_size_;
136   };
137 
138   struct DexSectionHeader {
139    public:
140     DexSectionHeader(uint32_t dex_size,
141                      uint32_t dex_shared_data_size,
142                      uint32_t quickening_info_size);
143 
GetDexSizeDexSectionHeader144     uint32_t GetDexSize() const { return dex_size_; }
GetDexSharedDataSizeDexSectionHeader145     uint32_t GetDexSharedDataSize() const { return dex_shared_data_size_; }
GetQuickeningInfoSizeDexSectionHeader146     uint32_t GetQuickeningInfoSize() const { return quickening_info_size_; }
147 
GetDexSectionSizeDexSectionHeader148     size_t GetDexSectionSize() const {
149       return sizeof(DexSectionHeader) +
150            GetDexSize() +
151            GetDexSharedDataSize();
152     }
153 
154    private:
155     uint32_t dex_size_;
156     uint32_t dex_shared_data_size_;
157     uint32_t quickening_info_size_;
158 
159     friend class VdexFile;  // For updating quickening_info_size_.
160   };
161 
GetComputedFileSize()162   size_t GetComputedFileSize() const {
163     size_t size = sizeof(VerifierDepsHeader);
164     const VerifierDepsHeader& header = GetVerifierDepsHeader();
165     size += header.GetVerifierDepsSize();
166     size += header.GetSizeOfChecksumsSection();
167     if (header.HasDexSection()) {
168       size += GetDexSectionHeader().GetDexSectionSize();
169       size += GetDexSectionHeader().GetQuickeningInfoSize();
170     }
171     size += header.GetBootClassPathChecksumStringSize();
172     size += header.GetClassLoaderContextStringSize();
173     return size;
174   }
175 
176   // Note: The file is called "primary" to match the naming with profiles.
177   static const constexpr char* kVdexNameInDmFile = "primary.vdex";
178 
VdexFile(MemMap && mmap)179   explicit VdexFile(MemMap&& mmap) : mmap_(std::move(mmap)) {}
180 
181   // Returns nullptr if the vdex file cannot be opened or is not valid.
182   // The mmap_* parameters can be left empty (nullptr/0/false) to allocate at random address.
183   static std::unique_ptr<VdexFile> OpenAtAddress(uint8_t* mmap_addr,
184                                                  size_t mmap_size,
185                                                  bool mmap_reuse,
186                                                  const std::string& vdex_filename,
187                                                  bool writable,
188                                                  bool low_4gb,
189                                                  bool unquicken,
190                                                  std::string* error_msg);
191 
192   // Returns nullptr if the vdex file cannot be opened or is not valid.
193   // The mmap_* parameters can be left empty (nullptr/0/false) to allocate at random address.
194   static std::unique_ptr<VdexFile> OpenAtAddress(uint8_t* mmap_addr,
195                                                  size_t mmap_size,
196                                                  bool mmap_reuse,
197                                                  int file_fd,
198                                                  size_t vdex_length,
199                                                  const std::string& vdex_filename,
200                                                  bool writable,
201                                                  bool low_4gb,
202                                                  bool unquicken,
203                                                  std::string* error_msg);
204 
205   // Returns nullptr if the vdex file cannot be opened or is not valid.
Open(const std::string & vdex_filename,bool writable,bool low_4gb,bool unquicken,std::string * error_msg)206   static std::unique_ptr<VdexFile> Open(const std::string& vdex_filename,
207                                         bool writable,
208                                         bool low_4gb,
209                                         bool unquicken,
210                                         std::string* error_msg) {
211     return OpenAtAddress(nullptr,
212                          0,
213                          false,
214                          vdex_filename,
215                          writable,
216                          low_4gb,
217                          unquicken,
218                          error_msg);
219   }
220 
221   // Returns nullptr if the vdex file cannot be opened or is not valid.
Open(int file_fd,size_t vdex_length,const std::string & vdex_filename,bool writable,bool low_4gb,bool unquicken,std::string * error_msg)222   static std::unique_ptr<VdexFile> Open(int file_fd,
223                                         size_t vdex_length,
224                                         const std::string& vdex_filename,
225                                         bool writable,
226                                         bool low_4gb,
227                                         bool unquicken,
228                                         std::string* error_msg) {
229     return OpenAtAddress(nullptr,
230                          0,
231                          false,
232                          file_fd,
233                          vdex_length,
234                          vdex_filename,
235                          writable,
236                          low_4gb,
237                          unquicken,
238                          error_msg);
239   }
240 
Begin()241   const uint8_t* Begin() const { return mmap_.Begin(); }
End()242   const uint8_t* End() const { return mmap_.End(); }
Size()243   size_t Size() const { return mmap_.Size(); }
244 
GetVerifierDepsHeader()245   const VerifierDepsHeader& GetVerifierDepsHeader() const {
246     return *reinterpret_cast<const VerifierDepsHeader*>(Begin());
247   }
248 
GetDexSectionHeaderOffset()249   uint32_t GetDexSectionHeaderOffset() const {
250     return sizeof(VerifierDepsHeader) + GetVerifierDepsHeader().GetSizeOfChecksumsSection();
251   }
252 
GetDexSectionHeader()253   const DexSectionHeader& GetDexSectionHeader() const {
254     DCHECK(GetVerifierDepsHeader().HasDexSection());
255     return *reinterpret_cast<const DexSectionHeader*>(Begin() + GetDexSectionHeaderOffset());
256   }
257 
GetVerifierDepsStart()258   const uint8_t* GetVerifierDepsStart() const {
259     const uint8_t* result = Begin() + GetDexSectionHeaderOffset();
260     if (GetVerifierDepsHeader().HasDexSection()) {
261       // When there is a dex section, the verifier deps are after it, but before the quickening.
262       return result + GetDexSectionHeader().GetDexSectionSize();
263     } else {
264       // When there is no dex section, the verifier deps are just after the header.
265       return result;
266     }
267   }
268 
GetVerifierDepsData()269   ArrayRef<const uint8_t> GetVerifierDepsData() const {
270     return ArrayRef<const uint8_t>(
271         GetVerifierDepsStart(),
272         GetVerifierDepsHeader().GetVerifierDepsSize());
273   }
274 
GetQuickeningInfo()275   ArrayRef<const uint8_t> GetQuickeningInfo() const {
276     return ArrayRef<const uint8_t>(
277         GetVerifierDepsData().end(),
278         GetVerifierDepsHeader().HasDexSection()
279             ? GetDexSectionHeader().GetQuickeningInfoSize() : 0);
280   }
281 
GetBootClassPathChecksumData()282   ArrayRef<const uint8_t> GetBootClassPathChecksumData() const {
283     return ArrayRef<const uint8_t>(
284         GetQuickeningInfo().end(),
285         GetVerifierDepsHeader().GetBootClassPathChecksumStringSize());
286   }
287 
GetClassLoaderContextData()288   ArrayRef<const uint8_t> GetClassLoaderContextData() const {
289     return ArrayRef<const uint8_t>(
290         GetBootClassPathChecksumData().end(),
291         GetVerifierDepsHeader().GetClassLoaderContextStringSize());
292   }
293 
IsValid()294   bool IsValid() const {
295     return mmap_.Size() >= sizeof(VerifierDepsHeader) && GetVerifierDepsHeader().IsValid();
296   }
297 
298   // This method is for iterating over the dex files in the vdex. If `cursor` is null,
299   // the first dex file is returned. If `cursor` is not null, it must point to a dex
300   // file and this method returns the next dex file if there is one, or null if there
301   // is none.
302   const uint8_t* GetNextDexFileData(const uint8_t* cursor) const;
303 
304   // Get the location checksum of the dex file number `dex_file_index`.
GetLocationChecksum(uint32_t dex_file_index)305   uint32_t GetLocationChecksum(uint32_t dex_file_index) const {
306     DCHECK_LT(dex_file_index, GetVerifierDepsHeader().GetNumberOfDexFiles());
307     return reinterpret_cast<const uint32_t*>(Begin() + sizeof(VerifierDepsHeader))[dex_file_index];
308   }
309 
310   // Open all the dex files contained in this vdex file.
311   bool OpenAllDexFiles(std::vector<std::unique_ptr<const DexFile>>* dex_files,
312                        std::string* error_msg);
313 
314   // In-place unquicken the given `dex_files` based on `quickening_info`.
315   // `decompile_return_instruction` controls if RETURN_VOID_BARRIER instructions are
316   // decompiled to RETURN_VOID instructions using the slower ClassAccessor instead of the faster
317   // QuickeningInfoIterator.
318   // Always unquickens using the vdex dex files as the source for quicken tables.
319   void Unquicken(const std::vector<const DexFile*>& target_dex_files,
320                  bool decompile_return_instruction) const;
321 
322   // Fully unquicken `target_dex_file` based on `quickening_info`.
323   void UnquickenDexFile(const DexFile& target_dex_file,
324                         const DexFile& source_dex_file,
325                         bool decompile_return_instruction) const;
326 
327   // Return the quickening info of a given method index (or null if it's empty).
328   ArrayRef<const uint8_t> GetQuickenedInfoOf(const DexFile& dex_file,
329                                              uint32_t dex_method_idx) const;
330 
HasDexSection()331   bool HasDexSection() const {
332     return GetVerifierDepsHeader().HasDexSection();
333   }
334 
335   // Writes a vdex into `path` and returns true on success.
336   // The vdex will not contain a dex section but will store checksums of `dex_files`,
337   // encoded `verifier_deps`, as well as the current boot class path cheksum and
338   // encoded `class_loader_context`.
339   static bool WriteToDisk(const std::string& path,
340                           const std::vector<const DexFile*>& dex_files,
341                           const verifier::VerifierDeps& verifier_deps,
342                           const std::string& class_loader_context,
343                           std::string* error_msg);
344 
345   // Returns true if the dex file checksums stored in the vdex header match
346   // the checksums in `dex_headers`. Both the number of dex files and their
347   // order must match too.
348   bool MatchesDexFileChecksums(const std::vector<const DexFile::Header*>& dex_headers) const;
349 
350   // Returns true if the boot class path checksum stored in the vdex matches
351   // the checksum of boot class path in the current runtime.
352   bool MatchesBootClassPathChecksums() const;
353 
354   // Returns true if the class loader context stored in the vdex matches `context`.
355   bool MatchesClassLoaderContext(const ClassLoaderContext& context) const;
356 
357  private:
358   uint32_t GetQuickeningInfoTableOffset(const uint8_t* source_dex_begin) const;
359 
360   // Source dex must be the in the vdex file.
361   void UnquickenDexFile(const DexFile& target_dex_file,
362                         const uint8_t* source_dex_begin,
363                         bool decompile_return_instruction) const;
364 
365   CompactOffsetTable::Accessor GetQuickenInfoOffsetTable(
366         const DexFile& dex_file,
367         const ArrayRef<const uint8_t>& quickening_info) const;
368 
369   CompactOffsetTable::Accessor GetQuickenInfoOffsetTable(
370       const uint8_t* source_dex_begin,
371       const ArrayRef<const uint8_t>& quickening_info) const;
372 
373   bool ContainsDexFile(const DexFile& dex_file) const;
374 
DexBegin()375   const uint8_t* DexBegin() const {
376     DCHECK(HasDexSection());
377     return Begin() + GetDexSectionHeaderOffset() + sizeof(DexSectionHeader);
378   }
379 
DexEnd()380   const uint8_t* DexEnd() const {
381     DCHECK(HasDexSection());
382     return DexBegin() + GetDexSectionHeader().GetDexSize();
383   }
384 
385   MemMap mmap_;
386 
387   DISALLOW_COPY_AND_ASSIGN(VdexFile);
388 };
389 
390 }  // namespace art
391 
392 #endif  // ART_RUNTIME_VDEX_FILE_H_
393