| David Brazdil | 7b49e6c | 2016-09-01 11:06:18 +0100 | [diff] [blame] | 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 | #include "vdex_file.h" |
| 18 | |
| Andreas Gampe | 0dfc315 | 2017-04-24 07:58:06 -0700 | [diff] [blame] | 19 | #include <sys/mman.h> // For the PROT_* and MAP_* constants. |
| David Brazdil | 35a3f6a | 2019-03-04 15:59:06 +0000 | [diff] [blame] | 20 | #include <sys/stat.h> // for mkdir() |
| Andreas Gampe | 0dfc315 | 2017-04-24 07:58:06 -0700 | [diff] [blame] | 21 | |
| David Brazdil | 7b49e6c | 2016-09-01 11:06:18 +0100 | [diff] [blame] | 22 | #include <memory> |
| Mathieu Chartier | a79efdb | 2018-01-18 16:31:01 -0800 | [diff] [blame] | 23 | #include <unordered_set> |
| David Brazdil | 7b49e6c | 2016-09-01 11:06:18 +0100 | [diff] [blame] | 24 | |
| Andreas Gampe | 5794381 | 2017-12-06 21:39:13 -0800 | [diff] [blame] | 25 | #include <android-base/logging.h> |
| 26 | |
| Nicolas Geoffray | 28453cf | 2017-08-10 15:30:26 +0100 | [diff] [blame] | 27 | #include "base/bit_utils.h" |
| David Sehr | 67bf42e | 2018-02-26 16:43:04 -0800 | [diff] [blame] | 28 | #include "base/leb128.h" |
| Nicolas Geoffray | 4e868fa | 2017-04-21 17:16:44 +0100 | [diff] [blame] | 29 | #include "base/stl_util.h" |
| Mathieu Chartier | 4a17f8a | 2019-05-17 11:03:26 -0700 | [diff] [blame] | 30 | #include "base/systrace.h" |
| Andreas Gampe | f7e8223 | 2016-09-12 15:55:56 -0700 | [diff] [blame] | 31 | #include "base/unix_file/fd_file.h" |
| David Brazdil | 35a3f6a | 2019-03-04 15:59:06 +0000 | [diff] [blame] | 32 | #include "class_linker.h" |
| 33 | #include "class_loader_context.h" |
| David Sehr | 013fd80 | 2018-01-11 22:55:24 -0800 | [diff] [blame] | 34 | #include "dex/art_dex_file_loader.h" |
| Mathieu Chartier | 1f1cb9f | 2018-06-04 09:22:46 -0700 | [diff] [blame] | 35 | #include "dex/class_accessor-inl.h" |
| David Sehr | 9e734c7 | 2018-01-04 17:56:19 -0800 | [diff] [blame] | 36 | #include "dex/dex_file_loader.h" |
| David Brazdil | 35a3f6a | 2019-03-04 15:59:06 +0000 | [diff] [blame] | 37 | #include "gc/heap.h" |
| 38 | #include "gc/space/image_space.h" |
| Nicolas Geoffray | 6df4511 | 2021-02-07 21:51:58 +0000 | [diff] [blame] | 39 | #include "mirror/class-inl.h" |
| Mathieu Chartier | 210531f | 2018-01-12 10:15:51 -0800 | [diff] [blame] | 40 | #include "quicken_info.h" |
| Nicolas Geoffray | 6df4511 | 2021-02-07 21:51:58 +0000 | [diff] [blame] | 41 | #include "handle_scope-inl.h" |
| David Brazdil | 35a3f6a | 2019-03-04 15:59:06 +0000 | [diff] [blame] | 42 | #include "runtime.h" |
| 43 | #include "verifier/verifier_deps.h" |
| David Brazdil | 7b49e6c | 2016-09-01 11:06:18 +0100 | [diff] [blame] | 44 | |
| 45 | namespace art { |
| 46 | |
| Nicolas Geoffray | a129d8a | 2021-03-18 22:23:04 +0000 | [diff] [blame] | 47 | constexpr uint8_t VdexFile::VdexFileHeader::kVdexInvalidMagic[4]; |
| 48 | constexpr uint8_t VdexFile::VdexFileHeader::kVdexMagic[4]; |
| 49 | constexpr uint8_t VdexFile::VdexFileHeader::kVdexVersion[4]; |
| David Brazdil | 7b49e6c | 2016-09-01 11:06:18 +0100 | [diff] [blame] | 50 | |
| Nicolas Geoffray | a129d8a | 2021-03-18 22:23:04 +0000 | [diff] [blame] | 51 | bool VdexFile::VdexFileHeader::IsMagicValid() const { |
| David Brazdil | 7b49e6c | 2016-09-01 11:06:18 +0100 | [diff] [blame] | 52 | return (memcmp(magic_, kVdexMagic, sizeof(kVdexMagic)) == 0); |
| 53 | } |
| 54 | |
| Nicolas Geoffray | a129d8a | 2021-03-18 22:23:04 +0000 | [diff] [blame] | 55 | bool VdexFile::VdexFileHeader::IsVdexVersionValid() const { |
| 56 | return (memcmp(vdex_version_, kVdexVersion, sizeof(kVdexVersion)) == 0); |
| David Brazdil | 7b49e6c | 2016-09-01 11:06:18 +0100 | [diff] [blame] | 57 | } |
| 58 | |
| Nicolas Geoffray | a129d8a | 2021-03-18 22:23:04 +0000 | [diff] [blame] | 59 | VdexFile::VdexFileHeader::VdexFileHeader(bool has_dex_section ATTRIBUTE_UNUSED) |
| 60 | : number_of_sections_(static_cast<uint32_t>(VdexSection::kNumberOfSections)) { |
| David Brazdil | 7b49e6c | 2016-09-01 11:06:18 +0100 | [diff] [blame] | 61 | memcpy(magic_, kVdexMagic, sizeof(kVdexMagic)); |
| Nicolas Geoffray | a129d8a | 2021-03-18 22:23:04 +0000 | [diff] [blame] | 62 | memcpy(vdex_version_, kVdexVersion, sizeof(kVdexVersion)); |
| David Brazdil | 7b49e6c | 2016-09-01 11:06:18 +0100 | [diff] [blame] | 63 | DCHECK(IsMagicValid()); |
| Nicolas Geoffray | a129d8a | 2021-03-18 22:23:04 +0000 | [diff] [blame] | 64 | DCHECK(IsVdexVersionValid()); |
| David Brazdil | 7b49e6c | 2016-09-01 11:06:18 +0100 | [diff] [blame] | 65 | } |
| 66 | |
| David Srbecky | ec2cdf4 | 2017-12-08 16:21:25 +0000 | [diff] [blame] | 67 | std::unique_ptr<VdexFile> VdexFile::OpenAtAddress(uint8_t* mmap_addr, |
| 68 | size_t mmap_size, |
| 69 | bool mmap_reuse, |
| 70 | const std::string& vdex_filename, |
| 71 | bool writable, |
| 72 | bool low_4gb, |
| 73 | bool unquicken, |
| 74 | std::string* error_msg) { |
| Mathieu Chartier | 4a17f8a | 2019-05-17 11:03:26 -0700 | [diff] [blame] | 75 | ScopedTrace trace(("VdexFile::OpenAtAddress " + vdex_filename).c_str()); |
| David Brazdil | 7b49e6c | 2016-09-01 11:06:18 +0100 | [diff] [blame] | 76 | if (!OS::FileExists(vdex_filename.c_str())) { |
| 77 | *error_msg = "File " + vdex_filename + " does not exist."; |
| 78 | return nullptr; |
| 79 | } |
| 80 | |
| 81 | std::unique_ptr<File> vdex_file; |
| 82 | if (writable) { |
| 83 | vdex_file.reset(OS::OpenFileReadWrite(vdex_filename.c_str())); |
| 84 | } else { |
| 85 | vdex_file.reset(OS::OpenFileForReading(vdex_filename.c_str())); |
| 86 | } |
| 87 | if (vdex_file == nullptr) { |
| 88 | *error_msg = "Could not open file " + vdex_filename + |
| 89 | (writable ? " for read/write" : "for reading"); |
| 90 | return nullptr; |
| 91 | } |
| 92 | |
| 93 | int64_t vdex_length = vdex_file->GetLength(); |
| 94 | if (vdex_length == -1) { |
| 95 | *error_msg = "Could not read the length of file " + vdex_filename; |
| 96 | return nullptr; |
| 97 | } |
| 98 | |
| David Srbecky | ec2cdf4 | 2017-12-08 16:21:25 +0000 | [diff] [blame] | 99 | return OpenAtAddress(mmap_addr, |
| 100 | mmap_size, |
| 101 | mmap_reuse, |
| 102 | vdex_file->Fd(), |
| 103 | vdex_length, |
| 104 | vdex_filename, |
| 105 | writable, |
| 106 | low_4gb, |
| 107 | unquicken, |
| 108 | error_msg); |
| Nicolas Geoffray | b0bbe8e | 2016-11-19 10:42:37 +0000 | [diff] [blame] | 109 | } |
| 110 | |
| David Srbecky | ec2cdf4 | 2017-12-08 16:21:25 +0000 | [diff] [blame] | 111 | std::unique_ptr<VdexFile> VdexFile::OpenAtAddress(uint8_t* mmap_addr, |
| 112 | size_t mmap_size, |
| 113 | bool mmap_reuse, |
| 114 | int file_fd, |
| 115 | size_t vdex_length, |
| 116 | const std::string& vdex_filename, |
| 117 | bool writable, |
| 118 | bool low_4gb, |
| 119 | bool unquicken, |
| 120 | std::string* error_msg) { |
| David Srbecky | ec2cdf4 | 2017-12-08 16:21:25 +0000 | [diff] [blame] | 121 | if (mmap_addr != nullptr && mmap_size < vdex_length) { |
| 122 | LOG(WARNING) << "Insufficient pre-allocated space to mmap vdex."; |
| 123 | mmap_addr = nullptr; |
| 124 | mmap_reuse = false; |
| 125 | } |
| Andreas Gampe | c1fc449 | 2018-01-10 14:19:36 -0800 | [diff] [blame] | 126 | CHECK(!mmap_reuse || mmap_addr != nullptr); |
| Alex Light | abd8f05 | 2019-12-06 10:49:17 -0800 | [diff] [blame] | 127 | CHECK(!(writable && unquicken)) << "We don't want to be writing unquickened files out to disk!"; |
| 128 | // Start as PROT_WRITE so we can mprotect back to it if we want to. |
| Vladimir Marko | c34bebf | 2018-08-16 16:12:49 +0100 | [diff] [blame] | 129 | MemMap mmap = MemMap::MapFileAtAddress( |
| David Srbecky | ec2cdf4 | 2017-12-08 16:21:25 +0000 | [diff] [blame] | 130 | mmap_addr, |
| Nicolas Geoffray | 4e868fa | 2017-04-21 17:16:44 +0100 | [diff] [blame] | 131 | vdex_length, |
| Alex Light | abd8f05 | 2019-12-06 10:49:17 -0800 | [diff] [blame] | 132 | PROT_READ | PROT_WRITE, |
| 133 | writable ? MAP_SHARED : MAP_PRIVATE, |
| Nicolas Geoffray | 4e868fa | 2017-04-21 17:16:44 +0100 | [diff] [blame] | 134 | file_fd, |
| Andreas Gampe | 98ea9d9 | 2018-10-19 14:06:15 -0700 | [diff] [blame] | 135 | /* start= */ 0u, |
| Nicolas Geoffray | 4e868fa | 2017-04-21 17:16:44 +0100 | [diff] [blame] | 136 | low_4gb, |
| 137 | vdex_filename.c_str(), |
| Vladimir Marko | c09cd05 | 2018-08-23 16:36:36 +0100 | [diff] [blame] | 138 | mmap_reuse, |
| Andreas Gampe | 98ea9d9 | 2018-10-19 14:06:15 -0700 | [diff] [blame] | 139 | /* reservation= */ nullptr, |
| Vladimir Marko | c34bebf | 2018-08-16 16:12:49 +0100 | [diff] [blame] | 140 | error_msg); |
| 141 | if (!mmap.IsValid()) { |
| David Brazdil | 7b49e6c | 2016-09-01 11:06:18 +0100 | [diff] [blame] | 142 | *error_msg = "Failed to mmap file " + vdex_filename + " : " + *error_msg; |
| 143 | return nullptr; |
| 144 | } |
| 145 | |
| Vladimir Marko | c34bebf | 2018-08-16 16:12:49 +0100 | [diff] [blame] | 146 | std::unique_ptr<VdexFile> vdex(new VdexFile(std::move(mmap))); |
| Richard Uhler | b8ab63a | 2017-01-31 11:27:37 +0000 | [diff] [blame] | 147 | if (!vdex->IsValid()) { |
| 148 | *error_msg = "Vdex file is not valid"; |
| 149 | return nullptr; |
| 150 | } |
| 151 | |
| Nicolas Geoffray | 9d393d5 | 2021-03-31 10:15:47 +0100 | [diff] [blame] | 152 | if (!writable) { |
| 153 | Runtime* runtime = Runtime::Current(); |
| 154 | // The runtime might not be available at this point if we're running |
| 155 | // dex2oat or oatdump. |
| 156 | if (runtime != nullptr) { |
| 157 | size_t madvise_size_limit = runtime->GetMadviseWillNeedSizeVdex(); |
| 158 | Runtime::MadviseFileForRange(madvise_size_limit, |
| 159 | vdex->Size(), |
| 160 | vdex->Begin(), |
| 161 | vdex->End(), |
| 162 | vdex_filename); |
| 163 | } |
| 164 | } |
| 165 | |
| Richard Uhler | b8ab63a | 2017-01-31 11:27:37 +0000 | [diff] [blame] | 166 | return vdex; |
| David Brazdil | 7b49e6c | 2016-09-01 11:06:18 +0100 | [diff] [blame] | 167 | } |
| 168 | |
| Nicolas Geoffray | a129d8a | 2021-03-18 22:23:04 +0000 | [diff] [blame] | 169 | const uint8_t* VdexFile::GetNextDexFileData(const uint8_t* cursor, uint32_t dex_file_index) const { |
| Nicolas Geoffray | b0bbe8e | 2016-11-19 10:42:37 +0000 | [diff] [blame] | 170 | DCHECK(cursor == nullptr || (cursor > Begin() && cursor <= End())); |
| 171 | if (cursor == nullptr) { |
| 172 | // Beginning of the iteration, return the first dex file if there is one. |
| Nicolas Geoffray | a129d8a | 2021-03-18 22:23:04 +0000 | [diff] [blame] | 173 | return HasDexSection() ? DexBegin() : nullptr; |
| 174 | } else if (dex_file_index >= GetNumberOfDexFiles()) { |
| 175 | return nullptr; |
| Nicolas Geoffray | b0bbe8e | 2016-11-19 10:42:37 +0000 | [diff] [blame] | 176 | } else { |
| 177 | // Fetch the next dex file. Return null if there is none. |
| 178 | const uint8_t* data = cursor + reinterpret_cast<const DexFile::Header*>(cursor)->file_size_; |
| Nicolas Geoffray | 28453cf | 2017-08-10 15:30:26 +0100 | [diff] [blame] | 179 | // Dex files are required to be 4 byte aligned. the OatWriter makes sure they are, see |
| 180 | // OatWriter::SeekToDexFiles. |
| Nicolas Geoffray | a129d8a | 2021-03-18 22:23:04 +0000 | [diff] [blame] | 181 | return AlignUp(data, 4); |
| Nicolas Geoffray | b0bbe8e | 2016-11-19 10:42:37 +0000 | [diff] [blame] | 182 | } |
| 183 | } |
| 184 | |
| Nicolas Geoffray | 0b94328 | 2021-04-16 09:16:00 +0000 | [diff] [blame] | 185 | const uint8_t* VdexFile::GetNextTypeLookupTableData(const uint8_t* cursor, |
| 186 | uint32_t dex_file_index) const { |
| 187 | if (cursor == nullptr) { |
| 188 | // Beginning of the iteration, return the first dex file if there is one. |
| 189 | return HasTypeLookupTableSection() ? TypeLookupTableDataBegin() : nullptr; |
| 190 | } else if (dex_file_index >= GetNumberOfDexFiles()) { |
| 191 | return nullptr; |
| 192 | } else { |
| 193 | const uint8_t* data = cursor + sizeof(uint32_t) + reinterpret_cast<const uint32_t*>(cursor)[0]; |
| 194 | // TypeLookupTables are required to be 4 byte aligned. the OatWriter makes sure they are. |
| 195 | CHECK_ALIGNED(data, 4); |
| 196 | return data; |
| 197 | } |
| 198 | } |
| 199 | |
| David Sehr | beca4fe | 2017-03-30 17:50:24 -0700 | [diff] [blame] | 200 | bool VdexFile::OpenAllDexFiles(std::vector<std::unique_ptr<const DexFile>>* dex_files, |
| Alex Light | abd8f05 | 2019-12-06 10:49:17 -0800 | [diff] [blame] | 201 | std::string* error_msg) const { |
| David Sehr | 013fd80 | 2018-01-11 22:55:24 -0800 | [diff] [blame] | 202 | const ArtDexFileLoader dex_file_loader; |
| David Sehr | beca4fe | 2017-03-30 17:50:24 -0700 | [diff] [blame] | 203 | size_t i = 0; |
| Nicolas Geoffray | a129d8a | 2021-03-18 22:23:04 +0000 | [diff] [blame] | 204 | for (const uint8_t* dex_file_start = GetNextDexFileData(nullptr, i); |
| David Sehr | beca4fe | 2017-03-30 17:50:24 -0700 | [diff] [blame] | 205 | dex_file_start != nullptr; |
| Nicolas Geoffray | a129d8a | 2021-03-18 22:23:04 +0000 | [diff] [blame] | 206 | dex_file_start = GetNextDexFileData(dex_file_start, ++i)) { |
| David Sehr | beca4fe | 2017-03-30 17:50:24 -0700 | [diff] [blame] | 207 | size_t size = reinterpret_cast<const DexFile::Header*>(dex_file_start)->file_size_; |
| 208 | // TODO: Supply the location information for a vdex file. |
| 209 | static constexpr char kVdexLocation[] = ""; |
| Mathieu Chartier | 79c87da | 2017-10-10 11:54:29 -0700 | [diff] [blame] | 210 | std::string location = DexFileLoader::GetMultiDexLocation(i, kVdexLocation); |
| Mathieu Chartier | c3a22aa | 2018-01-19 18:58:34 -0800 | [diff] [blame] | 211 | std::unique_ptr<const DexFile> dex(dex_file_loader.OpenWithDataSection( |
| 212 | dex_file_start, |
| 213 | size, |
| Andreas Gampe | 98ea9d9 | 2018-10-19 14:06:15 -0700 | [diff] [blame] | 214 | /*data_base=*/ nullptr, |
| 215 | /*data_size=*/ 0u, |
| Mathieu Chartier | c3a22aa | 2018-01-19 18:58:34 -0800 | [diff] [blame] | 216 | location, |
| 217 | GetLocationChecksum(i), |
| Andreas Gampe | 98ea9d9 | 2018-10-19 14:06:15 -0700 | [diff] [blame] | 218 | /*oat_dex_file=*/ nullptr, |
| 219 | /*verify=*/ false, |
| 220 | /*verify_checksum=*/ false, |
| Mathieu Chartier | c3a22aa | 2018-01-19 18:58:34 -0800 | [diff] [blame] | 221 | error_msg)); |
| David Sehr | beca4fe | 2017-03-30 17:50:24 -0700 | [diff] [blame] | 222 | if (dex == nullptr) { |
| 223 | return false; |
| 224 | } |
| 225 | dex_files->push_back(std::move(dex)); |
| 226 | } |
| 227 | return true; |
| 228 | } |
| 229 | |
| David Brazdil | 35a3f6a | 2019-03-04 15:59:06 +0000 | [diff] [blame] | 230 | static bool CreateDirectories(const std::string& child_path, /* out */ std::string* error_msg) { |
| 231 | size_t last_slash_pos = child_path.find_last_of('/'); |
| 232 | CHECK_NE(last_slash_pos, std::string::npos) << "Invalid path: " << child_path; |
| 233 | std::string parent_path = child_path.substr(0, last_slash_pos); |
| 234 | if (OS::DirectoryExists(parent_path.c_str())) { |
| 235 | return true; |
| 236 | } else if (CreateDirectories(parent_path, error_msg)) { |
| 237 | if (mkdir(parent_path.c_str(), 0700) == 0) { |
| 238 | return true; |
| 239 | } |
| 240 | *error_msg = "Could not create directory " + parent_path; |
| 241 | return false; |
| 242 | } else { |
| 243 | return false; |
| 244 | } |
| 245 | } |
| 246 | |
| 247 | bool VdexFile::WriteToDisk(const std::string& path, |
| 248 | const std::vector<const DexFile*>& dex_files, |
| 249 | const verifier::VerifierDeps& verifier_deps, |
| David Brazdil | 35a3f6a | 2019-03-04 15:59:06 +0000 | [diff] [blame] | 250 | std::string* error_msg) { |
| 251 | std::vector<uint8_t> verifier_deps_data; |
| 252 | verifier_deps.Encode(dex_files, &verifier_deps_data); |
| Nicolas Geoffray | 0b94328 | 2021-04-16 09:16:00 +0000 | [diff] [blame] | 253 | uint32_t verifier_deps_size = verifier_deps_data.size(); |
| 254 | // Add padding so the type lookup tables are 4 byte aligned. |
| 255 | uint32_t verifier_deps_with_padding_size = RoundUp(verifier_deps_data.size(), 4); |
| 256 | DCHECK_GE(verifier_deps_with_padding_size, verifier_deps_data.size()); |
| 257 | verifier_deps_data.resize(verifier_deps_with_padding_size, 0); |
| 258 | |
| 259 | size_t type_lookup_table_size = 0u; |
| 260 | for (const DexFile* dex_file : dex_files) { |
| 261 | type_lookup_table_size += |
| 262 | sizeof(uint32_t) + TypeLookupTable::RawDataLength(dex_file->NumClassDefs()); |
| 263 | } |
| David Brazdil | 35a3f6a | 2019-03-04 15:59:06 +0000 | [diff] [blame] | 264 | |
| Nicolas Geoffray | a129d8a | 2021-03-18 22:23:04 +0000 | [diff] [blame] | 265 | VdexFile::VdexFileHeader vdex_header(/* has_dex_section= */ false); |
| 266 | VdexFile::VdexSectionHeader sections[static_cast<uint32_t>(VdexSection::kNumberOfSections)]; |
| David Brazdil | 35a3f6a | 2019-03-04 15:59:06 +0000 | [diff] [blame] | 267 | |
| Nicolas Geoffray | a129d8a | 2021-03-18 22:23:04 +0000 | [diff] [blame] | 268 | // Set checksum section. |
| 269 | sections[VdexSection::kChecksumSection].section_kind = VdexSection::kChecksumSection; |
| 270 | sections[VdexSection::kChecksumSection].section_offset = GetChecksumsOffset(); |
| 271 | sections[VdexSection::kChecksumSection].section_size = |
| 272 | sizeof(VdexFile::VdexChecksum) * dex_files.size(); |
| 273 | |
| 274 | // Set dex section. |
| 275 | sections[VdexSection::kDexFileSection].section_kind = VdexSection::kDexFileSection; |
| 276 | sections[VdexSection::kDexFileSection].section_offset = 0u; |
| 277 | sections[VdexSection::kDexFileSection].section_size = 0u; |
| 278 | |
| 279 | // Set VerifierDeps section. |
| 280 | sections[VdexSection::kVerifierDepsSection].section_kind = VdexSection::kVerifierDepsSection; |
| 281 | sections[VdexSection::kVerifierDepsSection].section_offset = |
| 282 | GetChecksumsOffset() + sections[kChecksumSection].section_size; |
| Nicolas Geoffray | 0b94328 | 2021-04-16 09:16:00 +0000 | [diff] [blame] | 283 | sections[VdexSection::kVerifierDepsSection].section_size = verifier_deps_size; |
| 284 | |
| 285 | // Set TypeLookupTable section. |
| 286 | sections[VdexSection::kTypeLookupTableSection].section_kind = |
| 287 | VdexSection::kTypeLookupTableSection; |
| 288 | sections[VdexSection::kTypeLookupTableSection].section_offset = |
| 289 | sections[VdexSection::kVerifierDepsSection].section_offset + verifier_deps_with_padding_size; |
| 290 | sections[VdexSection::kTypeLookupTableSection].section_size = type_lookup_table_size; |
| David Brazdil | 35a3f6a | 2019-03-04 15:59:06 +0000 | [diff] [blame] | 291 | |
| 292 | if (!CreateDirectories(path, error_msg)) { |
| 293 | return false; |
| 294 | } |
| 295 | |
| 296 | std::unique_ptr<File> out(OS::CreateEmptyFileWriteOnly(path.c_str())); |
| 297 | if (out == nullptr) { |
| 298 | *error_msg = "Could not open " + path + " for writing"; |
| 299 | return false; |
| 300 | } |
| 301 | |
| Nicolas Geoffray | a129d8a | 2021-03-18 22:23:04 +0000 | [diff] [blame] | 302 | // Write header. |
| 303 | if (!out->WriteFully(reinterpret_cast<const char*>(&vdex_header), sizeof(vdex_header))) { |
| David Brazdil | 35a3f6a | 2019-03-04 15:59:06 +0000 | [diff] [blame] | 304 | *error_msg = "Could not write vdex header to " + path; |
| 305 | out->Unlink(); |
| 306 | return false; |
| 307 | } |
| 308 | |
| Nicolas Geoffray | a129d8a | 2021-03-18 22:23:04 +0000 | [diff] [blame] | 309 | // Write section infos. |
| 310 | if (!out->WriteFully(reinterpret_cast<const char*>(§ions), sizeof(sections))) { |
| 311 | *error_msg = "Could not write vdex sections to " + path; |
| 312 | out->Unlink(); |
| 313 | return false; |
| 314 | } |
| 315 | |
| 316 | // Write checksum section. |
| David Brazdil | 35a3f6a | 2019-03-04 15:59:06 +0000 | [diff] [blame] | 317 | for (const DexFile* dex_file : dex_files) { |
| Nicolas Geoffray | 9bc364b | 2021-03-29 10:41:39 +0100 | [diff] [blame] | 318 | uint32_t checksum = dex_file->GetLocationChecksum(); |
| 319 | const uint32_t* checksum_ptr = &checksum; |
| David Brazdil | 35a3f6a | 2019-03-04 15:59:06 +0000 | [diff] [blame] | 320 | static_assert(sizeof(*checksum_ptr) == sizeof(VdexFile::VdexChecksum)); |
| 321 | if (!out->WriteFully(reinterpret_cast<const char*>(checksum_ptr), |
| 322 | sizeof(VdexFile::VdexChecksum))) { |
| 323 | *error_msg = "Could not write dex checksums to " + path; |
| 324 | out->Unlink(); |
| Nicolas Geoffray | a129d8a | 2021-03-18 22:23:04 +0000 | [diff] [blame] | 325 | return false; |
| David Brazdil | 35a3f6a | 2019-03-04 15:59:06 +0000 | [diff] [blame] | 326 | } |
| 327 | } |
| 328 | |
| 329 | if (!out->WriteFully(reinterpret_cast<const char*>(verifier_deps_data.data()), |
| Nicolas Geoffray | 0b94328 | 2021-04-16 09:16:00 +0000 | [diff] [blame] | 330 | verifier_deps_with_padding_size)) { |
| David Brazdil | 35a3f6a | 2019-03-04 15:59:06 +0000 | [diff] [blame] | 331 | *error_msg = "Could not write verifier deps to " + path; |
| 332 | out->Unlink(); |
| 333 | return false; |
| 334 | } |
| 335 | |
| Nicolas Geoffray | 0b94328 | 2021-04-16 09:16:00 +0000 | [diff] [blame] | 336 | size_t written_type_lookup_table_size = 0; |
| 337 | for (const DexFile* dex_file : dex_files) { |
| 338 | TypeLookupTable type_lookup_table = TypeLookupTable::Create(*dex_file); |
| 339 | uint32_t size = type_lookup_table.RawDataLength(); |
| 340 | DCHECK_ALIGNED(size, 4); |
| 341 | if (!out->WriteFully(reinterpret_cast<const char*>(&size), sizeof(uint32_t)) || |
| 342 | !out->WriteFully(reinterpret_cast<const char*>(type_lookup_table.RawData()), size)) { |
| 343 | *error_msg = "Could not write type lookup table " + path; |
| 344 | out->Unlink(); |
| 345 | return false; |
| 346 | } |
| 347 | written_type_lookup_table_size += sizeof(uint32_t) + size; |
| 348 | } |
| 349 | DCHECK_EQ(written_type_lookup_table_size, type_lookup_table_size); |
| 350 | |
| David Brazdil | 35a3f6a | 2019-03-04 15:59:06 +0000 | [diff] [blame] | 351 | if (out->FlushClose() != 0) { |
| 352 | *error_msg = "Could not flush and close " + path; |
| 353 | out->Unlink(); |
| 354 | return false; |
| 355 | } |
| 356 | |
| 357 | return true; |
| 358 | } |
| 359 | |
| David Brazdil | 7126c5b | 2019-03-05 00:02:51 +0000 | [diff] [blame] | 360 | bool VdexFile::MatchesDexFileChecksums(const std::vector<const DexFile::Header*>& dex_headers) |
| 361 | const { |
| Nicolas Geoffray | a129d8a | 2021-03-18 22:23:04 +0000 | [diff] [blame] | 362 | if (dex_headers.size() != GetNumberOfDexFiles()) { |
| David Brazdil | 7126c5b | 2019-03-05 00:02:51 +0000 | [diff] [blame] | 363 | LOG(WARNING) << "Mismatch of number of dex files in vdex (expected=" |
| Nicolas Geoffray | a129d8a | 2021-03-18 22:23:04 +0000 | [diff] [blame] | 364 | << GetNumberOfDexFiles() << ", actual=" << dex_headers.size() << ")"; |
| David Brazdil | 7126c5b | 2019-03-05 00:02:51 +0000 | [diff] [blame] | 365 | return false; |
| 366 | } |
| Nicolas Geoffray | a129d8a | 2021-03-18 22:23:04 +0000 | [diff] [blame] | 367 | const VdexChecksum* checksums = GetDexChecksumsArray(); |
| David Brazdil | 7126c5b | 2019-03-05 00:02:51 +0000 | [diff] [blame] | 368 | for (size_t i = 0; i < dex_headers.size(); ++i) { |
| 369 | if (checksums[i] != dex_headers[i]->checksum_) { |
| 370 | LOG(WARNING) << "Mismatch of dex file checksum in vdex (index=" << i << ")"; |
| 371 | return false; |
| 372 | } |
| 373 | } |
| 374 | return true; |
| 375 | } |
| 376 | |
| Nicolas Geoffray | 6df4511 | 2021-02-07 21:51:58 +0000 | [diff] [blame] | 377 | static ObjPtr<mirror::Class> FindClassAndClearException(ClassLinker* class_linker, |
| 378 | Thread* self, |
| 379 | const char* name, |
| 380 | Handle<mirror::ClassLoader> class_loader) |
| 381 | REQUIRES_SHARED(Locks::mutator_lock_) { |
| 382 | ObjPtr<mirror::Class> result = class_linker->FindClass(self, name, class_loader); |
| 383 | if (result == nullptr) { |
| 384 | DCHECK(self->IsExceptionPending()); |
| 385 | self->ClearException(); |
| 386 | } |
| 387 | return result; |
| 388 | } |
| 389 | |
| 390 | static const char* GetStringFromId(const DexFile& dex_file, |
| 391 | dex::StringIndex string_id, |
| 392 | uint32_t number_of_extra_strings, |
| 393 | const uint32_t* extra_strings_offsets, |
| 394 | const uint8_t* verifier_deps) { |
| 395 | uint32_t num_ids_in_dex = dex_file.NumStringIds(); |
| 396 | if (string_id.index_ < num_ids_in_dex) { |
| 397 | return dex_file.StringDataByIdx(string_id); |
| 398 | } else { |
| 399 | CHECK_LT(string_id.index_ - num_ids_in_dex, number_of_extra_strings); |
| 400 | uint32_t offset = extra_strings_offsets[string_id.index_ - num_ids_in_dex]; |
| 401 | return reinterpret_cast<const char*>(verifier_deps) + offset; |
| 402 | } |
| 403 | } |
| 404 | |
| 405 | // Returns an array of offsets where the assignability checks for each class |
| 406 | // definition are stored. |
| 407 | static const uint32_t* GetDexFileClassDefs(const uint8_t* verifier_deps, uint32_t index) { |
| 408 | uint32_t dex_file_offset = reinterpret_cast<const uint32_t*>(verifier_deps)[index]; |
| 409 | return reinterpret_cast<const uint32_t*>(verifier_deps + dex_file_offset); |
| 410 | } |
| 411 | |
| 412 | // Returns an array of offsets where extra strings are stored. |
| 413 | static const uint32_t* GetExtraStringsOffsets(const DexFile& dex_file, |
| 414 | const uint8_t* verifier_deps, |
| 415 | const uint32_t* dex_file_class_defs, |
| 416 | /*out*/ uint32_t* number_of_extra_strings) { |
| 417 | // The information for strings is right after dex_file_class_defs, 4-byte |
| 418 | // aligned |
| 419 | uint32_t end_of_assignability_types = dex_file_class_defs[dex_file.NumClassDefs()]; |
| 420 | const uint8_t* strings_data_start = |
| 421 | AlignUp(verifier_deps + end_of_assignability_types, sizeof(uint32_t)); |
| 422 | // First entry is the number of extra strings for this dex file. |
| 423 | *number_of_extra_strings = *reinterpret_cast<const uint32_t*>(strings_data_start); |
| 424 | // Then an array of offsets in `verifier_deps` for the extra strings. |
| 425 | return reinterpret_cast<const uint32_t*>(strings_data_start + sizeof(uint32_t)); |
| 426 | } |
| 427 | |
| 428 | ClassStatus VdexFile::ComputeClassStatus(Thread* self, Handle<mirror::Class> cls) const { |
| 429 | const DexFile& dex_file = cls->GetDexFile(); |
| 430 | uint16_t class_def_index = cls->GetDexClassDefIndex(); |
| 431 | |
| 432 | // Find which dex file index from within the vdex file. |
| 433 | uint32_t index = 0; |
| Nicolas Geoffray | a129d8a | 2021-03-18 22:23:04 +0000 | [diff] [blame] | 434 | for (; index < GetNumberOfDexFiles(); ++index) { |
| Nicolas Geoffray | 6df4511 | 2021-02-07 21:51:58 +0000 | [diff] [blame] | 435 | if (dex_file.GetLocationChecksum() == GetLocationChecksum(index)) { |
| 436 | break; |
| 437 | } |
| 438 | } |
| Nicolas Geoffray | 6df4511 | 2021-02-07 21:51:58 +0000 | [diff] [blame] | 439 | |
| Nicolas Geoffray | a129d8a | 2021-03-18 22:23:04 +0000 | [diff] [blame] | 440 | DCHECK_NE(index, GetNumberOfDexFiles()); |
| 441 | |
| 442 | const uint8_t* verifier_deps = GetVerifierDepsData().data(); |
| Nicolas Geoffray | 6df4511 | 2021-02-07 21:51:58 +0000 | [diff] [blame] | 443 | const uint32_t* dex_file_class_defs = GetDexFileClassDefs(verifier_deps, index); |
| 444 | |
| 445 | // Fetch type checks offsets. |
| 446 | uint32_t class_def_offset = dex_file_class_defs[class_def_index]; |
| 447 | if (class_def_offset == verifier::VerifierDeps::kNotVerifiedMarker) { |
| 448 | // Return a status that needs re-verification. |
| 449 | return ClassStatus::kResolved; |
| 450 | } |
| 451 | // End offset for this class's type checks. We know there is one and the loop |
| 452 | // will terminate. |
| 453 | uint32_t end_offset = verifier::VerifierDeps::kNotVerifiedMarker; |
| 454 | for (uint32_t i = class_def_index + 1; i < dex_file.NumClassDefs() + 1; ++i) { |
| 455 | end_offset = dex_file_class_defs[i]; |
| 456 | if (end_offset != verifier::VerifierDeps::kNotVerifiedMarker) { |
| 457 | break; |
| 458 | } |
| 459 | } |
| 460 | DCHECK_NE(end_offset, verifier::VerifierDeps::kNotVerifiedMarker); |
| 461 | |
| 462 | uint32_t number_of_extra_strings = 0; |
| 463 | // Offset where extra strings are stored. |
| 464 | const uint32_t* extra_strings_offsets = GetExtraStringsOffsets(dex_file, |
| 465 | verifier_deps, |
| 466 | dex_file_class_defs, |
| 467 | &number_of_extra_strings); |
| 468 | |
| 469 | // Loop over and perform each assignability check. |
| 470 | StackHandleScope<3> hs(self); |
| 471 | ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); |
| 472 | Handle<mirror::ClassLoader> class_loader(hs.NewHandle(cls->GetClassLoader())); |
| 473 | MutableHandle<mirror::Class> source(hs.NewHandle<mirror::Class>(nullptr)); |
| 474 | MutableHandle<mirror::Class> destination(hs.NewHandle<mirror::Class>(nullptr)); |
| 475 | |
| 476 | const uint8_t* cursor = verifier_deps + class_def_offset; |
| 477 | const uint8_t* end = verifier_deps + end_offset; |
| 478 | while (cursor < end) { |
| 479 | uint32_t destination_index; |
| 480 | uint32_t source_index; |
| 481 | if (UNLIKELY(!DecodeUnsignedLeb128Checked(&cursor, end, &destination_index) || |
| 482 | !DecodeUnsignedLeb128Checked(&cursor, end, &source_index))) { |
| 483 | // Error parsing the data, just return that we are not verified. |
| 484 | return ClassStatus::kResolved; |
| 485 | } |
| 486 | const char* destination_desc = GetStringFromId(dex_file, |
| 487 | dex::StringIndex(destination_index), |
| 488 | number_of_extra_strings, |
| 489 | extra_strings_offsets, |
| 490 | verifier_deps); |
| 491 | destination.Assign( |
| 492 | FindClassAndClearException(class_linker, self, destination_desc, class_loader)); |
| 493 | |
| 494 | const char* source_desc = GetStringFromId(dex_file, |
| 495 | dex::StringIndex(source_index), |
| 496 | number_of_extra_strings, |
| 497 | extra_strings_offsets, |
| 498 | verifier_deps); |
| 499 | source.Assign(FindClassAndClearException(class_linker, self, source_desc, class_loader)); |
| 500 | |
| 501 | if (destination == nullptr || source == nullptr) { |
| 502 | // The interpreter / compiler can handle a missing class. |
| 503 | continue; |
| 504 | } |
| 505 | |
| 506 | DCHECK(destination->IsResolved() && source->IsResolved()); |
| 507 | if (!destination->IsAssignableFrom(source.Get())) { |
| 508 | // An implicit assignability check is failing in the code, return that the |
| 509 | // class is not verified. |
| 510 | return ClassStatus::kResolved; |
| 511 | } |
| 512 | } |
| 513 | |
| 514 | return ClassStatus::kVerifiedNeedsAccessChecks; |
| 515 | } |
| 516 | |
| David Brazdil | 7b49e6c | 2016-09-01 11:06:18 +0100 | [diff] [blame] | 517 | } // namespace art |