Home | History | Annotate | Download | only in runtime
      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 "dex/compact_offset_table.h"
     28 #include "dex/dex_file.h"
     29 #include "quicken_info.h"
     30 
     31 namespace art {
     32 
     33 class ClassLoaderContext;
     34 
     35 namespace verifier {
     36 class VerifierDeps;
     37 }  // namespace verifier
     38 
     39 // VDEX files contain extracted DEX files. The VdexFile class maps the file to
     40 // memory and provides tools for accessing its individual sections.
     41 //
     42 // File format:
     43 //   VdexFile::VerifierDepsHeader    fixed-length header
     44 //      Dex file checksums
     45 //
     46 //   Optionally:
     47 //      VdexFile::DexSectionHeader   fixed-length header
     48 //
     49 //      quicken_table_off[0]  offset into QuickeningInfo section for offset table for DEX[0].
     50 //      DEX[0]                array of the input DEX files, the bytecode may have been quickened.
     51 //      quicken_table_off[1]
     52 //      DEX[1]
     53 //      ...
     54 //      DEX[D]
     55 //
     56 //   VerifierDeps
     57 //      uint8[D][]                 verification dependencies
     58 //
     59 //   Optionally:
     60 //      QuickeningInfo
     61 //        uint8[D][]                  quickening data
     62 //        uint32[D][]                 quickening data offset tables
     63 
     64 class VdexFile {
     65  public:
     66   using VdexChecksum = uint32_t;
     67   using QuickeningTableOffsetType = uint32_t;
     68 
     69   struct VerifierDepsHeader {
     70    public:
     71     VerifierDepsHeader(uint32_t number_of_dex_files_,
     72                        uint32_t verifier_deps_size,
     73                        bool has_dex_section,
     74                        uint32_t bootclasspath_checksums_size = 0,
     75                        uint32_t class_loader_context_size = 0);
     76 
     77     const char* GetMagic() const { return reinterpret_cast<const char*>(magic_); }
     78     const char* GetVerifierDepsVersion() const {
     79       return reinterpret_cast<const char*>(verifier_deps_version_);
     80     }
     81     const char* GetDexSectionVersion() const {
     82       return reinterpret_cast<const char*>(dex_section_version_);
     83     }
     84     bool IsMagicValid() const;
     85     bool IsVerifierDepsVersionValid() const;
     86     bool IsDexSectionVersionValid() const;
     87     bool IsValid() const {
     88       return IsMagicValid() && IsVerifierDepsVersionValid() && IsDexSectionVersionValid();
     89     }
     90     bool HasDexSection() const;
     91 
     92     uint32_t GetVerifierDepsSize() const { return verifier_deps_size_; }
     93     uint32_t GetNumberOfDexFiles() const { return number_of_dex_files_; }
     94     uint32_t GetBootClassPathChecksumStringSize() const { return bootclasspath_checksums_size_; }
     95     uint32_t GetClassLoaderContextStringSize() const { return class_loader_context_size_; }
     96 
     97     size_t GetSizeOfChecksumsSection() const {
     98       return sizeof(VdexChecksum) * GetNumberOfDexFiles();
     99     }
    100 
    101     const VdexChecksum* GetDexChecksumsArray() const {
    102       return reinterpret_cast<const VdexChecksum*>(
    103           reinterpret_cast<const uint8_t*>(this) + sizeof(VerifierDepsHeader));
    104     }
    105 
    106     VdexChecksum GetDexChecksumAtOffset(size_t idx) const {
    107       DCHECK_LT(idx, GetNumberOfDexFiles());
    108       return GetDexChecksumsArray()[idx];
    109     }
    110 
    111     static constexpr uint8_t kVdexInvalidMagic[] = { 'w', 'd', 'e', 'x' };
    112 
    113    private:
    114     static constexpr uint8_t kVdexMagic[] = { 'v', 'd', 'e', 'x' };
    115 
    116     // The format version of the verifier deps header and the verifier deps.
    117     // Last update: Add boot checksum, class loader context.
    118     static constexpr uint8_t kVerifierDepsVersion[] = { '0', '2', '1', '\0' };
    119 
    120     // The format version of the dex section header and the dex section, containing
    121     // both the dex code and the quickening data.
    122     // Last update: Add owned section for CompactDex.
    123     static constexpr uint8_t kDexSectionVersion[] = { '0', '0', '2', '\0' };
    124 
    125     // If the .vdex file has no dex section (hence no dex code nor quickening data),
    126     // we encode this magic version.
    127     static constexpr uint8_t kDexSectionVersionEmpty[] = { '0', '0', '0', '\0' };
    128 
    129     uint8_t magic_[4];
    130     uint8_t verifier_deps_version_[4];
    131     uint8_t dex_section_version_[4];
    132     uint32_t number_of_dex_files_;
    133     uint32_t verifier_deps_size_;
    134     uint32_t bootclasspath_checksums_size_;
    135     uint32_t class_loader_context_size_;
    136   };
    137 
    138   struct DexSectionHeader {
    139    public:
    140     DexSectionHeader(uint32_t dex_size,
    141                      uint32_t dex_shared_data_size,
    142                      uint32_t quickening_info_size);
    143 
    144     uint32_t GetDexSize() const { return dex_size_; }
    145     uint32_t GetDexSharedDataSize() const { return dex_shared_data_size_; }
    146     uint32_t GetQuickeningInfoSize() const { return quickening_info_size_; }
    147 
    148     size_t GetDexSectionSize() const {
    149       return sizeof(DexSectionHeader) +
    150            GetDexSize() +
    151            GetDexSharedDataSize();
    152     }
    153 
    154    private:
    155     uint32_t dex_size_;
    156     uint32_t dex_shared_data_size_;
    157     uint32_t quickening_info_size_;
    158 
    159     friend class VdexFile;  // For updating quickening_info_size_.
    160   };
    161 
    162   size_t GetComputedFileSize() const {
    163     size_t size = sizeof(VerifierDepsHeader);
    164     const VerifierDepsHeader& header = GetVerifierDepsHeader();
    165     size += header.GetVerifierDepsSize();
    166     size += header.GetSizeOfChecksumsSection();
    167     if (header.HasDexSection()) {
    168       size += GetDexSectionHeader().GetDexSectionSize();
    169       size += GetDexSectionHeader().GetQuickeningInfoSize();
    170     }
    171     size += header.GetBootClassPathChecksumStringSize();
    172     size += header.GetClassLoaderContextStringSize();
    173     return size;
    174   }
    175 
    176   // Note: The file is called "primary" to match the naming with profiles.
    177   static const constexpr char* kVdexNameInDmFile = "primary.vdex";
    178 
    179   explicit VdexFile(MemMap&& mmap) : mmap_(std::move(mmap)) {}
    180 
    181   // Returns nullptr if the vdex file cannot be opened or is not valid.
    182   // The mmap_* parameters can be left empty (nullptr/0/false) to allocate at random address.
    183   static std::unique_ptr<VdexFile> OpenAtAddress(uint8_t* mmap_addr,
    184                                                  size_t mmap_size,
    185                                                  bool mmap_reuse,
    186                                                  const std::string& vdex_filename,
    187                                                  bool writable,
    188                                                  bool low_4gb,
    189                                                  bool unquicken,
    190                                                  std::string* error_msg);
    191 
    192   // Returns nullptr if the vdex file cannot be opened or is not valid.
    193   // The mmap_* parameters can be left empty (nullptr/0/false) to allocate at random address.
    194   static std::unique_ptr<VdexFile> OpenAtAddress(uint8_t* mmap_addr,
    195                                                  size_t mmap_size,
    196                                                  bool mmap_reuse,
    197                                                  int file_fd,
    198                                                  size_t vdex_length,
    199                                                  const std::string& vdex_filename,
    200                                                  bool writable,
    201                                                  bool low_4gb,
    202                                                  bool unquicken,
    203                                                  std::string* error_msg);
    204 
    205   // Returns nullptr if the vdex file cannot be opened or is not valid.
    206   static std::unique_ptr<VdexFile> Open(const std::string& vdex_filename,
    207                                         bool writable,
    208                                         bool low_4gb,
    209                                         bool unquicken,
    210                                         std::string* error_msg) {
    211     return OpenAtAddress(nullptr,
    212                          0,
    213                          false,
    214                          vdex_filename,
    215                          writable,
    216                          low_4gb,
    217                          unquicken,
    218                          error_msg);
    219   }
    220 
    221   // Returns nullptr if the vdex file cannot be opened or is not valid.
    222   static std::unique_ptr<VdexFile> Open(int file_fd,
    223                                         size_t vdex_length,
    224                                         const std::string& vdex_filename,
    225                                         bool writable,
    226                                         bool low_4gb,
    227                                         bool unquicken,
    228                                         std::string* error_msg) {
    229     return OpenAtAddress(nullptr,
    230                          0,
    231                          false,
    232                          file_fd,
    233                          vdex_length,
    234                          vdex_filename,
    235                          writable,
    236                          low_4gb,
    237                          unquicken,
    238                          error_msg);
    239   }
    240 
    241   const uint8_t* Begin() const { return mmap_.Begin(); }
    242   const uint8_t* End() const { return mmap_.End(); }
    243   size_t Size() const { return mmap_.Size(); }
    244 
    245   const VerifierDepsHeader& GetVerifierDepsHeader() const {
    246     return *reinterpret_cast<const VerifierDepsHeader*>(Begin());
    247   }
    248 
    249   uint32_t GetDexSectionHeaderOffset() const {
    250     return sizeof(VerifierDepsHeader) + GetVerifierDepsHeader().GetSizeOfChecksumsSection();
    251   }
    252 
    253   const DexSectionHeader& GetDexSectionHeader() const {
    254     DCHECK(GetVerifierDepsHeader().HasDexSection());
    255     return *reinterpret_cast<const DexSectionHeader*>(Begin() + GetDexSectionHeaderOffset());
    256   }
    257 
    258   const uint8_t* GetVerifierDepsStart() const {
    259     const uint8_t* result = Begin() + GetDexSectionHeaderOffset();
    260     if (GetVerifierDepsHeader().HasDexSection()) {
    261       // When there is a dex section, the verifier deps are after it, but before the quickening.
    262       return result + GetDexSectionHeader().GetDexSectionSize();
    263     } else {
    264       // When there is no dex section, the verifier deps are just after the header.
    265       return result;
    266     }
    267   }
    268 
    269   ArrayRef<const uint8_t> GetVerifierDepsData() const {
    270     return ArrayRef<const uint8_t>(
    271         GetVerifierDepsStart(),
    272         GetVerifierDepsHeader().GetVerifierDepsSize());
    273   }
    274 
    275   ArrayRef<const uint8_t> GetQuickeningInfo() const {
    276     return ArrayRef<const uint8_t>(
    277         GetVerifierDepsData().end(),
    278         GetVerifierDepsHeader().HasDexSection()
    279             ? GetDexSectionHeader().GetQuickeningInfoSize() : 0);
    280   }
    281 
    282   ArrayRef<const uint8_t> GetBootClassPathChecksumData() const {
    283     return ArrayRef<const uint8_t>(
    284         GetQuickeningInfo().end(),
    285         GetVerifierDepsHeader().GetBootClassPathChecksumStringSize());
    286   }
    287 
    288   ArrayRef<const uint8_t> GetClassLoaderContextData() const {
    289     return ArrayRef<const uint8_t>(
    290         GetBootClassPathChecksumData().end(),
    291         GetVerifierDepsHeader().GetClassLoaderContextStringSize());
    292   }
    293 
    294   bool IsValid() const {
    295     return mmap_.Size() >= sizeof(VerifierDepsHeader) && GetVerifierDepsHeader().IsValid();
    296   }
    297 
    298   // This method is for iterating over the dex files in the vdex. If `cursor` is null,
    299   // the first dex file is returned. If `cursor` is not null, it must point to a dex
    300   // file and this method returns the next dex file if there is one, or null if there
    301   // is none.
    302   const uint8_t* GetNextDexFileData(const uint8_t* cursor) const;
    303 
    304   // Get the location checksum of the dex file number `dex_file_index`.
    305   uint32_t GetLocationChecksum(uint32_t dex_file_index) const {
    306     DCHECK_LT(dex_file_index, GetVerifierDepsHeader().GetNumberOfDexFiles());
    307     return reinterpret_cast<const uint32_t*>(Begin() + sizeof(VerifierDepsHeader))[dex_file_index];
    308   }
    309 
    310   // Open all the dex files contained in this vdex file.
    311   bool OpenAllDexFiles(std::vector<std::unique_ptr<const DexFile>>* dex_files,
    312                        std::string* error_msg);
    313 
    314   // In-place unquicken the given `dex_files` based on `quickening_info`.
    315   // `decompile_return_instruction` controls if RETURN_VOID_BARRIER instructions are
    316   // decompiled to RETURN_VOID instructions using the slower ClassAccessor instead of the faster
    317   // QuickeningInfoIterator.
    318   // Always unquickens using the vdex dex files as the source for quicken tables.
    319   void Unquicken(const std::vector<const DexFile*>& target_dex_files,
    320                  bool decompile_return_instruction) const;
    321 
    322   // Fully unquicken `target_dex_file` based on `quickening_info`.
    323   void UnquickenDexFile(const DexFile& target_dex_file,
    324                         const DexFile& source_dex_file,
    325                         bool decompile_return_instruction) const;
    326 
    327   // Return the quickening info of a given method index (or null if it's empty).
    328   ArrayRef<const uint8_t> GetQuickenedInfoOf(const DexFile& dex_file,
    329                                              uint32_t dex_method_idx) const;
    330 
    331   bool HasDexSection() const {
    332     return GetVerifierDepsHeader().HasDexSection();
    333   }
    334 
    335   // Writes a vdex into `path` and returns true on success.
    336   // The vdex will not contain a dex section but will store checksums of `dex_files`,
    337   // encoded `verifier_deps`, as well as the current boot class path cheksum and
    338   // encoded `class_loader_context`.
    339   static bool WriteToDisk(const std::string& path,
    340                           const std::vector<const DexFile*>& dex_files,
    341                           const verifier::VerifierDeps& verifier_deps,
    342                           const std::string& class_loader_context,
    343                           std::string* error_msg);
    344 
    345   // Returns true if the dex file checksums stored in the vdex header match
    346   // the checksums in `dex_headers`. Both the number of dex files and their
    347   // order must match too.
    348   bool MatchesDexFileChecksums(const std::vector<const DexFile::Header*>& dex_headers) const;
    349 
    350   // Returns true if the boot class path checksum stored in the vdex matches
    351   // the checksum of boot class path in the current runtime.
    352   bool MatchesBootClassPathChecksums() const;
    353 
    354   // Returns true if the class loader context stored in the vdex matches `context`.
    355   bool MatchesClassLoaderContext(const ClassLoaderContext& context) const;
    356 
    357  private:
    358   uint32_t GetQuickeningInfoTableOffset(const uint8_t* source_dex_begin) const;
    359 
    360   // Source dex must be the in the vdex file.
    361   void UnquickenDexFile(const DexFile& target_dex_file,
    362                         const uint8_t* source_dex_begin,
    363                         bool decompile_return_instruction) const;
    364 
    365   CompactOffsetTable::Accessor GetQuickenInfoOffsetTable(
    366         const DexFile& dex_file,
    367         const ArrayRef<const uint8_t>& quickening_info) const;
    368 
    369   CompactOffsetTable::Accessor GetQuickenInfoOffsetTable(
    370       const uint8_t* source_dex_begin,
    371       const ArrayRef<const uint8_t>& quickening_info) const;
    372 
    373   bool ContainsDexFile(const DexFile& dex_file) const;
    374 
    375   const uint8_t* DexBegin() const {
    376     DCHECK(HasDexSection());
    377     return Begin() + GetDexSectionHeaderOffset() + sizeof(DexSectionHeader);
    378   }
    379 
    380   const uint8_t* DexEnd() const {
    381     DCHECK(HasDexSection());
    382     return DexBegin() + GetDexSectionHeader().GetDexSize();
    383   }
    384 
    385   MemMap mmap_;
    386 
    387   DISALLOW_COPY_AND_ASSIGN(VdexFile);
    388 };
    389 
    390 }  // namespace art
    391 
    392 #endif  // ART_RUNTIME_VDEX_FILE_H_
    393