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