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