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