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