• 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 "class_status.h"
28 #include "dex/compact_offset_table.h"
29 #include "dex/dex_file.h"
30 #include "quicken_info.h"
31 #include "handle.h"
32 
33 namespace art {
34 
35 class ClassLoaderContext;
36 class Thread;
37 
38 namespace mirror {
39 class Class;
40 }
41 
42 namespace verifier {
43 class VerifierDeps;
44 }  // namespace verifier
45 
46 // VDEX files contain extracted DEX files. The VdexFile class maps the file to
47 // memory and provides tools for accessing its individual sections.
48 //
49 // In the description below, D is the number of dex files.
50 //
51 // File format:
52 //   VdexFileHeader    fixed-length header
53 //   VdexSectionHeader[kNumberOfSections]
54 //
55 //   Checksum section
56 //     VdexChecksum[D]
57 //
58 //   Optionally:
59 //      DexSection
60 //          DEX[0]                array of the input DEX files
61 //          DEX[1]
62 //          ...
63 //          DEX[D-1]
64 //
65 //   VerifierDeps
66 //      4-byte alignment
67 //      uint32[D]                  DexFileDeps offsets for each dex file
68 //      DexFileDeps[D][]           verification dependencies
69 //        4-byte alignment
70 //        uint32[class_def_size]     TypeAssignability offsets (kNotVerifiedMarker for a class
71 //                                        that isn't verified)
72 //        uint32                     Offset of end of AssignabilityType sets
73 //        uint8[]                    AssignabilityType sets
74 //        4-byte alignment
75 //        uint32                     Number of strings
76 //        uint32[]                   String data offsets for each string
77 //        uint8[]                    String data
78 
79 
80 enum VdexSection : uint32_t {
81   kChecksumSection = 0,
82   kDexFileSection = 1,
83   kVerifierDepsSection = 2,
84   kTypeLookupTableSection = 3,
85   kNumberOfSections = 4,
86 };
87 
88 class VdexFile {
89  public:
90   using VdexChecksum = uint32_t;
91 
92   struct VdexSectionHeader {
93     VdexSection section_kind;
94     uint32_t section_offset;
95     uint32_t section_size;
96 
VdexSectionHeaderVdexSectionHeader97     VdexSectionHeader(VdexSection kind, uint32_t offset, uint32_t size)
98         : section_kind(kind), section_offset(offset), section_size(size) {}
99 
VdexSectionHeaderVdexSectionHeader100     VdexSectionHeader() {}
101   };
102 
103   struct VdexFileHeader {
104    public:
105     explicit VdexFileHeader(bool has_dex_section);
106 
GetMagicVdexFileHeader107     const char* GetMagic() const { return reinterpret_cast<const char*>(magic_); }
GetVdexVersionVdexFileHeader108     const char* GetVdexVersion() const {
109       return reinterpret_cast<const char*>(vdex_version_);
110     }
GetNumberOfSectionsVdexFileHeader111     uint32_t GetNumberOfSections() const {
112       return number_of_sections_;
113     }
114     bool IsMagicValid() const;
115     bool IsVdexVersionValid() const;
IsValidVdexFileHeader116     bool IsValid() const {
117       return IsMagicValid() && IsVdexVersionValid();
118     }
119 
120     static constexpr uint8_t kVdexInvalidMagic[] = { 'w', 'd', 'e', 'x' };
121 
122    private:
123     static constexpr uint8_t kVdexMagic[] = { 'v', 'd', 'e', 'x' };
124 
125     // The format version of the verifier deps header and the verifier deps.
126     // Last update: Introduce vdex sections.
127     static constexpr uint8_t kVdexVersion[] = { '0', '2', '7', '\0' };
128 
129     uint8_t magic_[4];
130     uint8_t vdex_version_[4];
131     uint32_t number_of_sections_;
132   };
133 
GetSectionHeaderAt(uint32_t index)134   const VdexSectionHeader& GetSectionHeaderAt(uint32_t index) const {
135     DCHECK_LT(index, GetVdexFileHeader().GetNumberOfSections());
136     return *reinterpret_cast<const VdexSectionHeader*>(
137         Begin() + sizeof(VdexFileHeader) + index * sizeof(VdexSectionHeader));
138   }
139 
GetSectionHeader(VdexSection kind)140   const VdexSectionHeader& GetSectionHeader(VdexSection kind) const {
141     return GetSectionHeaderAt(static_cast<uint32_t>(kind));
142   }
143 
GetChecksumsOffset()144   static size_t GetChecksumsOffset() {
145     return sizeof(VdexFileHeader) +
146         static_cast<size_t>(VdexSection::kNumberOfSections) * sizeof(VdexSectionHeader);
147   }
148 
GetComputedFileSize()149   size_t GetComputedFileSize() const {
150     const VdexFileHeader& header = GetVdexFileHeader();
151     uint32_t size = sizeof(VdexFileHeader) +
152         header.GetNumberOfSections() * sizeof(VdexSectionHeader);
153     for (uint32_t i = 0; i < header.GetNumberOfSections(); ++i) {
154       size = std::max(size,
155                       GetSectionHeaderAt(i).section_offset + GetSectionHeaderAt(i).section_size);
156     }
157     return size;
158   }
159 
HasDexSection()160   bool HasDexSection() const {
161     return GetSectionHeader(VdexSection::kDexFileSection).section_size != 0u;
162   }
GetVerifierDepsSize()163   uint32_t GetVerifierDepsSize() const {
164     return GetSectionHeader(VdexSection::kVerifierDepsSection).section_size;
165   }
GetNumberOfDexFiles()166   uint32_t GetNumberOfDexFiles() const {
167     return GetSectionHeader(VdexSection::kChecksumSection).section_size / sizeof(VdexChecksum);
168   }
169 
HasTypeLookupTableSection()170   bool HasTypeLookupTableSection() const {
171     return GetVdexFileHeader().GetNumberOfSections() >= (kTypeLookupTableSection + 1);
172   }
173 
GetDexChecksumsArray()174   const VdexChecksum* GetDexChecksumsArray() const {
175     return reinterpret_cast<const VdexChecksum*>(
176         Begin() + GetSectionHeader(VdexSection::kChecksumSection).section_offset);
177   }
178 
GetDexChecksumAt(size_t idx)179   VdexChecksum GetDexChecksumAt(size_t idx) const {
180     DCHECK_LT(idx, GetNumberOfDexFiles());
181     return GetDexChecksumsArray()[idx];
182   }
183 
184   // Note: The file is called "primary" to match the naming with profiles.
185   static const constexpr char* kVdexNameInDmFile = "primary.vdex";
186 
VdexFile(MemMap && mmap)187   explicit VdexFile(MemMap&& mmap) : mmap_(std::move(mmap)) {}
188 
189   // Returns nullptr if the vdex file cannot be opened or is not valid.
190   // The mmap_* parameters can be left empty (nullptr/0/false) to allocate at random address.
191   static std::unique_ptr<VdexFile> OpenAtAddress(uint8_t* mmap_addr,
192                                                  size_t mmap_size,
193                                                  bool mmap_reuse,
194                                                  const std::string& vdex_filename,
195                                                  bool writable,
196                                                  bool low_4gb,
197                                                  std::string* error_msg);
198 
199   // Returns nullptr if the vdex file cannot be opened or is not valid.
200   // The mmap_* parameters can be left empty (nullptr/0/false) to allocate at random address.
201   static std::unique_ptr<VdexFile> OpenAtAddress(uint8_t* mmap_addr,
202                                                  size_t mmap_size,
203                                                  bool mmap_reuse,
204                                                  int file_fd,
205                                                  size_t vdex_length,
206                                                  const std::string& vdex_filename,
207                                                  bool writable,
208                                                  bool low_4gb,
209                                                  std::string* error_msg);
210 
211   // Returns nullptr if the vdex file cannot be opened or is not valid.
Open(const std::string & vdex_filename,bool writable,bool low_4gb,std::string * error_msg)212   static std::unique_ptr<VdexFile> Open(const std::string& vdex_filename,
213                                         bool writable,
214                                         bool low_4gb,
215                                         std::string* error_msg) {
216     return OpenAtAddress(nullptr,
217                          0,
218                          false,
219                          vdex_filename,
220                          writable,
221                          low_4gb,
222                          error_msg);
223   }
224 
225   // 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,std::string * error_msg)226   static std::unique_ptr<VdexFile> Open(int file_fd,
227                                         size_t vdex_length,
228                                         const std::string& vdex_filename,
229                                         bool writable,
230                                         bool low_4gb,
231                                         std::string* error_msg) {
232     return OpenAtAddress(nullptr,
233                          0,
234                          false,
235                          file_fd,
236                          vdex_length,
237                          vdex_filename,
238                          writable,
239                          low_4gb,
240                          error_msg);
241   }
242 
243   static std::unique_ptr<VdexFile> OpenFromDm(const std::string& filename,
244                                               const ZipArchive& archive);
245 
Begin()246   const uint8_t* Begin() const { return mmap_.Begin(); }
End()247   const uint8_t* End() const { return mmap_.End(); }
Size()248   size_t Size() const { return mmap_.Size(); }
Contains(const uint8_t * pointer)249   bool Contains(const uint8_t* pointer) const {
250     return pointer >= Begin() && pointer < End();
251   }
252 
GetVdexFileHeader()253   const VdexFileHeader& GetVdexFileHeader() const {
254     return *reinterpret_cast<const VdexFileHeader*>(Begin());
255   }
256 
GetVerifierDepsData()257   ArrayRef<const uint8_t> GetVerifierDepsData() const {
258     return ArrayRef<const uint8_t>(
259         Begin() + GetSectionHeader(VdexSection::kVerifierDepsSection).section_offset,
260         GetSectionHeader(VdexSection::kVerifierDepsSection).section_size);
261   }
262 
IsValid()263   bool IsValid() const {
264     return mmap_.Size() >= sizeof(VdexFileHeader) && GetVdexFileHeader().IsValid();
265   }
266 
267   // This method is for iterating over the dex files in the vdex. If `cursor` is null,
268   // the first dex file is returned. If `cursor` is not null, it must point to a dex
269   // file and this method returns the next dex file if there is one, or null if there
270   // is none.
271   const uint8_t* GetNextDexFileData(const uint8_t* cursor, uint32_t dex_file_index) const;
272 
273   const uint8_t* GetNextTypeLookupTableData(const uint8_t* cursor, uint32_t dex_file_index) const;
274 
275   // Get the location checksum of the dex file number `dex_file_index`.
GetLocationChecksum(uint32_t dex_file_index)276   uint32_t GetLocationChecksum(uint32_t dex_file_index) const {
277     DCHECK_LT(dex_file_index, GetNumberOfDexFiles());
278     return GetDexChecksumAt(dex_file_index);
279   }
280 
281   // Open all the dex files contained in this vdex file.
282   bool OpenAllDexFiles(std::vector<std::unique_ptr<const DexFile>>* dex_files,
283                        std::string* error_msg) const;
284 
285   // Writes a vdex into `path` and returns true on success.
286   // The vdex will not contain a dex section but will store checksums of `dex_files`,
287   // encoded `verifier_deps`, as well as the current boot class path cheksum and
288   // encoded `class_loader_context`.
289   static bool WriteToDisk(const std::string& path,
290                           const std::vector<const DexFile*>& dex_files,
291                           const verifier::VerifierDeps& verifier_deps,
292                           std::string* error_msg);
293 
294   // Returns true if the dex file checksums stored in the vdex header match
295   // the checksums in `dex_headers`. Both the number of dex files and their
296   // order must match too.
297   bool MatchesDexFileChecksums(const std::vector<const DexFile::Header*>& dex_headers) const;
298 
299   ClassStatus ComputeClassStatus(Thread* self, Handle<mirror::Class> cls) const
300       REQUIRES_SHARED(Locks::mutator_lock_);
301 
302   // Return the name of the underlying `MemMap` of the vdex file, typically the
303   // location on disk of the vdex file.
GetName()304   const std::string& GetName() const {
305     return mmap_.GetName();
306   }
307 
308  private:
309   bool ContainsDexFile(const DexFile& dex_file) const;
310 
DexBegin()311   const uint8_t* DexBegin() const {
312     DCHECK(HasDexSection());
313     return Begin() + GetSectionHeader(VdexSection::kDexFileSection).section_offset;
314   }
315 
TypeLookupTableDataBegin()316   const uint8_t* TypeLookupTableDataBegin() const {
317     DCHECK(HasTypeLookupTableSection());
318     return Begin() + GetSectionHeader(VdexSection::kTypeLookupTableSection).section_offset;
319   }
320 
321   MemMap mmap_;
322 
323   DISALLOW_COPY_AND_ASSIGN(VdexFile);
324 };
325 
326 }  // namespace art
327 
328 #endif  // ART_RUNTIME_VDEX_FILE_H_
329