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