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