• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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 "oat_writer.h"
18 
19 #include <algorithm>
20 #include <unistd.h>
21 #include <zlib.h>
22 
23 #include "arch/arm64/instruction_set_features_arm64.h"
24 #include "art_method-inl.h"
25 #include "base/allocator.h"
26 #include "base/bit_vector-inl.h"
27 #include "base/enums.h"
28 #include "base/file_magic.h"
29 #include "base/file_utils.h"
30 #include "base/indenter.h"
31 #include "base/logging.h"  // For VLOG
32 #include "base/os.h"
33 #include "base/safe_map.h"
34 #include "base/stl_util.h"
35 #include "base/unix_file/fd_file.h"
36 #include "base/zip_archive.h"
37 #include "class_linker.h"
38 #include "class_table-inl.h"
39 #include "compiled_method-inl.h"
40 #include "debug/method_debug_info.h"
41 #include "dex/art_dex_file_loader.h"
42 #include "dex/class_accessor-inl.h"
43 #include "dex/dex_file-inl.h"
44 #include "dex/dex_file_loader.h"
45 #include "dex/dex_file_types.h"
46 #include "dex/standard_dex_file.h"
47 #include "dex/type_lookup_table.h"
48 #include "dex/verification_results.h"
49 #include "dex_container.h"
50 #include "dexlayout.h"
51 #include "driver/compiler_driver-inl.h"
52 #include "driver/compiler_options.h"
53 #include "gc/space/image_space.h"
54 #include "gc/space/space.h"
55 #include "handle_scope-inl.h"
56 #include "image_writer.h"
57 #include "linker/index_bss_mapping_encoder.h"
58 #include "linker/linker_patch.h"
59 #include "linker/multi_oat_relative_patcher.h"
60 #include "mirror/array.h"
61 #include "mirror/class_loader.h"
62 #include "mirror/dex_cache-inl.h"
63 #include "mirror/object-inl.h"
64 #include "oat_quick_method_header.h"
65 #include "profile/profile_compilation_info.h"
66 #include "quicken_info.h"
67 #include "scoped_thread_state_change-inl.h"
68 #include "stack_map.h"
69 #include "stream/buffered_output_stream.h"
70 #include "stream/file_output_stream.h"
71 #include "stream/output_stream.h"
72 #include "utils/dex_cache_arrays_layout-inl.h"
73 #include "vdex_file.h"
74 #include "verifier/verifier_deps.h"
75 
76 namespace art {
77 namespace linker {
78 
79 namespace {  // anonymous namespace
80 
81 // If we write dex layout info in the oat file.
82 static constexpr bool kWriteDexLayoutInfo = true;
83 
84 // Force the OAT method layout to be sorted-by-name instead of
85 // the default (class_def_idx, method_idx).
86 //
87 // Otherwise if profiles are used, that will act as
88 // the primary sort order.
89 //
90 // A bit easier to use for development since oatdump can easily
91 // show that things are being re-ordered when two methods aren't adjacent.
92 static constexpr bool kOatWriterForceOatCodeLayout = false;
93 
94 static constexpr bool kOatWriterDebugOatCodeLayout = false;
95 
96 using UnalignedDexFileHeader __attribute__((__aligned__(1))) = DexFile::Header;
97 
AsUnalignedDexFileHeader(const uint8_t * raw_data)98 const UnalignedDexFileHeader* AsUnalignedDexFileHeader(const uint8_t* raw_data) {
99   return reinterpret_cast<const UnalignedDexFileHeader*>(raw_data);
100 }
101 
CodeAlignmentSize(uint32_t header_offset,const CompiledMethod & compiled_method)102 inline uint32_t CodeAlignmentSize(uint32_t header_offset, const CompiledMethod& compiled_method) {
103   // We want to align the code rather than the preheader.
104   uint32_t unaligned_code_offset = header_offset + sizeof(OatQuickMethodHeader);
105   uint32_t aligned_code_offset =  compiled_method.AlignCode(unaligned_code_offset);
106   return aligned_code_offset - unaligned_code_offset;
107 }
108 
109 }  // anonymous namespace
110 
111 class OatWriter::ChecksumUpdatingOutputStream : public OutputStream {
112  public:
ChecksumUpdatingOutputStream(OutputStream * out,OatWriter * writer)113   ChecksumUpdatingOutputStream(OutputStream* out, OatWriter* writer)
114       : OutputStream(out->GetLocation()), out_(out), writer_(writer) { }
115 
WriteFully(const void * buffer,size_t byte_count)116   bool WriteFully(const void* buffer, size_t byte_count) override {
117     if (buffer != nullptr) {
118       const uint8_t* bytes = reinterpret_cast<const uint8_t*>(buffer);
119       uint32_t old_checksum = writer_->oat_checksum_;
120       writer_->oat_checksum_ = adler32(old_checksum, bytes, byte_count);
121     } else {
122       DCHECK_EQ(0U, byte_count);
123     }
124     return out_->WriteFully(buffer, byte_count);
125   }
126 
Seek(off_t offset,Whence whence)127   off_t Seek(off_t offset, Whence whence) override {
128     return out_->Seek(offset, whence);
129   }
130 
Flush()131   bool Flush() override {
132     return out_->Flush();
133   }
134 
135  private:
136   OutputStream* const out_;
137   OatWriter* const writer_;
138 };
139 
140 // Defines the location of the raw dex file to write.
141 class OatWriter::DexFileSource {
142  public:
143   enum Type {
144     kNone,
145     kZipEntry,
146     kRawFile,
147     kRawData,
148   };
149 
DexFileSource(ZipEntry * zip_entry)150   explicit DexFileSource(ZipEntry* zip_entry)
151       : type_(kZipEntry), source_(zip_entry) {
152     DCHECK(source_ != nullptr);
153   }
154 
DexFileSource(File * raw_file)155   explicit DexFileSource(File* raw_file)
156       : type_(kRawFile), source_(raw_file) {
157     DCHECK(source_ != nullptr);
158   }
159 
DexFileSource(const uint8_t * dex_file)160   explicit DexFileSource(const uint8_t* dex_file)
161       : type_(kRawData), source_(dex_file) {
162     DCHECK(source_ != nullptr);
163   }
164 
GetType() const165   Type GetType() const { return type_; }
IsZipEntry() const166   bool IsZipEntry() const { return type_ == kZipEntry; }
IsRawFile() const167   bool IsRawFile() const { return type_ == kRawFile; }
IsRawData() const168   bool IsRawData() const { return type_ == kRawData; }
169 
GetZipEntry() const170   ZipEntry* GetZipEntry() const {
171     DCHECK(IsZipEntry());
172     DCHECK(source_ != nullptr);
173     return static_cast<ZipEntry*>(const_cast<void*>(source_));
174   }
175 
GetRawFile() const176   File* GetRawFile() const {
177     DCHECK(IsRawFile());
178     DCHECK(source_ != nullptr);
179     return static_cast<File*>(const_cast<void*>(source_));
180   }
181 
GetRawData() const182   const uint8_t* GetRawData() const {
183     DCHECK(IsRawData());
184     DCHECK(source_ != nullptr);
185     return static_cast<const uint8_t*>(source_);
186   }
187 
Clear()188   void Clear() {
189     type_ = kNone;
190     source_ = nullptr;
191   }
192 
193  private:
194   Type type_;
195   const void* source_;
196 };
197 
198 // OatClassHeader is the header only part of the oat class that is required even when compilation
199 // is not enabled.
200 class OatWriter::OatClassHeader {
201  public:
OatClassHeader(uint32_t offset,uint32_t num_non_null_compiled_methods,uint32_t num_methods,ClassStatus status)202   OatClassHeader(uint32_t offset,
203                  uint32_t num_non_null_compiled_methods,
204                  uint32_t num_methods,
205                  ClassStatus status)
206       : status_(enum_cast<uint16_t>(status)),
207         offset_(offset) {
208     // We just arbitrarily say that 0 methods means kOatClassNoneCompiled and that we won't use
209     // kOatClassAllCompiled unless there is at least one compiled method. This means in an
210     // interpreter only system, we can assert that all classes are kOatClassNoneCompiled.
211     if (num_non_null_compiled_methods == 0) {
212       type_ = kOatClassNoneCompiled;
213     } else if (num_non_null_compiled_methods == num_methods) {
214       type_ = kOatClassAllCompiled;
215     } else {
216       type_ = kOatClassSomeCompiled;
217     }
218   }
219 
220   bool Write(OatWriter* oat_writer, OutputStream* out, const size_t file_offset) const;
221 
SizeOf()222   static size_t SizeOf() {
223     return sizeof(status_) + sizeof(type_);
224   }
225 
226   // Data to write.
227   static_assert(enum_cast<>(ClassStatus::kLast) < (1 << 16), "class status won't fit in 16bits");
228   uint16_t status_;
229 
230   static_assert(OatClassType::kOatClassMax < (1 << 16), "oat_class type won't fit in 16bits");
231   uint16_t type_;
232 
233   // Offset of start of OatClass from beginning of OatHeader. It is
234   // used to validate file position when writing.
235   uint32_t offset_;
236 };
237 
238 // The actual oat class body contains the information about compiled methods. It is only required
239 // for compiler filters that have any compilation.
240 class OatWriter::OatClass {
241  public:
242   OatClass(const dchecked_vector<CompiledMethod*>& compiled_methods,
243            uint32_t compiled_methods_with_code,
244            uint16_t oat_class_type);
245   OatClass(OatClass&& src) = default;
246   size_t SizeOf() const;
247   bool Write(OatWriter* oat_writer, OutputStream* out) const;
248 
GetCompiledMethod(size_t class_def_method_index) const249   CompiledMethod* GetCompiledMethod(size_t class_def_method_index) const {
250     return compiled_methods_[class_def_method_index];
251   }
252 
253   // CompiledMethods for each class_def_method_index, or null if no method is available.
254   dchecked_vector<CompiledMethod*> compiled_methods_;
255 
256   // Offset from OatClass::offset_ to the OatMethodOffsets for the
257   // class_def_method_index. If 0, it means the corresponding
258   // CompiledMethod entry in OatClass::compiled_methods_ should be
259   // null and that the OatClass::type_ should be kOatClassBitmap.
260   dchecked_vector<uint32_t> oat_method_offsets_offsets_from_oat_class_;
261 
262   // Data to write.
263   uint32_t method_bitmap_size_;
264 
265   // bit vector indexed by ClassDef method index. When
266   // OatClassType::type_ is kOatClassBitmap, a set bit indicates the
267   // method has an OatMethodOffsets in methods_offsets_, otherwise
268   // the entry was ommited to save space. If OatClassType::type_ is
269   // not is kOatClassBitmap, the bitmap will be null.
270   std::unique_ptr<BitVector> method_bitmap_;
271 
272   // OatMethodOffsets and OatMethodHeaders for each CompiledMethod
273   // present in the OatClass. Note that some may be missing if
274   // OatClass::compiled_methods_ contains null values (and
275   // oat_method_offsets_offsets_from_oat_class_ should contain 0
276   // values in this case).
277   dchecked_vector<OatMethodOffsets> method_offsets_;
278   dchecked_vector<OatQuickMethodHeader> method_headers_;
279 
280  private:
GetMethodOffsetsRawSize() const281   size_t GetMethodOffsetsRawSize() const {
282     return method_offsets_.size() * sizeof(method_offsets_[0]);
283   }
284 
285   DISALLOW_COPY_AND_ASSIGN(OatClass);
286 };
287 
288 class OatWriter::OatDexFile {
289  public:
290   OatDexFile(const char* dex_file_location,
291              DexFileSource source,
292              CreateTypeLookupTable create_type_lookup_table,
293              uint32_t dex_file_location_checksun,
294              size_t dex_file_size);
295   OatDexFile(OatDexFile&& src) = default;
296 
GetLocation() const297   const char* GetLocation() const {
298     return dex_file_location_data_;
299   }
300 
301   size_t SizeOf() const;
302   bool Write(OatWriter* oat_writer, OutputStream* out) const;
303   bool WriteClassOffsets(OatWriter* oat_writer, OutputStream* out);
304 
GetClassOffsetsRawSize() const305   size_t GetClassOffsetsRawSize() const {
306     return class_offsets_.size() * sizeof(class_offsets_[0]);
307   }
308 
309   // The source of the dex file.
310   DexFileSource source_;
311 
312   // Whether to create the type lookup table.
313   CreateTypeLookupTable create_type_lookup_table_;
314 
315   // Dex file size. Passed in the constructor, but could be
316   // overwritten by LayoutAndWriteDexFile.
317   size_t dex_file_size_;
318 
319   // Offset of start of OatDexFile from beginning of OatHeader. It is
320   // used to validate file position when writing.
321   size_t offset_;
322 
323   ///// Start of data to write to vdex/oat file.
324 
325   const uint32_t dex_file_location_size_;
326   const char* const dex_file_location_data_;
327 
328   // The checksum of the dex file.
329   const uint32_t dex_file_location_checksum_;
330 
331   // Offset of the dex file in the vdex file. Set when writing dex files in
332   // SeekToDexFile.
333   uint32_t dex_file_offset_;
334 
335   // The lookup table offset in the oat file. Set in WriteTypeLookupTables.
336   uint32_t lookup_table_offset_;
337 
338   // Class and BSS offsets set in PrepareLayout.
339   uint32_t class_offsets_offset_;
340   uint32_t method_bss_mapping_offset_;
341   uint32_t type_bss_mapping_offset_;
342   uint32_t string_bss_mapping_offset_;
343 
344   // Offset of dex sections that will have different runtime madvise states.
345   // Set in WriteDexLayoutSections.
346   uint32_t dex_sections_layout_offset_;
347 
348   // Data to write to a separate section. We set the length
349   // of the vector in OpenDexFiles.
350   dchecked_vector<uint32_t> class_offsets_;
351 
352   // Dex section layout info to serialize.
353   DexLayoutSections dex_sections_layout_;
354 
355   ///// End of data to write to vdex/oat file.
356  private:
357   DISALLOW_COPY_AND_ASSIGN(OatDexFile);
358 };
359 
360 #define DCHECK_OFFSET() \
361   DCHECK_EQ(static_cast<off_t>(file_offset + relative_offset), out->Seek(0, kSeekCurrent)) \
362     << "file_offset=" << file_offset << " relative_offset=" << relative_offset
363 
364 #define DCHECK_OFFSET_() \
365   DCHECK_EQ(static_cast<off_t>(file_offset + offset_), out->Seek(0, kSeekCurrent)) \
366     << "file_offset=" << file_offset << " offset_=" << offset_
367 
OatWriter(const CompilerOptions & compiler_options,TimingLogger * timings,ProfileCompilationInfo * info,CompactDexLevel compact_dex_level)368 OatWriter::OatWriter(const CompilerOptions& compiler_options,
369                      TimingLogger* timings,
370                      ProfileCompilationInfo* info,
371                      CompactDexLevel compact_dex_level)
372   : write_state_(WriteState::kAddingDexFileSources),
373     timings_(timings),
374     raw_dex_files_(),
375     zip_archives_(),
376     zipped_dex_files_(),
377     zipped_dex_file_locations_(),
378     compiler_driver_(nullptr),
379     compiler_options_(compiler_options),
380     image_writer_(nullptr),
381     extract_dex_files_into_vdex_(true),
382     dex_files_(nullptr),
383     primary_oat_file_(false),
384     vdex_size_(0u),
385     vdex_dex_files_offset_(0u),
386     vdex_dex_shared_data_offset_(0u),
387     vdex_verifier_deps_offset_(0u),
388     vdex_quickening_info_offset_(0u),
389     oat_checksum_(adler32(0L, Z_NULL, 0)),
390     code_size_(0u),
391     oat_size_(0u),
392     data_bimg_rel_ro_start_(0u),
393     data_bimg_rel_ro_size_(0u),
394     bss_start_(0u),
395     bss_size_(0u),
396     bss_methods_offset_(0u),
397     bss_roots_offset_(0u),
398     data_bimg_rel_ro_entries_(),
399     bss_method_entry_references_(),
400     bss_method_entries_(),
401     bss_type_entries_(),
402     bss_string_entries_(),
403     oat_data_offset_(0u),
404     oat_header_(nullptr),
405     size_vdex_header_(0),
406     size_vdex_checksums_(0),
407     size_dex_file_alignment_(0),
408     size_executable_offset_alignment_(0),
409     size_oat_header_(0),
410     size_oat_header_key_value_store_(0),
411     size_dex_file_(0),
412     size_verifier_deps_(0),
413     size_verifier_deps_alignment_(0),
414     size_quickening_info_(0),
415     size_quickening_info_alignment_(0),
416     size_interpreter_to_interpreter_bridge_(0),
417     size_interpreter_to_compiled_code_bridge_(0),
418     size_jni_dlsym_lookup_(0),
419     size_quick_generic_jni_trampoline_(0),
420     size_quick_imt_conflict_trampoline_(0),
421     size_quick_resolution_trampoline_(0),
422     size_quick_to_interpreter_bridge_(0),
423     size_trampoline_alignment_(0),
424     size_method_header_(0),
425     size_code_(0),
426     size_code_alignment_(0),
427     size_data_bimg_rel_ro_(0),
428     size_data_bimg_rel_ro_alignment_(0),
429     size_relative_call_thunks_(0),
430     size_misc_thunks_(0),
431     size_vmap_table_(0),
432     size_method_info_(0),
433     size_oat_dex_file_location_size_(0),
434     size_oat_dex_file_location_data_(0),
435     size_oat_dex_file_location_checksum_(0),
436     size_oat_dex_file_offset_(0),
437     size_oat_dex_file_class_offsets_offset_(0),
438     size_oat_dex_file_lookup_table_offset_(0),
439     size_oat_dex_file_dex_layout_sections_offset_(0),
440     size_oat_dex_file_dex_layout_sections_(0),
441     size_oat_dex_file_dex_layout_sections_alignment_(0),
442     size_oat_dex_file_method_bss_mapping_offset_(0),
443     size_oat_dex_file_type_bss_mapping_offset_(0),
444     size_oat_dex_file_string_bss_mapping_offset_(0),
445     size_oat_lookup_table_alignment_(0),
446     size_oat_lookup_table_(0),
447     size_oat_class_offsets_alignment_(0),
448     size_oat_class_offsets_(0),
449     size_oat_class_type_(0),
450     size_oat_class_status_(0),
451     size_oat_class_method_bitmaps_(0),
452     size_oat_class_method_offsets_(0),
453     size_method_bss_mappings_(0u),
454     size_type_bss_mappings_(0u),
455     size_string_bss_mappings_(0u),
456     relative_patcher_(nullptr),
457     profile_compilation_info_(info),
458     compact_dex_level_(compact_dex_level) {
459   // If we have a profile, always use at least the default compact dex level. The reason behind
460   // this is that CompactDex conversion is not more expensive than normal dexlayout.
461   if (info != nullptr && compact_dex_level_ == CompactDexLevel::kCompactDexLevelNone) {
462     compact_dex_level_ = kDefaultCompactDexLevel;
463   }
464 }
465 
ValidateDexFileHeader(const uint8_t * raw_header,const char * location)466 static bool ValidateDexFileHeader(const uint8_t* raw_header, const char* location) {
467   const bool valid_standard_dex_magic = DexFileLoader::IsMagicValid(raw_header);
468   if (!valid_standard_dex_magic) {
469     LOG(ERROR) << "Invalid magic number in dex file header. " << " File: " << location;
470     return false;
471   }
472   if (!DexFileLoader::IsVersionAndMagicValid(raw_header)) {
473     LOG(ERROR) << "Invalid version number in dex file header. " << " File: " << location;
474     return false;
475   }
476   const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_header);
477   if (header->file_size_ < sizeof(DexFile::Header)) {
478     LOG(ERROR) << "Dex file header specifies file size insufficient to contain the header."
479                << " File: " << location;
480     return false;
481   }
482   return true;
483 }
484 
GetDexFileHeader(File * file,uint8_t * raw_header,const char * location)485 static const UnalignedDexFileHeader* GetDexFileHeader(File* file,
486                                                       uint8_t* raw_header,
487                                                       const char* location) {
488   // Read the dex file header and perform minimal verification.
489   if (!file->ReadFully(raw_header, sizeof(DexFile::Header))) {
490     PLOG(ERROR) << "Failed to read dex file header. Actual: "
491                 << " File: " << location << " Output: " << file->GetPath();
492     return nullptr;
493   }
494   if (!ValidateDexFileHeader(raw_header, location)) {
495     return nullptr;
496   }
497 
498   return AsUnalignedDexFileHeader(raw_header);
499 }
500 
AddDexFileSource(const char * filename,const char * location,CreateTypeLookupTable create_type_lookup_table)501 bool OatWriter::AddDexFileSource(const char* filename,
502                                  const char* location,
503                                  CreateTypeLookupTable create_type_lookup_table) {
504   DCHECK(write_state_ == WriteState::kAddingDexFileSources);
505   uint32_t magic;
506   std::string error_msg;
507   File fd = OpenAndReadMagic(filename, &magic, &error_msg);
508   if (fd.Fd() == -1) {
509     PLOG(ERROR) << "Failed to read magic number from dex file: '" << filename << "'";
510     return false;
511   } else if (DexFileLoader::IsMagicValid(magic)) {
512     uint8_t raw_header[sizeof(DexFile::Header)];
513     const UnalignedDexFileHeader* header = GetDexFileHeader(&fd, raw_header, location);
514     if (header == nullptr) {
515       return false;
516     }
517     // The file is open for reading, not writing, so it's OK to let the File destructor
518     // close it without checking for explicit Close(), so pass checkUsage = false.
519     raw_dex_files_.emplace_back(new File(fd.Release(), location, /* checkUsage */ false));
520     oat_dex_files_.emplace_back(/* OatDexFile */
521         location,
522         DexFileSource(raw_dex_files_.back().get()),
523         create_type_lookup_table,
524         header->checksum_,
525         header->file_size_);
526   } else if (IsZipMagic(magic)) {
527     if (!AddZippedDexFilesSource(std::move(fd), location, create_type_lookup_table)) {
528       return false;
529     }
530   } else {
531     LOG(ERROR) << "Expected valid zip or dex file: '" << filename << "'";
532     return false;
533   }
534   return true;
535 }
536 
537 // Add dex file source(s) from a zip file specified by a file handle.
AddZippedDexFilesSource(File && zip_fd,const char * location,CreateTypeLookupTable create_type_lookup_table)538 bool OatWriter::AddZippedDexFilesSource(File&& zip_fd,
539                                         const char* location,
540                                         CreateTypeLookupTable create_type_lookup_table) {
541   DCHECK(write_state_ == WriteState::kAddingDexFileSources);
542   std::string error_msg;
543   zip_archives_.emplace_back(ZipArchive::OpenFromFd(zip_fd.Release(), location, &error_msg));
544   ZipArchive* zip_archive = zip_archives_.back().get();
545   if (zip_archive == nullptr) {
546     LOG(ERROR) << "Failed to open zip from file descriptor for '" << location << "': "
547         << error_msg;
548     return false;
549   }
550   for (size_t i = 0; ; ++i) {
551     std::string entry_name = DexFileLoader::GetMultiDexClassesDexName(i);
552     std::unique_ptr<ZipEntry> entry(zip_archive->Find(entry_name.c_str(), &error_msg));
553     if (entry == nullptr) {
554       break;
555     }
556     zipped_dex_files_.push_back(std::move(entry));
557     zipped_dex_file_locations_.push_back(DexFileLoader::GetMultiDexLocation(i, location));
558     const char* full_location = zipped_dex_file_locations_.back().c_str();
559     // We override the checksum from header with the CRC from ZIP entry.
560     oat_dex_files_.emplace_back(/* OatDexFile */
561         full_location,
562         DexFileSource(zipped_dex_files_.back().get()),
563         create_type_lookup_table,
564         zipped_dex_files_.back()->GetCrc32(),
565         zipped_dex_files_.back()->GetUncompressedLength());
566   }
567   if (zipped_dex_file_locations_.empty()) {
568     LOG(ERROR) << "No dex files in zip file '" << location << "': " << error_msg;
569     return false;
570   }
571   return true;
572 }
573 
574 // Add dex file source(s) from a vdex file specified by a file handle.
AddVdexDexFilesSource(const VdexFile & vdex_file,const char * location,CreateTypeLookupTable create_type_lookup_table)575 bool OatWriter::AddVdexDexFilesSource(const VdexFile& vdex_file,
576                                       const char* location,
577                                       CreateTypeLookupTable create_type_lookup_table) {
578   DCHECK(write_state_ == WriteState::kAddingDexFileSources);
579   DCHECK(vdex_file.HasDexSection());
580   const uint8_t* current_dex_data = nullptr;
581   for (size_t i = 0; i < vdex_file.GetVerifierDepsHeader().GetNumberOfDexFiles(); ++i) {
582     current_dex_data = vdex_file.GetNextDexFileData(current_dex_data);
583     if (current_dex_data == nullptr) {
584       LOG(ERROR) << "Unexpected number of dex files in vdex " << location;
585       return false;
586     }
587 
588     if (!DexFileLoader::IsMagicValid(current_dex_data)) {
589       LOG(ERROR) << "Invalid magic in vdex file created from " << location;
590       return false;
591     }
592     // We used `zipped_dex_file_locations_` to keep the strings in memory.
593     zipped_dex_file_locations_.push_back(DexFileLoader::GetMultiDexLocation(i, location));
594     const char* full_location = zipped_dex_file_locations_.back().c_str();
595     const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(current_dex_data);
596     oat_dex_files_.emplace_back(/* OatDexFile */
597         full_location,
598         DexFileSource(current_dex_data),
599         create_type_lookup_table,
600         vdex_file.GetLocationChecksum(i),
601         header->file_size_);
602   }
603 
604   if (vdex_file.GetNextDexFileData(current_dex_data) != nullptr) {
605     LOG(ERROR) << "Unexpected number of dex files in vdex " << location;
606     return false;
607   }
608 
609   if (oat_dex_files_.empty()) {
610     LOG(ERROR) << "No dex files in vdex file created from " << location;
611     return false;
612   }
613   return true;
614 }
615 
616 // Add dex file source from raw memory.
AddRawDexFileSource(const ArrayRef<const uint8_t> & data,const char * location,uint32_t location_checksum,CreateTypeLookupTable create_type_lookup_table)617 bool OatWriter::AddRawDexFileSource(const ArrayRef<const uint8_t>& data,
618                                     const char* location,
619                                     uint32_t location_checksum,
620                                     CreateTypeLookupTable create_type_lookup_table) {
621   DCHECK(write_state_ == WriteState::kAddingDexFileSources);
622   if (data.size() < sizeof(DexFile::Header)) {
623     LOG(ERROR) << "Provided data is shorter than dex file header. size: "
624                << data.size() << " File: " << location;
625     return false;
626   }
627   if (!ValidateDexFileHeader(data.data(), location)) {
628     return false;
629   }
630   const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(data.data());
631   if (data.size() < header->file_size_) {
632     LOG(ERROR) << "Truncated dex file data. Data size: " << data.size()
633                << " file size from header: " << header->file_size_ << " File: " << location;
634     return false;
635   }
636 
637   oat_dex_files_.emplace_back(/* OatDexFile */
638       location,
639       DexFileSource(data.data()),
640       create_type_lookup_table,
641       location_checksum,
642       header->file_size_);
643   return true;
644 }
645 
GetSourceLocations() const646 dchecked_vector<std::string> OatWriter::GetSourceLocations() const {
647   dchecked_vector<std::string> locations;
648   locations.reserve(oat_dex_files_.size());
649   for (const OatDexFile& oat_dex_file : oat_dex_files_) {
650     locations.push_back(oat_dex_file.GetLocation());
651   }
652   return locations;
653 }
654 
MayHaveCompiledMethods() const655 bool OatWriter::MayHaveCompiledMethods() const {
656   return GetCompilerOptions().IsAnyCompilationEnabled();
657 }
658 
WriteAndOpenDexFiles(File * vdex_file,OutputStream * oat_rodata,SafeMap<std::string,std::string> * key_value_store,bool verify,bool update_input_vdex,CopyOption copy_dex_files,std::vector<MemMap> * opened_dex_files_map,std::vector<std::unique_ptr<const DexFile>> * opened_dex_files)659 bool OatWriter::WriteAndOpenDexFiles(
660     File* vdex_file,
661     OutputStream* oat_rodata,
662     SafeMap<std::string, std::string>* key_value_store,
663     bool verify,
664     bool update_input_vdex,
665     CopyOption copy_dex_files,
666     /*out*/ std::vector<MemMap>* opened_dex_files_map,
667     /*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files) {
668   CHECK(write_state_ == WriteState::kAddingDexFileSources);
669 
670   // Record the ELF rodata section offset, i.e. the beginning of the OAT data.
671   if (!RecordOatDataOffset(oat_rodata)) {
672      return false;
673   }
674 
675   // Record whether this is the primary oat file.
676   primary_oat_file_ = (key_value_store != nullptr);
677 
678   // Initialize VDEX and OAT headers.
679 
680   // Reserve space for Vdex header and checksums.
681   vdex_size_ = sizeof(VdexFile::VerifierDepsHeader) +
682       oat_dex_files_.size() * sizeof(VdexFile::VdexChecksum);
683   oat_size_ = InitOatHeader(dchecked_integral_cast<uint32_t>(oat_dex_files_.size()),
684                             key_value_store);
685 
686   ChecksumUpdatingOutputStream checksum_updating_rodata(oat_rodata, this);
687 
688   std::unique_ptr<BufferedOutputStream> vdex_out =
689       std::make_unique<BufferedOutputStream>(std::make_unique<FileOutputStream>(vdex_file));
690   // Write DEX files into VDEX, mmap and open them.
691   std::vector<MemMap> dex_files_map;
692   std::vector<std::unique_ptr<const DexFile>> dex_files;
693   if (!WriteDexFiles(vdex_out.get(), vdex_file, update_input_vdex, copy_dex_files) ||
694       !OpenDexFiles(vdex_file, verify, &dex_files_map, &dex_files)) {
695     return false;
696   }
697 
698   // Write type lookup tables into the oat file.
699   if (!WriteTypeLookupTables(&checksum_updating_rodata, dex_files)) {
700     return false;
701   }
702 
703   // Write dex layout sections into the oat file.
704   if (!WriteDexLayoutSections(&checksum_updating_rodata, dex_files)) {
705     return false;
706   }
707 
708   *opened_dex_files_map = std::move(dex_files_map);
709   *opened_dex_files = std::move(dex_files);
710   write_state_ = WriteState::kPrepareLayout;
711   return true;
712 }
713 
714 // Initialize the writer with the given parameters.
Initialize(const CompilerDriver * compiler_driver,ImageWriter * image_writer,const std::vector<const DexFile * > & dex_files)715 void OatWriter::Initialize(const CompilerDriver* compiler_driver,
716                            ImageWriter* image_writer,
717                            const std::vector<const DexFile*>& dex_files) {
718   compiler_driver_ = compiler_driver;
719   image_writer_ = image_writer;
720   dex_files_ = &dex_files;
721 }
722 
PrepareLayout(MultiOatRelativePatcher * relative_patcher)723 void OatWriter::PrepareLayout(MultiOatRelativePatcher* relative_patcher) {
724   CHECK(write_state_ == WriteState::kPrepareLayout);
725 
726   relative_patcher_ = relative_patcher;
727   SetMultiOatRelativePatcherAdjustment();
728 
729   if (GetCompilerOptions().IsBootImage()) {
730     CHECK(image_writer_ != nullptr);
731   }
732   InstructionSet instruction_set = compiler_options_.GetInstructionSet();
733   CHECK_EQ(instruction_set, oat_header_->GetInstructionSet());
734 
735   {
736     TimingLogger::ScopedTiming split("InitBssLayout", timings_);
737     InitBssLayout(instruction_set);
738   }
739 
740   uint32_t offset = oat_size_;
741   {
742     TimingLogger::ScopedTiming split("InitClassOffsets", timings_);
743     offset = InitClassOffsets(offset);
744   }
745   {
746     TimingLogger::ScopedTiming split("InitOatClasses", timings_);
747     offset = InitOatClasses(offset);
748   }
749   {
750     TimingLogger::ScopedTiming split("InitIndexBssMappings", timings_);
751     offset = InitIndexBssMappings(offset);
752   }
753   {
754     TimingLogger::ScopedTiming split("InitOatMaps", timings_);
755     offset = InitOatMaps(offset);
756   }
757   {
758     TimingLogger::ScopedTiming split("InitOatDexFiles", timings_);
759     oat_header_->SetOatDexFilesOffset(offset);
760     offset = InitOatDexFiles(offset);
761   }
762   {
763     TimingLogger::ScopedTiming split("InitOatCode", timings_);
764     offset = InitOatCode(offset);
765   }
766   {
767     TimingLogger::ScopedTiming split("InitOatCodeDexFiles", timings_);
768     offset = InitOatCodeDexFiles(offset);
769     code_size_ = offset - GetOatHeader().GetExecutableOffset();
770   }
771   {
772     TimingLogger::ScopedTiming split("InitDataBimgRelRoLayout", timings_);
773     offset = InitDataBimgRelRoLayout(offset);
774   }
775   oat_size_ = offset;  // .bss does not count towards oat_size_.
776   bss_start_ = (bss_size_ != 0u) ? RoundUp(oat_size_, kPageSize) : 0u;
777 
778   CHECK_EQ(dex_files_->size(), oat_dex_files_.size());
779 
780   write_state_ = WriteState::kWriteRoData;
781 }
782 
~OatWriter()783 OatWriter::~OatWriter() {
784 }
785 
786 class OatWriter::DexMethodVisitor {
787  public:
DexMethodVisitor(OatWriter * writer,size_t offset)788   DexMethodVisitor(OatWriter* writer, size_t offset)
789       : writer_(writer),
790         offset_(offset),
791         dex_file_(nullptr),
792         class_def_index_(dex::kDexNoIndex) {}
793 
StartClass(const DexFile * dex_file,size_t class_def_index)794   virtual bool StartClass(const DexFile* dex_file, size_t class_def_index) {
795     DCHECK(dex_file_ == nullptr);
796     DCHECK_EQ(class_def_index_, dex::kDexNoIndex);
797     dex_file_ = dex_file;
798     class_def_index_ = class_def_index;
799     return true;
800   }
801 
802   virtual bool VisitMethod(size_t class_def_method_index, const ClassAccessor::Method& method) = 0;
803 
EndClass()804   virtual bool EndClass() {
805     if (kIsDebugBuild) {
806       dex_file_ = nullptr;
807       class_def_index_ = dex::kDexNoIndex;
808     }
809     return true;
810   }
811 
GetOffset() const812   size_t GetOffset() const {
813     return offset_;
814   }
815 
816  protected:
~DexMethodVisitor()817   virtual ~DexMethodVisitor() { }
818 
819   OatWriter* const writer_;
820 
821   // The offset is usually advanced for each visited method by the derived class.
822   size_t offset_;
823 
824   // The dex file and class def index are set in StartClass().
825   const DexFile* dex_file_;
826   size_t class_def_index_;
827 };
828 
829 class OatWriter::OatDexMethodVisitor : public DexMethodVisitor {
830  public:
OatDexMethodVisitor(OatWriter * writer,size_t offset)831   OatDexMethodVisitor(OatWriter* writer, size_t offset)
832       : DexMethodVisitor(writer, offset),
833         oat_class_index_(0u),
834         method_offsets_index_(0u) {}
835 
StartClass(const DexFile * dex_file,size_t class_def_index)836   bool StartClass(const DexFile* dex_file, size_t class_def_index) override {
837     DexMethodVisitor::StartClass(dex_file, class_def_index);
838     if (kIsDebugBuild && writer_->MayHaveCompiledMethods()) {
839       // There are no oat classes if there aren't any compiled methods.
840       CHECK_LT(oat_class_index_, writer_->oat_classes_.size());
841     }
842     method_offsets_index_ = 0u;
843     return true;
844   }
845 
EndClass()846   bool EndClass() override {
847     ++oat_class_index_;
848     return DexMethodVisitor::EndClass();
849   }
850 
851  protected:
852   size_t oat_class_index_;
853   size_t method_offsets_index_;
854 };
855 
HasCompiledCode(const CompiledMethod * method)856 static bool HasCompiledCode(const CompiledMethod* method) {
857   return method != nullptr && !method->GetQuickCode().empty();
858 }
859 
HasQuickeningInfo(const CompiledMethod * method)860 static bool HasQuickeningInfo(const CompiledMethod* method) {
861   // The dextodexcompiler puts the quickening info table into the CompiledMethod
862   // for simplicity.
863   return method != nullptr && method->GetQuickCode().empty() && !method->GetVmapTable().empty();
864 }
865 
866 class OatWriter::InitBssLayoutMethodVisitor : public DexMethodVisitor {
867  public:
InitBssLayoutMethodVisitor(OatWriter * writer)868   explicit InitBssLayoutMethodVisitor(OatWriter* writer)
869       : DexMethodVisitor(writer, /* offset */ 0u) {}
870 
VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED,const ClassAccessor::Method & method)871   bool VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED,
872                    const ClassAccessor::Method& method) override {
873     // Look for patches with .bss references and prepare maps with placeholders for their offsets.
874     CompiledMethod* compiled_method = writer_->compiler_driver_->GetCompiledMethod(
875         MethodReference(dex_file_, method.GetIndex()));
876     if (HasCompiledCode(compiled_method)) {
877       for (const LinkerPatch& patch : compiled_method->GetPatches()) {
878         if (patch.GetType() == LinkerPatch::Type::kDataBimgRelRo) {
879           writer_->data_bimg_rel_ro_entries_.Overwrite(patch.BootImageOffset(),
880                                                        /* placeholder */ 0u);
881         } else if (patch.GetType() == LinkerPatch::Type::kMethodBssEntry) {
882           MethodReference target_method = patch.TargetMethod();
883           AddBssReference(target_method,
884                           target_method.dex_file->NumMethodIds(),
885                           &writer_->bss_method_entry_references_);
886           writer_->bss_method_entries_.Overwrite(target_method, /* placeholder */ 0u);
887         } else if (patch.GetType() == LinkerPatch::Type::kTypeBssEntry) {
888           TypeReference target_type(patch.TargetTypeDexFile(), patch.TargetTypeIndex());
889           AddBssReference(target_type,
890                           target_type.dex_file->NumTypeIds(),
891                           &writer_->bss_type_entry_references_);
892           writer_->bss_type_entries_.Overwrite(target_type, /* placeholder */ 0u);
893         } else if (patch.GetType() == LinkerPatch::Type::kStringBssEntry) {
894           StringReference target_string(patch.TargetStringDexFile(), patch.TargetStringIndex());
895           AddBssReference(target_string,
896                           target_string.dex_file->NumStringIds(),
897                           &writer_->bss_string_entry_references_);
898           writer_->bss_string_entries_.Overwrite(target_string, /* placeholder */ 0u);
899         }
900       }
901     } else {
902       DCHECK(compiled_method == nullptr || compiled_method->GetPatches().empty());
903     }
904     return true;
905   }
906 
907  private:
AddBssReference(const DexFileReference & ref,size_t number_of_indexes,SafeMap<const DexFile *,BitVector> * references)908   void AddBssReference(const DexFileReference& ref,
909                        size_t number_of_indexes,
910                        /*inout*/ SafeMap<const DexFile*, BitVector>* references) {
911     // We currently support inlining of throwing instructions only when they originate in the
912     // same dex file as the outer method. All .bss references are used by throwing instructions.
913     DCHECK_EQ(dex_file_, ref.dex_file);
914 
915     auto refs_it = references->find(ref.dex_file);
916     if (refs_it == references->end()) {
917       refs_it = references->Put(
918           ref.dex_file,
919           BitVector(number_of_indexes, /* expandable */ false, Allocator::GetMallocAllocator()));
920       refs_it->second.ClearAllBits();
921     }
922     refs_it->second.SetBit(ref.index);
923   }
924 };
925 
926 class OatWriter::InitOatClassesMethodVisitor : public DexMethodVisitor {
927  public:
InitOatClassesMethodVisitor(OatWriter * writer,size_t offset)928   InitOatClassesMethodVisitor(OatWriter* writer, size_t offset)
929       : DexMethodVisitor(writer, offset),
930         compiled_methods_(),
931         compiled_methods_with_code_(0u) {
932     size_t num_classes = 0u;
933     for (const OatDexFile& oat_dex_file : writer_->oat_dex_files_) {
934       num_classes += oat_dex_file.class_offsets_.size();
935     }
936     // If we aren't compiling only reserve headers.
937     writer_->oat_class_headers_.reserve(num_classes);
938     if (writer->MayHaveCompiledMethods()) {
939       writer->oat_classes_.reserve(num_classes);
940     }
941     compiled_methods_.reserve(256u);
942     // If there are any classes, the class offsets allocation aligns the offset.
943     DCHECK(num_classes == 0u || IsAligned<4u>(offset));
944   }
945 
StartClass(const DexFile * dex_file,size_t class_def_index)946   bool StartClass(const DexFile* dex_file, size_t class_def_index) override {
947     DexMethodVisitor::StartClass(dex_file, class_def_index);
948     compiled_methods_.clear();
949     compiled_methods_with_code_ = 0u;
950     return true;
951   }
952 
VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED,const ClassAccessor::Method & method)953   bool VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED,
954                    const ClassAccessor::Method& method) override {
955     // Fill in the compiled_methods_ array for methods that have a
956     // CompiledMethod. We track the number of non-null entries in
957     // compiled_methods_with_code_ since we only want to allocate
958     // OatMethodOffsets for the compiled methods.
959     uint32_t method_idx = method.GetIndex();
960     CompiledMethod* compiled_method =
961         writer_->compiler_driver_->GetCompiledMethod(MethodReference(dex_file_, method_idx));
962     compiled_methods_.push_back(compiled_method);
963     if (HasCompiledCode(compiled_method)) {
964       ++compiled_methods_with_code_;
965     }
966     return true;
967   }
968 
EndClass()969   bool EndClass() override {
970     ClassReference class_ref(dex_file_, class_def_index_);
971     ClassStatus status;
972     bool found = writer_->compiler_driver_->GetCompiledClass(class_ref, &status);
973     if (!found) {
974       const VerificationResults* results = writer_->compiler_options_.GetVerificationResults();
975       if (results != nullptr && results->IsClassRejected(class_ref)) {
976         // The oat class status is used only for verification of resolved classes,
977         // so use ClassStatus::kErrorResolved whether the class was resolved or unresolved
978         // during compile-time verification.
979         status = ClassStatus::kErrorResolved;
980       } else {
981         status = ClassStatus::kNotReady;
982       }
983     }
984 
985     writer_->oat_class_headers_.emplace_back(offset_,
986                                              compiled_methods_with_code_,
987                                              compiled_methods_.size(),
988                                              status);
989     OatClassHeader& header = writer_->oat_class_headers_.back();
990     offset_ += header.SizeOf();
991     if (writer_->MayHaveCompiledMethods()) {
992       writer_->oat_classes_.emplace_back(compiled_methods_,
993                                          compiled_methods_with_code_,
994                                          header.type_);
995       offset_ += writer_->oat_classes_.back().SizeOf();
996     }
997     return DexMethodVisitor::EndClass();
998   }
999 
1000  private:
1001   dchecked_vector<CompiledMethod*> compiled_methods_;
1002   size_t compiled_methods_with_code_;
1003 };
1004 
1005 // CompiledMethod + metadata required to do ordered method layout.
1006 //
1007 // See also OrderedMethodVisitor.
1008 struct OatWriter::OrderedMethodData {
1009   ProfileCompilationInfo::MethodHotness method_hotness;
1010   OatClass* oat_class;
1011   CompiledMethod* compiled_method;
1012   MethodReference method_reference;
1013   size_t method_offsets_index;
1014 
1015   size_t class_def_index;
1016   uint32_t access_flags;
1017   const dex::CodeItem* code_item;
1018 
1019   // A value of -1 denotes missing debug info
1020   static constexpr size_t kDebugInfoIdxInvalid = static_cast<size_t>(-1);
1021   // Index into writer_->method_info_
1022   size_t debug_info_idx;
1023 
HasDebugInfoart::linker::OatWriter::OrderedMethodData1024   bool HasDebugInfo() const {
1025     return debug_info_idx != kDebugInfoIdxInvalid;
1026   }
1027 
1028   // Bin each method according to the profile flags.
1029   //
1030   // Groups by e.g.
1031   //  -- not hot at all
1032   //  -- hot
1033   //  -- hot and startup
1034   //  -- hot and post-startup
1035   //  -- hot and startup and poststartup
1036   //  -- startup
1037   //  -- startup and post-startup
1038   //  -- post-startup
1039   //
1040   // (See MethodHotness enum definition for up-to-date binning order.)
operator <art::linker::OatWriter::OrderedMethodData1041   bool operator<(const OrderedMethodData& other) const {
1042     if (kOatWriterForceOatCodeLayout) {
1043       // Development flag: Override default behavior by sorting by name.
1044 
1045       std::string name = method_reference.PrettyMethod();
1046       std::string other_name = other.method_reference.PrettyMethod();
1047       return name < other_name;
1048     }
1049 
1050     // Use the profile's method hotness to determine sort order.
1051     if (GetMethodHotnessOrder() < other.GetMethodHotnessOrder()) {
1052       return true;
1053     }
1054 
1055     // Default: retain the original order.
1056     return false;
1057   }
1058 
1059  private:
1060   // Used to determine relative order for OAT code layout when determining
1061   // binning.
GetMethodHotnessOrderart::linker::OatWriter::OrderedMethodData1062   size_t GetMethodHotnessOrder() const {
1063     bool hotness[] = {
1064       method_hotness.IsHot(),
1065       method_hotness.IsStartup(),
1066       method_hotness.IsPostStartup()
1067     };
1068 
1069 
1070     // Note: Bin-to-bin order does not matter. If the kernel does or does not read-ahead
1071     // any memory, it only goes into the buffer cache and does not grow the PSS until the first
1072     // time that memory is referenced in the process.
1073 
1074     size_t hotness_bits = 0;
1075     for (size_t i = 0; i < arraysize(hotness); ++i) {
1076       if (hotness[i]) {
1077         hotness_bits |= (1 << i);
1078       }
1079     }
1080 
1081     if (kIsDebugBuild) {
1082       // Check for bins that are always-empty given a real profile.
1083       if (method_hotness.IsHot() &&
1084               !method_hotness.IsStartup() && !method_hotness.IsPostStartup()) {
1085         std::string name = method_reference.PrettyMethod();
1086         LOG(FATAL) << "Method " << name << " had a Hot method that wasn't marked "
1087                    << "either start-up or post-startup. Possible corrupted profile?";
1088         // This is not fatal, so only warn.
1089       }
1090     }
1091 
1092     return hotness_bits;
1093   }
1094 };
1095 
1096 // Given a queue of CompiledMethod in some total order,
1097 // visit each one in that order.
1098 class OatWriter::OrderedMethodVisitor {
1099  public:
OrderedMethodVisitor(OrderedMethodList ordered_methods)1100   explicit OrderedMethodVisitor(OrderedMethodList ordered_methods)
1101       : ordered_methods_(std::move(ordered_methods)) {
1102   }
1103 
~OrderedMethodVisitor()1104   virtual ~OrderedMethodVisitor() {}
1105 
1106   // Invoke VisitMethod in the order of `ordered_methods`, then invoke VisitComplete.
Visit()1107   bool Visit() REQUIRES_SHARED(Locks::mutator_lock_) {
1108     if (!VisitStart()) {
1109       return false;
1110     }
1111 
1112     for (const OrderedMethodData& method_data : ordered_methods_)  {
1113       if (!VisitMethod(method_data)) {
1114         return false;
1115       }
1116     }
1117 
1118     return VisitComplete();
1119   }
1120 
1121   // Invoked once at the beginning, prior to visiting anything else.
1122   //
1123   // Return false to abort further visiting.
VisitStart()1124   virtual bool VisitStart() { return true; }
1125 
1126   // Invoked repeatedly in the order specified by `ordered_methods`.
1127   //
1128   // Return false to short-circuit and to stop visiting further methods.
1129   virtual bool VisitMethod(const OrderedMethodData& method_data)
1130       REQUIRES_SHARED(Locks::mutator_lock_)  = 0;
1131 
1132   // Invoked once at the end, after every other method has been successfully visited.
1133   //
1134   // Return false to indicate the overall `Visit` has failed.
1135   virtual bool VisitComplete() = 0;
1136 
ReleaseOrderedMethods()1137   OrderedMethodList ReleaseOrderedMethods() {
1138     return std::move(ordered_methods_);
1139   }
1140 
1141  private:
1142   // List of compiled methods, sorted by the order defined in OrderedMethodData.
1143   // Methods can be inserted more than once in case of duplicated methods.
1144   OrderedMethodList ordered_methods_;
1145 };
1146 
1147 // Visit every compiled method in order to determine its order within the OAT file.
1148 // Methods from the same class do not need to be adjacent in the OAT code.
1149 class OatWriter::LayoutCodeMethodVisitor : public OatDexMethodVisitor {
1150  public:
LayoutCodeMethodVisitor(OatWriter * writer,size_t offset)1151   LayoutCodeMethodVisitor(OatWriter* writer, size_t offset)
1152       : OatDexMethodVisitor(writer, offset) {
1153   }
1154 
EndClass()1155   bool EndClass() override {
1156     OatDexMethodVisitor::EndClass();
1157     return true;
1158   }
1159 
VisitMethod(size_t class_def_method_index,const ClassAccessor::Method & method)1160   bool VisitMethod(size_t class_def_method_index,
1161                    const ClassAccessor::Method& method)
1162       override
1163       REQUIRES_SHARED(Locks::mutator_lock_)  {
1164     Locks::mutator_lock_->AssertSharedHeld(Thread::Current());
1165 
1166     OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
1167     CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1168 
1169     if (HasCompiledCode(compiled_method)) {
1170       size_t debug_info_idx = OrderedMethodData::kDebugInfoIdxInvalid;
1171 
1172       {
1173         const CompilerOptions& compiler_options = writer_->GetCompilerOptions();
1174         ArrayRef<const uint8_t> quick_code = compiled_method->GetQuickCode();
1175         uint32_t code_size = quick_code.size() * sizeof(uint8_t);
1176 
1177         // Debug method info must be pushed in the original order
1178         // (i.e. all methods from the same class must be adjacent in the debug info sections)
1179         // ElfCompilationUnitWriter::Write requires this.
1180         if (compiler_options.GenerateAnyDebugInfo() && code_size != 0) {
1181           debug::MethodDebugInfo info = debug::MethodDebugInfo();
1182           writer_->method_info_.push_back(info);
1183 
1184           // The debug info is filled in LayoutReserveOffsetCodeMethodVisitor
1185           // once we know the offsets.
1186           //
1187           // Store the index into writer_->method_info_ since future push-backs
1188           // could reallocate and change the underlying data address.
1189           debug_info_idx = writer_->method_info_.size() - 1;
1190         }
1191       }
1192 
1193       MethodReference method_ref(dex_file_, method.GetIndex());
1194 
1195       // Lookup method hotness from profile, if available.
1196       // Otherwise assume a default of none-hotness.
1197       ProfileCompilationInfo::MethodHotness method_hotness =
1198           writer_->profile_compilation_info_ != nullptr
1199               ? writer_->profile_compilation_info_->GetMethodHotness(method_ref)
1200               : ProfileCompilationInfo::MethodHotness();
1201 
1202       // Handle duplicate methods by pushing them repeatedly.
1203       OrderedMethodData method_data = {
1204           method_hotness,
1205           oat_class,
1206           compiled_method,
1207           method_ref,
1208           method_offsets_index_,
1209           class_def_index_,
1210           method.GetAccessFlags(),
1211           method.GetCodeItem(),
1212           debug_info_idx
1213       };
1214       ordered_methods_.push_back(method_data);
1215 
1216       method_offsets_index_++;
1217     }
1218 
1219     return true;
1220   }
1221 
ReleaseOrderedMethods()1222   OrderedMethodList ReleaseOrderedMethods() {
1223     if (kOatWriterForceOatCodeLayout || writer_->profile_compilation_info_ != nullptr) {
1224       // Sort by the method ordering criteria (in OrderedMethodData).
1225       // Since most methods will have the same ordering criteria,
1226       // we preserve the original insertion order within the same sort order.
1227       std::stable_sort(ordered_methods_.begin(), ordered_methods_.end());
1228     } else {
1229       // The profile-less behavior is as if every method had 0 hotness
1230       // associated with it.
1231       //
1232       // Since sorting all methods with hotness=0 should give back the same
1233       // order as before, don't do anything.
1234       DCHECK(std::is_sorted(ordered_methods_.begin(), ordered_methods_.end()));
1235     }
1236 
1237     return std::move(ordered_methods_);
1238   }
1239 
1240  private:
1241   // List of compiled methods, later to be sorted by order defined in OrderedMethodData.
1242   // Methods can be inserted more than once in case of duplicated methods.
1243   OrderedMethodList ordered_methods_;
1244 };
1245 
1246 // Given a method order, reserve the offsets for each CompiledMethod in the OAT file.
1247 class OatWriter::LayoutReserveOffsetCodeMethodVisitor : public OrderedMethodVisitor {
1248  public:
LayoutReserveOffsetCodeMethodVisitor(OatWriter * writer,size_t offset,OrderedMethodList ordered_methods)1249   LayoutReserveOffsetCodeMethodVisitor(OatWriter* writer,
1250                                        size_t offset,
1251                                        OrderedMethodList ordered_methods)
1252       : LayoutReserveOffsetCodeMethodVisitor(writer,
1253                                              offset,
1254                                              writer->GetCompilerOptions(),
1255                                              std::move(ordered_methods)) {
1256   }
1257 
VisitComplete()1258   bool VisitComplete() override {
1259     offset_ = writer_->relative_patcher_->ReserveSpaceEnd(offset_);
1260     if (generate_debug_info_) {
1261       std::vector<debug::MethodDebugInfo> thunk_infos =
1262           relative_patcher_->GenerateThunkDebugInfo(executable_offset_);
1263       writer_->method_info_.insert(writer_->method_info_.end(),
1264                                    std::make_move_iterator(thunk_infos.begin()),
1265                                    std::make_move_iterator(thunk_infos.end()));
1266     }
1267     return true;
1268   }
1269 
VisitMethod(const OrderedMethodData & method_data)1270   bool VisitMethod(const OrderedMethodData& method_data) override
1271       REQUIRES_SHARED(Locks::mutator_lock_) {
1272     OatClass* oat_class = method_data.oat_class;
1273     CompiledMethod* compiled_method = method_data.compiled_method;
1274     const MethodReference& method_ref = method_data.method_reference;
1275     uint16_t method_offsets_index_ = method_data.method_offsets_index;
1276     size_t class_def_index = method_data.class_def_index;
1277     uint32_t access_flags = method_data.access_flags;
1278     bool has_debug_info = method_data.HasDebugInfo();
1279     size_t debug_info_idx = method_data.debug_info_idx;
1280 
1281     DCHECK(HasCompiledCode(compiled_method)) << method_ref.PrettyMethod();
1282 
1283     // Derived from CompiledMethod.
1284     uint32_t quick_code_offset = 0;
1285 
1286     ArrayRef<const uint8_t> quick_code = compiled_method->GetQuickCode();
1287     uint32_t code_size = quick_code.size() * sizeof(uint8_t);
1288     uint32_t thumb_offset = compiled_method->CodeDelta();
1289 
1290     // Deduplicate code arrays if we are not producing debuggable code.
1291     bool deduped = true;
1292     if (debuggable_) {
1293       quick_code_offset = relative_patcher_->GetOffset(method_ref);
1294       if (quick_code_offset != 0u) {
1295         // Duplicate methods, we want the same code for both of them so that the oat writer puts
1296         // the same code in both ArtMethods so that we do not get different oat code at runtime.
1297       } else {
1298         quick_code_offset = NewQuickCodeOffset(compiled_method, method_ref, thumb_offset);
1299         deduped = false;
1300       }
1301     } else {
1302       quick_code_offset = dedupe_map_.GetOrCreate(
1303           compiled_method,
1304           [this, &deduped, compiled_method, &method_ref, thumb_offset]() {
1305             deduped = false;
1306             return NewQuickCodeOffset(compiled_method, method_ref, thumb_offset);
1307           });
1308     }
1309 
1310     if (code_size != 0) {
1311       if (relative_patcher_->GetOffset(method_ref) != 0u) {
1312         // TODO: Should this be a hard failure?
1313         LOG(WARNING) << "Multiple definitions of "
1314             << method_ref.dex_file->PrettyMethod(method_ref.index)
1315             << " offsets " << relative_patcher_->GetOffset(method_ref)
1316             << " " << quick_code_offset;
1317       } else {
1318         relative_patcher_->SetOffset(method_ref, quick_code_offset);
1319       }
1320     }
1321 
1322     // Update quick method header.
1323     DCHECK_LT(method_offsets_index_, oat_class->method_headers_.size());
1324     OatQuickMethodHeader* method_header = &oat_class->method_headers_[method_offsets_index_];
1325     uint32_t vmap_table_offset = method_header->GetVmapTableOffset();
1326     // The code offset was 0 when the mapping/vmap table offset was set, so it's set
1327     // to 0-offset and we need to adjust it by code_offset.
1328     uint32_t code_offset = quick_code_offset - thumb_offset;
1329     CHECK(!compiled_method->GetQuickCode().empty());
1330     // If the code is compiled, we write the offset of the stack map relative
1331     // to the code.
1332     if (vmap_table_offset != 0u) {
1333       vmap_table_offset += code_offset;
1334       DCHECK_LT(vmap_table_offset, code_offset);
1335     }
1336     *method_header = OatQuickMethodHeader(vmap_table_offset, code_size);
1337 
1338     if (!deduped) {
1339       // Update offsets. (Checksum is updated when writing.)
1340       offset_ += sizeof(*method_header);  // Method header is prepended before code.
1341       offset_ += code_size;
1342     }
1343 
1344     // Exclude quickened dex methods (code_size == 0) since they have no native code.
1345     if (generate_debug_info_ && code_size != 0) {
1346       DCHECK(has_debug_info);
1347       const uint8_t* code_info = compiled_method->GetVmapTable().data();
1348       DCHECK(code_info != nullptr);
1349 
1350       // Record debug information for this function if we are doing that.
1351       debug::MethodDebugInfo& info = writer_->method_info_[debug_info_idx];
1352       info.custom_name = (access_flags & kAccNative) ? "art_jni_trampoline" : "";
1353       info.dex_file = method_ref.dex_file;
1354       info.class_def_index = class_def_index;
1355       info.dex_method_index = method_ref.index;
1356       info.access_flags = access_flags;
1357       // For intrinsics emitted by codegen, the code has no relation to the original code item.
1358       info.code_item = compiled_method->IsIntrinsic() ? nullptr : method_data.code_item;
1359       info.isa = compiled_method->GetInstructionSet();
1360       info.deduped = deduped;
1361       info.is_native_debuggable = native_debuggable_;
1362       info.is_optimized = method_header->IsOptimized();
1363       info.is_code_address_text_relative = true;
1364       info.code_address = code_offset - executable_offset_;
1365       info.code_size = code_size;
1366       info.frame_size_in_bytes = CodeInfo::DecodeFrameInfo(code_info).FrameSizeInBytes();
1367       info.code_info = code_info;
1368       info.cfi = compiled_method->GetCFIInfo();
1369     } else {
1370       DCHECK(!has_debug_info);
1371     }
1372 
1373     DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
1374     OatMethodOffsets* offsets = &oat_class->method_offsets_[method_offsets_index_];
1375     offsets->code_offset_ = quick_code_offset;
1376 
1377     return true;
1378   }
1379 
GetOffset() const1380   size_t GetOffset() const {
1381     return offset_;
1382   }
1383 
1384  private:
LayoutReserveOffsetCodeMethodVisitor(OatWriter * writer,size_t offset,const CompilerOptions & compiler_options,OrderedMethodList ordered_methods)1385   LayoutReserveOffsetCodeMethodVisitor(OatWriter* writer,
1386                                        size_t offset,
1387                                        const CompilerOptions& compiler_options,
1388                                        OrderedMethodList ordered_methods)
1389       : OrderedMethodVisitor(std::move(ordered_methods)),
1390         writer_(writer),
1391         offset_(offset),
1392         relative_patcher_(writer->relative_patcher_),
1393         executable_offset_(writer->oat_header_->GetExecutableOffset()),
1394         debuggable_(compiler_options.GetDebuggable()),
1395         native_debuggable_(compiler_options.GetNativeDebuggable()),
1396         generate_debug_info_(compiler_options.GenerateAnyDebugInfo()) {}
1397 
1398   struct CodeOffsetsKeyComparator {
operator ()art::linker::OatWriter::LayoutReserveOffsetCodeMethodVisitor::CodeOffsetsKeyComparator1399     bool operator()(const CompiledMethod* lhs, const CompiledMethod* rhs) const {
1400       // Code is deduplicated by CompilerDriver, compare only data pointers.
1401       if (lhs->GetQuickCode().data() != rhs->GetQuickCode().data()) {
1402         return lhs->GetQuickCode().data() < rhs->GetQuickCode().data();
1403       }
1404       // If the code is the same, all other fields are likely to be the same as well.
1405       if (UNLIKELY(lhs->GetVmapTable().data() != rhs->GetVmapTable().data())) {
1406         return lhs->GetVmapTable().data() < rhs->GetVmapTable().data();
1407       }
1408       if (UNLIKELY(lhs->GetPatches().data() != rhs->GetPatches().data())) {
1409         return lhs->GetPatches().data() < rhs->GetPatches().data();
1410       }
1411       if (UNLIKELY(lhs->IsIntrinsic() != rhs->IsIntrinsic())) {
1412         return rhs->IsIntrinsic();
1413       }
1414       return false;
1415     }
1416   };
1417 
NewQuickCodeOffset(CompiledMethod * compiled_method,const MethodReference & method_ref,uint32_t thumb_offset)1418   uint32_t NewQuickCodeOffset(CompiledMethod* compiled_method,
1419                               const MethodReference& method_ref,
1420                               uint32_t thumb_offset) {
1421     offset_ = relative_patcher_->ReserveSpace(offset_, compiled_method, method_ref);
1422     offset_ += CodeAlignmentSize(offset_, *compiled_method);
1423     DCHECK_ALIGNED_PARAM(offset_ + sizeof(OatQuickMethodHeader),
1424                          GetInstructionSetAlignment(compiled_method->GetInstructionSet()));
1425     return offset_ + sizeof(OatQuickMethodHeader) + thumb_offset;
1426   }
1427 
1428   OatWriter* writer_;
1429 
1430   // Offset of the code of the compiled methods.
1431   size_t offset_;
1432 
1433   // Deduplication is already done on a pointer basis by the compiler driver,
1434   // so we can simply compare the pointers to find out if things are duplicated.
1435   SafeMap<const CompiledMethod*, uint32_t, CodeOffsetsKeyComparator> dedupe_map_;
1436 
1437   // Cache writer_'s members and compiler options.
1438   MultiOatRelativePatcher* relative_patcher_;
1439   uint32_t executable_offset_;
1440   const bool debuggable_;
1441   const bool native_debuggable_;
1442   const bool generate_debug_info_;
1443 };
1444 
1445 class OatWriter::InitMapMethodVisitor : public OatDexMethodVisitor {
1446  public:
InitMapMethodVisitor(OatWriter * writer,size_t offset)1447   InitMapMethodVisitor(OatWriter* writer, size_t offset)
1448       : OatDexMethodVisitor(writer, offset),
1449         dedupe_bit_table_(&writer_->code_info_data_) {
1450   }
1451 
VisitMethod(size_t class_def_method_index,const ClassAccessor::Method & method ATTRIBUTE_UNUSED)1452   bool VisitMethod(size_t class_def_method_index,
1453                    const ClassAccessor::Method& method ATTRIBUTE_UNUSED)
1454       override REQUIRES_SHARED(Locks::mutator_lock_) {
1455     OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
1456     CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1457 
1458     if (HasCompiledCode(compiled_method)) {
1459       DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
1460       DCHECK_EQ(oat_class->method_headers_[method_offsets_index_].GetVmapTableOffset(), 0u);
1461 
1462       ArrayRef<const uint8_t> map = compiled_method->GetVmapTable();
1463       if (map.size() != 0u) {
1464         size_t offset = dedupe_code_info_.GetOrCreate(map.data(), [=]() {
1465           // Deduplicate the inner BitTable<>s within the CodeInfo.
1466           return offset_ + dedupe_bit_table_.Dedupe(map.data());
1467         });
1468         // Code offset is not initialized yet, so set the map offset to 0u-offset.
1469         DCHECK_EQ(oat_class->method_offsets_[method_offsets_index_].code_offset_, 0u);
1470         oat_class->method_headers_[method_offsets_index_].SetVmapTableOffset(0u - offset);
1471       }
1472       ++method_offsets_index_;
1473     }
1474 
1475     return true;
1476   }
1477 
1478  private:
1479   // Deduplicate at CodeInfo level. The value is byte offset within code_info_data_.
1480   // This deduplicates the whole CodeInfo object without going into the inner tables.
1481   // The compiler already deduplicated the pointers but it did not dedupe the tables.
1482   SafeMap<const uint8_t*, size_t> dedupe_code_info_;
1483 
1484   // Deduplicate at BitTable level.
1485   CodeInfo::Deduper dedupe_bit_table_;
1486 };
1487 
1488 class OatWriter::InitImageMethodVisitor : public OatDexMethodVisitor {
1489  public:
InitImageMethodVisitor(OatWriter * writer,size_t offset,const std::vector<const DexFile * > * dex_files)1490   InitImageMethodVisitor(OatWriter* writer,
1491                          size_t offset,
1492                          const std::vector<const DexFile*>* dex_files)
1493       : OatDexMethodVisitor(writer, offset),
1494         pointer_size_(GetInstructionSetPointerSize(writer_->compiler_options_.GetInstructionSet())),
1495         class_loader_(writer->HasImage() ? writer->image_writer_->GetAppClassLoader() : nullptr),
1496         dex_files_(dex_files),
1497         class_linker_(Runtime::Current()->GetClassLinker()) {}
1498 
1499   // Handle copied methods here. Copy pointer to quick code from
1500   // an origin method to a copied method only if they are
1501   // in the same oat file. If the origin and the copied methods are
1502   // in different oat files don't touch the copied method.
1503   // References to other oat files are not supported yet.
StartClass(const DexFile * dex_file,size_t class_def_index)1504   bool StartClass(const DexFile* dex_file, size_t class_def_index) override
1505       REQUIRES_SHARED(Locks::mutator_lock_) {
1506     OatDexMethodVisitor::StartClass(dex_file, class_def_index);
1507     // Skip classes that are not in the image.
1508     if (!IsImageClass()) {
1509       return true;
1510     }
1511     ObjPtr<mirror::DexCache> dex_cache = class_linker_->FindDexCache(Thread::Current(), *dex_file);
1512     const dex::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
1513     ObjPtr<mirror::Class> klass =
1514         class_linker_->LookupResolvedType(class_def.class_idx_, dex_cache, class_loader_);
1515     if (klass != nullptr) {
1516       for (ArtMethod& method : klass->GetCopiedMethods(pointer_size_)) {
1517         // Find origin method. Declaring class and dex_method_idx
1518         // in the copied method should be the same as in the origin
1519         // method.
1520         ObjPtr<mirror::Class> declaring_class = method.GetDeclaringClass();
1521         ArtMethod* origin = declaring_class->FindClassMethod(
1522             declaring_class->GetDexCache(),
1523             method.GetDexMethodIndex(),
1524             pointer_size_);
1525         CHECK(origin != nullptr);
1526         CHECK(!origin->IsDirect());
1527         CHECK(origin->GetDeclaringClass() == declaring_class);
1528         if (IsInOatFile(&declaring_class->GetDexFile())) {
1529           const void* code_ptr =
1530               origin->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size_);
1531           if (code_ptr == nullptr) {
1532             methods_to_process_.push_back(std::make_pair(&method, origin));
1533           } else {
1534             method.SetEntryPointFromQuickCompiledCodePtrSize(
1535                 code_ptr, pointer_size_);
1536           }
1537         }
1538       }
1539     }
1540     return true;
1541   }
1542 
VisitMethod(size_t class_def_method_index,const ClassAccessor::Method & method)1543   bool VisitMethod(size_t class_def_method_index, const ClassAccessor::Method& method) override
1544       REQUIRES_SHARED(Locks::mutator_lock_) {
1545     // Skip methods that are not in the image.
1546     if (!IsImageClass()) {
1547       return true;
1548     }
1549 
1550     OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
1551     CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1552 
1553     OatMethodOffsets offsets(0u);
1554     if (HasCompiledCode(compiled_method)) {
1555       DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
1556       offsets = oat_class->method_offsets_[method_offsets_index_];
1557       ++method_offsets_index_;
1558     }
1559 
1560     Thread* self = Thread::Current();
1561     ObjPtr<mirror::DexCache> dex_cache = class_linker_->FindDexCache(self, *dex_file_);
1562     ArtMethod* resolved_method;
1563     if (writer_->GetCompilerOptions().IsBootImage()) {
1564       resolved_method = class_linker_->LookupResolvedMethod(
1565           method.GetIndex(), dex_cache, /*class_loader=*/ nullptr);
1566       if (resolved_method == nullptr) {
1567         LOG(FATAL) << "Unexpected failure to look up a method: "
1568             << dex_file_->PrettyMethod(method.GetIndex(), true);
1569         UNREACHABLE();
1570       }
1571     } else {
1572       // Should already have been resolved by the compiler.
1573       // It may not be resolved if the class failed to verify, in this case, don't set the
1574       // entrypoint. This is not fatal since we shall use a resolution method.
1575       resolved_method = class_linker_->LookupResolvedMethod(method.GetIndex(),
1576                                                             dex_cache,
1577                                                             class_loader_);
1578     }
1579     if (resolved_method != nullptr &&
1580         compiled_method != nullptr &&
1581         compiled_method->GetQuickCode().size() != 0) {
1582       resolved_method->SetEntryPointFromQuickCompiledCodePtrSize(
1583           reinterpret_cast<void*>(offsets.code_offset_), pointer_size_);
1584     }
1585 
1586     return true;
1587   }
1588 
1589   // Check whether current class is image class
IsImageClass()1590   bool IsImageClass() {
1591     const dex::TypeId& type_id =
1592         dex_file_->GetTypeId(dex_file_->GetClassDef(class_def_index_).class_idx_);
1593     const char* class_descriptor = dex_file_->GetTypeDescriptor(type_id);
1594     return writer_->GetCompilerOptions().IsImageClass(class_descriptor);
1595   }
1596 
1597   // Check whether specified dex file is in the compiled oat file.
IsInOatFile(const DexFile * dex_file)1598   bool IsInOatFile(const DexFile* dex_file) {
1599     return ContainsElement(*dex_files_, dex_file);
1600   }
1601 
1602   // Assign a pointer to quick code for copied methods
1603   // not handled in the method StartClass
Postprocess()1604   void Postprocess() {
1605     for (std::pair<ArtMethod*, ArtMethod*>& p : methods_to_process_) {
1606       ArtMethod* method = p.first;
1607       ArtMethod* origin = p.second;
1608       const void* code_ptr =
1609           origin->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size_);
1610       if (code_ptr != nullptr) {
1611         method->SetEntryPointFromQuickCompiledCodePtrSize(code_ptr, pointer_size_);
1612       }
1613     }
1614   }
1615 
1616  private:
1617   const PointerSize pointer_size_;
1618   ObjPtr<mirror::ClassLoader> class_loader_;
1619   const std::vector<const DexFile*>* dex_files_;
1620   ClassLinker* const class_linker_;
1621   std::vector<std::pair<ArtMethod*, ArtMethod*>> methods_to_process_;
1622 };
1623 
1624 class OatWriter::WriteCodeMethodVisitor : public OrderedMethodVisitor {
1625  public:
WriteCodeMethodVisitor(OatWriter * writer,OutputStream * out,const size_t file_offset,size_t relative_offset,OrderedMethodList ordered_methods)1626   WriteCodeMethodVisitor(OatWriter* writer,
1627                          OutputStream* out,
1628                          const size_t file_offset,
1629                          size_t relative_offset,
1630                          OrderedMethodList ordered_methods)
1631       : OrderedMethodVisitor(std::move(ordered_methods)),
1632         writer_(writer),
1633         offset_(relative_offset),
1634         dex_file_(nullptr),
1635         pointer_size_(GetInstructionSetPointerSize(writer_->compiler_options_.GetInstructionSet())),
1636         class_loader_(writer->HasImage() ? writer->image_writer_->GetAppClassLoader() : nullptr),
1637         out_(out),
1638         file_offset_(file_offset),
1639         class_linker_(Runtime::Current()->GetClassLinker()),
1640         dex_cache_(nullptr),
1641         no_thread_suspension_("OatWriter patching") {
1642     patched_code_.reserve(16 * KB);
1643     if (writer_->GetCompilerOptions().IsBootImage()) {
1644       // If we're creating the image, the address space must be ready so that we can apply patches.
1645       CHECK(writer_->image_writer_->IsImageAddressSpaceReady());
1646     }
1647   }
1648 
VisitStart()1649   bool VisitStart() override {
1650     return true;
1651   }
1652 
UpdateDexFileAndDexCache(const DexFile * dex_file)1653   void UpdateDexFileAndDexCache(const DexFile* dex_file)
1654       REQUIRES_SHARED(Locks::mutator_lock_) {
1655     dex_file_ = dex_file;
1656 
1657     // Ordered method visiting is only for compiled methods.
1658     DCHECK(writer_->MayHaveCompiledMethods());
1659 
1660     if (writer_->GetCompilerOptions().IsAotCompilationEnabled()) {
1661       // Only need to set the dex cache if we have compilation. Other modes might have unloaded it.
1662       if (dex_cache_ == nullptr || dex_cache_->GetDexFile() != dex_file) {
1663         dex_cache_ = class_linker_->FindDexCache(Thread::Current(), *dex_file);
1664         DCHECK(dex_cache_ != nullptr);
1665       }
1666     }
1667   }
1668 
VisitComplete()1669   bool VisitComplete() override {
1670     offset_ = writer_->relative_patcher_->WriteThunks(out_, offset_);
1671     if (UNLIKELY(offset_ == 0u)) {
1672       PLOG(ERROR) << "Failed to write final relative call thunks";
1673       return false;
1674     }
1675     return true;
1676   }
1677 
VisitMethod(const OrderedMethodData & method_data)1678   bool VisitMethod(const OrderedMethodData& method_data) override
1679       REQUIRES_SHARED(Locks::mutator_lock_) {
1680     const MethodReference& method_ref = method_data.method_reference;
1681     UpdateDexFileAndDexCache(method_ref.dex_file);
1682 
1683     OatClass* oat_class = method_data.oat_class;
1684     CompiledMethod* compiled_method = method_data.compiled_method;
1685     uint16_t method_offsets_index = method_data.method_offsets_index;
1686 
1687     // No thread suspension since dex_cache_ that may get invalidated if that occurs.
1688     ScopedAssertNoThreadSuspension tsc(__FUNCTION__);
1689     DCHECK(HasCompiledCode(compiled_method)) << method_ref.PrettyMethod();
1690 
1691     // TODO: cleanup DCHECK_OFFSET_ to accept file_offset as parameter.
1692     size_t file_offset = file_offset_;  // Used by DCHECK_OFFSET_ macro.
1693     OutputStream* out = out_;
1694 
1695     ArrayRef<const uint8_t> quick_code = compiled_method->GetQuickCode();
1696     uint32_t code_size = quick_code.size() * sizeof(uint8_t);
1697 
1698     // Deduplicate code arrays.
1699     const OatMethodOffsets& method_offsets = oat_class->method_offsets_[method_offsets_index];
1700     if (method_offsets.code_offset_ > offset_) {
1701       offset_ = writer_->relative_patcher_->WriteThunks(out, offset_);
1702       if (offset_ == 0u) {
1703         ReportWriteFailure("relative call thunk", method_ref);
1704         return false;
1705       }
1706       uint32_t alignment_size = CodeAlignmentSize(offset_, *compiled_method);
1707       if (alignment_size != 0) {
1708         if (!writer_->WriteCodeAlignment(out, alignment_size)) {
1709           ReportWriteFailure("code alignment padding", method_ref);
1710           return false;
1711         }
1712         offset_ += alignment_size;
1713         DCHECK_OFFSET_();
1714       }
1715       DCHECK_ALIGNED_PARAM(offset_ + sizeof(OatQuickMethodHeader),
1716                            GetInstructionSetAlignment(compiled_method->GetInstructionSet()));
1717       DCHECK_EQ(method_offsets.code_offset_,
1718                 offset_ + sizeof(OatQuickMethodHeader) + compiled_method->CodeDelta())
1719           << dex_file_->PrettyMethod(method_ref.index);
1720       const OatQuickMethodHeader& method_header =
1721           oat_class->method_headers_[method_offsets_index];
1722       if (!out->WriteFully(&method_header, sizeof(method_header))) {
1723         ReportWriteFailure("method header", method_ref);
1724         return false;
1725       }
1726       writer_->size_method_header_ += sizeof(method_header);
1727       offset_ += sizeof(method_header);
1728       DCHECK_OFFSET_();
1729 
1730       if (!compiled_method->GetPatches().empty()) {
1731         patched_code_.assign(quick_code.begin(), quick_code.end());
1732         quick_code = ArrayRef<const uint8_t>(patched_code_);
1733         for (const LinkerPatch& patch : compiled_method->GetPatches()) {
1734           uint32_t literal_offset = patch.LiteralOffset();
1735           switch (patch.GetType()) {
1736             case LinkerPatch::Type::kIntrinsicReference: {
1737               uint32_t target_offset = GetTargetIntrinsicReferenceOffset(patch);
1738               writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1739                                                                    patch,
1740                                                                    offset_ + literal_offset,
1741                                                                    target_offset);
1742               break;
1743             }
1744             case LinkerPatch::Type::kDataBimgRelRo: {
1745               uint32_t target_offset =
1746                   writer_->data_bimg_rel_ro_start_ +
1747                   writer_->data_bimg_rel_ro_entries_.Get(patch.BootImageOffset());
1748               writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1749                                                                    patch,
1750                                                                    offset_ + literal_offset,
1751                                                                    target_offset);
1752               break;
1753             }
1754             case LinkerPatch::Type::kMethodBssEntry: {
1755               uint32_t target_offset =
1756                   writer_->bss_start_ + writer_->bss_method_entries_.Get(patch.TargetMethod());
1757               writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1758                                                                    patch,
1759                                                                    offset_ + literal_offset,
1760                                                                    target_offset);
1761               break;
1762             }
1763             case LinkerPatch::Type::kCallRelative: {
1764               // NOTE: Relative calls across oat files are not supported.
1765               uint32_t target_offset = GetTargetOffset(patch);
1766               writer_->relative_patcher_->PatchCall(&patched_code_,
1767                                                     literal_offset,
1768                                                     offset_ + literal_offset,
1769                                                     target_offset);
1770               break;
1771             }
1772             case LinkerPatch::Type::kStringRelative: {
1773               uint32_t target_offset = GetTargetObjectOffset(GetTargetString(patch));
1774               writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1775                                                                    patch,
1776                                                                    offset_ + literal_offset,
1777                                                                    target_offset);
1778               break;
1779             }
1780             case LinkerPatch::Type::kStringBssEntry: {
1781               StringReference ref(patch.TargetStringDexFile(), patch.TargetStringIndex());
1782               uint32_t target_offset =
1783                   writer_->bss_start_ + writer_->bss_string_entries_.Get(ref);
1784               writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1785                                                                    patch,
1786                                                                    offset_ + literal_offset,
1787                                                                    target_offset);
1788               break;
1789             }
1790             case LinkerPatch::Type::kTypeRelative: {
1791               uint32_t target_offset = GetTargetObjectOffset(GetTargetType(patch));
1792               writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1793                                                                    patch,
1794                                                                    offset_ + literal_offset,
1795                                                                    target_offset);
1796               break;
1797             }
1798             case LinkerPatch::Type::kTypeBssEntry: {
1799               TypeReference ref(patch.TargetTypeDexFile(), patch.TargetTypeIndex());
1800               uint32_t target_offset = writer_->bss_start_ + writer_->bss_type_entries_.Get(ref);
1801               writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1802                                                                    patch,
1803                                                                    offset_ + literal_offset,
1804                                                                    target_offset);
1805               break;
1806             }
1807             case LinkerPatch::Type::kMethodRelative: {
1808               uint32_t target_offset = GetTargetMethodOffset(GetTargetMethod(patch));
1809               writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1810                                                                    patch,
1811                                                                    offset_ + literal_offset,
1812                                                                    target_offset);
1813               break;
1814             }
1815             case LinkerPatch::Type::kBakerReadBarrierBranch: {
1816               writer_->relative_patcher_->PatchBakerReadBarrierBranch(&patched_code_,
1817                                                                       patch,
1818                                                                       offset_ + literal_offset);
1819               break;
1820             }
1821             default: {
1822               DCHECK(false) << "Unexpected linker patch type: " << patch.GetType();
1823               break;
1824             }
1825           }
1826         }
1827       }
1828 
1829       if (!out->WriteFully(quick_code.data(), code_size)) {
1830         ReportWriteFailure("method code", method_ref);
1831         return false;
1832       }
1833       writer_->size_code_ += code_size;
1834       offset_ += code_size;
1835     }
1836     DCHECK_OFFSET_();
1837 
1838     return true;
1839   }
1840 
GetOffset() const1841   size_t GetOffset() const {
1842     return offset_;
1843   }
1844 
1845  private:
1846   OatWriter* const writer_;
1847 
1848   // Updated in VisitMethod as methods are written out.
1849   size_t offset_;
1850 
1851   // Potentially varies with every different VisitMethod.
1852   // Used to determine which DexCache to use when finding ArtMethods.
1853   const DexFile* dex_file_;
1854 
1855   // Pointer size we are compiling to.
1856   const PointerSize pointer_size_;
1857   // The image writer's classloader, if there is one, else null.
1858   ObjPtr<mirror::ClassLoader> class_loader_;
1859   // Stream to output file, where the OAT code will be written to.
1860   OutputStream* const out_;
1861   const size_t file_offset_;
1862   ClassLinker* const class_linker_;
1863   ObjPtr<mirror::DexCache> dex_cache_;
1864   std::vector<uint8_t> patched_code_;
1865   const ScopedAssertNoThreadSuspension no_thread_suspension_;
1866 
ReportWriteFailure(const char * what,const MethodReference & method_ref)1867   void ReportWriteFailure(const char* what, const MethodReference& method_ref) {
1868     PLOG(ERROR) << "Failed to write " << what << " for "
1869         << method_ref.PrettyMethod() << " to " << out_->GetLocation();
1870   }
1871 
GetTargetMethod(const LinkerPatch & patch)1872   ArtMethod* GetTargetMethod(const LinkerPatch& patch)
1873       REQUIRES_SHARED(Locks::mutator_lock_) {
1874     MethodReference ref = patch.TargetMethod();
1875     ObjPtr<mirror::DexCache> dex_cache =
1876         (dex_file_ == ref.dex_file) ? dex_cache_ : class_linker_->FindDexCache(
1877             Thread::Current(), *ref.dex_file);
1878     ArtMethod* method =
1879         class_linker_->LookupResolvedMethod(ref.index, dex_cache, class_loader_);
1880     CHECK(method != nullptr);
1881     return method;
1882   }
1883 
GetTargetOffset(const LinkerPatch & patch)1884   uint32_t GetTargetOffset(const LinkerPatch& patch) REQUIRES_SHARED(Locks::mutator_lock_) {
1885     uint32_t target_offset = writer_->relative_patcher_->GetOffset(patch.TargetMethod());
1886     // If there's no new compiled code, either we're compiling an app and the target method
1887     // is in the boot image, or we need to point to the correct trampoline.
1888     if (UNLIKELY(target_offset == 0)) {
1889       ArtMethod* target = GetTargetMethod(patch);
1890       DCHECK(target != nullptr);
1891       const void* oat_code_offset =
1892           target->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size_);
1893       if (oat_code_offset != nullptr) {
1894         DCHECK(!writer_->GetCompilerOptions().IsBootImage());
1895         DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickResolutionStub(oat_code_offset));
1896         DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickToInterpreterBridge(oat_code_offset));
1897         DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickGenericJniStub(oat_code_offset));
1898         target_offset = PointerToLowMemUInt32(oat_code_offset);
1899       } else {
1900         target_offset = target->IsNative()
1901             ? writer_->oat_header_->GetQuickGenericJniTrampolineOffset()
1902             : writer_->oat_header_->GetQuickToInterpreterBridgeOffset();
1903       }
1904     }
1905     return target_offset;
1906   }
1907 
GetDexCache(const DexFile * target_dex_file)1908   ObjPtr<mirror::DexCache> GetDexCache(const DexFile* target_dex_file)
1909       REQUIRES_SHARED(Locks::mutator_lock_) {
1910     return (target_dex_file == dex_file_)
1911         ? dex_cache_
1912         : class_linker_->FindDexCache(Thread::Current(), *target_dex_file);
1913   }
1914 
GetTargetType(const LinkerPatch & patch)1915   ObjPtr<mirror::Class> GetTargetType(const LinkerPatch& patch)
1916       REQUIRES_SHARED(Locks::mutator_lock_) {
1917     DCHECK(writer_->HasImage());
1918     ObjPtr<mirror::DexCache> dex_cache = GetDexCache(patch.TargetTypeDexFile());
1919     ObjPtr<mirror::Class> type =
1920         class_linker_->LookupResolvedType(patch.TargetTypeIndex(), dex_cache, class_loader_);
1921     CHECK(type != nullptr);
1922     return type;
1923   }
1924 
GetTargetString(const LinkerPatch & patch)1925   ObjPtr<mirror::String> GetTargetString(const LinkerPatch& patch)
1926       REQUIRES_SHARED(Locks::mutator_lock_) {
1927     ClassLinker* linker = Runtime::Current()->GetClassLinker();
1928     ObjPtr<mirror::String> string =
1929         linker->LookupString(patch.TargetStringIndex(), GetDexCache(patch.TargetStringDexFile()));
1930     DCHECK(string != nullptr);
1931     DCHECK(writer_->GetCompilerOptions().IsBootImage() ||
1932            Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(string));
1933     return string;
1934   }
1935 
GetTargetIntrinsicReferenceOffset(const LinkerPatch & patch)1936   uint32_t GetTargetIntrinsicReferenceOffset(const LinkerPatch& patch)
1937       REQUIRES_SHARED(Locks::mutator_lock_) {
1938     DCHECK(writer_->GetCompilerOptions().IsBootImage());
1939     const void* address =
1940         writer_->image_writer_->GetIntrinsicReferenceAddress(patch.IntrinsicData());
1941     size_t oat_index = writer_->image_writer_->GetOatIndexForDexFile(dex_file_);
1942     uintptr_t oat_data_begin = writer_->image_writer_->GetOatDataBegin(oat_index);
1943     // TODO: Clean up offset types. The target offset must be treated as signed.
1944     return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(address) - oat_data_begin);
1945   }
1946 
GetTargetMethodOffset(ArtMethod * method)1947   uint32_t GetTargetMethodOffset(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) {
1948     DCHECK(writer_->GetCompilerOptions().IsBootImage());
1949     method = writer_->image_writer_->GetImageMethodAddress(method);
1950     size_t oat_index = writer_->image_writer_->GetOatIndexForDexFile(dex_file_);
1951     uintptr_t oat_data_begin = writer_->image_writer_->GetOatDataBegin(oat_index);
1952     // TODO: Clean up offset types. The target offset must be treated as signed.
1953     return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(method) - oat_data_begin);
1954   }
1955 
GetTargetObjectOffset(ObjPtr<mirror::Object> object)1956   uint32_t GetTargetObjectOffset(ObjPtr<mirror::Object> object)
1957       REQUIRES_SHARED(Locks::mutator_lock_) {
1958     DCHECK(writer_->GetCompilerOptions().IsBootImage());
1959     object = writer_->image_writer_->GetImageAddress(object.Ptr());
1960     size_t oat_index = writer_->image_writer_->GetOatIndexForDexFile(dex_file_);
1961     uintptr_t oat_data_begin = writer_->image_writer_->GetOatDataBegin(oat_index);
1962     // TODO: Clean up offset types. The target offset must be treated as signed.
1963     return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(object.Ptr()) - oat_data_begin);
1964   }
1965 
PatchObjectAddress(std::vector<uint8_t> * code,uint32_t offset,mirror::Object * object)1966   void PatchObjectAddress(std::vector<uint8_t>* code, uint32_t offset, mirror::Object* object)
1967       REQUIRES_SHARED(Locks::mutator_lock_) {
1968     if (writer_->GetCompilerOptions().IsBootImage()) {
1969       object = writer_->image_writer_->GetImageAddress(object);
1970     } else {
1971       // NOTE: We're using linker patches for app->boot references when the image can
1972       // be relocated and therefore we need to emit .oat_patches. We're not using this
1973       // for app->app references, so check that the object is in the image space.
1974       DCHECK(Runtime::Current()->GetHeap()->FindSpaceFromObject(object, false)->IsImageSpace());
1975     }
1976     // Note: We only patch targeting Objects in image which is in the low 4gb.
1977     uint32_t address = PointerToLowMemUInt32(object);
1978     DCHECK_LE(offset + 4, code->size());
1979     uint8_t* data = &(*code)[offset];
1980     data[0] = address & 0xffu;
1981     data[1] = (address >> 8) & 0xffu;
1982     data[2] = (address >> 16) & 0xffu;
1983     data[3] = (address >> 24) & 0xffu;
1984   }
1985 };
1986 
1987 // Visit all methods from all classes in all dex files with the specified visitor.
VisitDexMethods(DexMethodVisitor * visitor)1988 bool OatWriter::VisitDexMethods(DexMethodVisitor* visitor) {
1989   for (const DexFile* dex_file : *dex_files_) {
1990     for (ClassAccessor accessor : dex_file->GetClasses()) {
1991       if (UNLIKELY(!visitor->StartClass(dex_file, accessor.GetClassDefIndex()))) {
1992         return false;
1993       }
1994       if (MayHaveCompiledMethods()) {
1995         size_t class_def_method_index = 0u;
1996         for (const ClassAccessor::Method& method : accessor.GetMethods()) {
1997           if (!visitor->VisitMethod(class_def_method_index, method)) {
1998             return false;
1999           }
2000           ++class_def_method_index;
2001         }
2002       }
2003       if (UNLIKELY(!visitor->EndClass())) {
2004         return false;
2005       }
2006     }
2007   }
2008   return true;
2009 }
2010 
InitOatHeader(uint32_t num_dex_files,SafeMap<std::string,std::string> * key_value_store)2011 size_t OatWriter::InitOatHeader(uint32_t num_dex_files,
2012                                 SafeMap<std::string, std::string>* key_value_store) {
2013   TimingLogger::ScopedTiming split("InitOatHeader", timings_);
2014   // Check that oat version when runtime was compiled matches the oat version
2015   // when dex2oat was compiled. We have seen cases where they got out of sync.
2016   constexpr std::array<uint8_t, 4> dex2oat_oat_version = OatHeader::kOatVersion;
2017   OatHeader::CheckOatVersion(dex2oat_oat_version);
2018   oat_header_.reset(OatHeader::Create(GetCompilerOptions().GetInstructionSet(),
2019                                       GetCompilerOptions().GetInstructionSetFeatures(),
2020                                       num_dex_files,
2021                                       key_value_store));
2022   size_oat_header_ += sizeof(OatHeader);
2023   size_oat_header_key_value_store_ += oat_header_->GetHeaderSize() - sizeof(OatHeader);
2024   return oat_header_->GetHeaderSize();
2025 }
2026 
InitClassOffsets(size_t offset)2027 size_t OatWriter::InitClassOffsets(size_t offset) {
2028   // Reserve space for class offsets in OAT and update class_offsets_offset_.
2029   for (OatDexFile& oat_dex_file : oat_dex_files_) {
2030     DCHECK_EQ(oat_dex_file.class_offsets_offset_, 0u);
2031     if (!oat_dex_file.class_offsets_.empty()) {
2032       // Class offsets are required to be 4 byte aligned.
2033       offset = RoundUp(offset, 4u);
2034       oat_dex_file.class_offsets_offset_ = offset;
2035       offset += oat_dex_file.GetClassOffsetsRawSize();
2036       DCHECK_ALIGNED(offset, 4u);
2037     }
2038   }
2039   return offset;
2040 }
2041 
InitOatClasses(size_t offset)2042 size_t OatWriter::InitOatClasses(size_t offset) {
2043   // calculate the offsets within OatDexFiles to OatClasses
2044   InitOatClassesMethodVisitor visitor(this, offset);
2045   bool success = VisitDexMethods(&visitor);
2046   CHECK(success);
2047   offset = visitor.GetOffset();
2048 
2049   // Update oat_dex_files_.
2050   auto oat_class_it = oat_class_headers_.begin();
2051   for (OatDexFile& oat_dex_file : oat_dex_files_) {
2052     for (uint32_t& class_offset : oat_dex_file.class_offsets_) {
2053       DCHECK(oat_class_it != oat_class_headers_.end());
2054       class_offset = oat_class_it->offset_;
2055       ++oat_class_it;
2056     }
2057   }
2058   CHECK(oat_class_it == oat_class_headers_.end());
2059 
2060   return offset;
2061 }
2062 
InitOatMaps(size_t offset)2063 size_t OatWriter::InitOatMaps(size_t offset) {
2064   if (!MayHaveCompiledMethods()) {
2065     return offset;
2066   }
2067   {
2068     InitMapMethodVisitor visitor(this, offset);
2069     bool success = VisitDexMethods(&visitor);
2070     DCHECK(success);
2071     code_info_data_.shrink_to_fit();
2072     offset += code_info_data_.size();
2073   }
2074   return offset;
2075 }
2076 
2077 template <typename GetBssOffset>
CalculateNumberOfIndexBssMappingEntries(size_t number_of_indexes,size_t slot_size,const BitVector & indexes,GetBssOffset get_bss_offset)2078 static size_t CalculateNumberOfIndexBssMappingEntries(size_t number_of_indexes,
2079                                                       size_t slot_size,
2080                                                       const BitVector& indexes,
2081                                                       GetBssOffset get_bss_offset) {
2082   IndexBssMappingEncoder encoder(number_of_indexes, slot_size);
2083   size_t number_of_entries = 0u;
2084   bool first_index = true;
2085   for (uint32_t index : indexes.Indexes()) {
2086     uint32_t bss_offset = get_bss_offset(index);
2087     if (first_index || !encoder.TryMerge(index, bss_offset)) {
2088       encoder.Reset(index, bss_offset);
2089       ++number_of_entries;
2090       first_index = false;
2091     }
2092   }
2093   DCHECK_NE(number_of_entries, 0u);
2094   return number_of_entries;
2095 }
2096 
2097 template <typename GetBssOffset>
CalculateIndexBssMappingSize(size_t number_of_indexes,size_t slot_size,const BitVector & indexes,GetBssOffset get_bss_offset)2098 static size_t CalculateIndexBssMappingSize(size_t number_of_indexes,
2099                                            size_t slot_size,
2100                                            const BitVector& indexes,
2101                                            GetBssOffset get_bss_offset) {
2102   size_t number_of_entries = CalculateNumberOfIndexBssMappingEntries(number_of_indexes,
2103                                                                      slot_size,
2104                                                                      indexes,
2105                                                                      get_bss_offset);
2106   return IndexBssMapping::ComputeSize(number_of_entries);
2107 }
2108 
InitIndexBssMappings(size_t offset)2109 size_t OatWriter::InitIndexBssMappings(size_t offset) {
2110   if (bss_method_entry_references_.empty() &&
2111       bss_type_entry_references_.empty() &&
2112       bss_string_entry_references_.empty()) {
2113     return offset;
2114   }
2115   // If there are any classes, the class offsets allocation aligns the offset
2116   // and we cannot have any index bss mappings without class offsets.
2117   static_assert(alignof(IndexBssMapping) == 4u, "IndexBssMapping alignment check.");
2118   DCHECK_ALIGNED(offset, 4u);
2119 
2120   size_t number_of_method_dex_files = 0u;
2121   size_t number_of_type_dex_files = 0u;
2122   size_t number_of_string_dex_files = 0u;
2123   PointerSize pointer_size = GetInstructionSetPointerSize(oat_header_->GetInstructionSet());
2124   for (size_t i = 0, size = dex_files_->size(); i != size; ++i) {
2125     const DexFile* dex_file = (*dex_files_)[i];
2126     auto method_it = bss_method_entry_references_.find(dex_file);
2127     if (method_it != bss_method_entry_references_.end()) {
2128       const BitVector& method_indexes = method_it->second;
2129       ++number_of_method_dex_files;
2130       oat_dex_files_[i].method_bss_mapping_offset_ = offset;
2131       offset += CalculateIndexBssMappingSize(
2132           dex_file->NumMethodIds(),
2133           static_cast<size_t>(pointer_size),
2134           method_indexes,
2135           [=](uint32_t index) {
2136             return bss_method_entries_.Get({dex_file, index});
2137           });
2138     }
2139 
2140     auto type_it = bss_type_entry_references_.find(dex_file);
2141     if (type_it != bss_type_entry_references_.end()) {
2142       const BitVector& type_indexes = type_it->second;
2143       ++number_of_type_dex_files;
2144       oat_dex_files_[i].type_bss_mapping_offset_ = offset;
2145       offset += CalculateIndexBssMappingSize(
2146           dex_file->NumTypeIds(),
2147           sizeof(GcRoot<mirror::Class>),
2148           type_indexes,
2149           [=](uint32_t index) {
2150             return bss_type_entries_.Get({dex_file, dex::TypeIndex(index)});
2151           });
2152     }
2153 
2154     auto string_it = bss_string_entry_references_.find(dex_file);
2155     if (string_it != bss_string_entry_references_.end()) {
2156       const BitVector& string_indexes = string_it->second;
2157       ++number_of_string_dex_files;
2158       oat_dex_files_[i].string_bss_mapping_offset_ = offset;
2159       offset += CalculateIndexBssMappingSize(
2160           dex_file->NumStringIds(),
2161           sizeof(GcRoot<mirror::String>),
2162           string_indexes,
2163           [=](uint32_t index) {
2164             return bss_string_entries_.Get({dex_file, dex::StringIndex(index)});
2165           });
2166     }
2167   }
2168   // Check that all dex files targeted by bss entries are in `*dex_files_`.
2169   CHECK_EQ(number_of_method_dex_files, bss_method_entry_references_.size());
2170   CHECK_EQ(number_of_type_dex_files, bss_type_entry_references_.size());
2171   CHECK_EQ(number_of_string_dex_files, bss_string_entry_references_.size());
2172   return offset;
2173 }
2174 
InitOatDexFiles(size_t offset)2175 size_t OatWriter::InitOatDexFiles(size_t offset) {
2176   // Initialize offsets of oat dex files.
2177   for (OatDexFile& oat_dex_file : oat_dex_files_) {
2178     oat_dex_file.offset_ = offset;
2179     offset += oat_dex_file.SizeOf();
2180   }
2181   return offset;
2182 }
2183 
InitOatCode(size_t offset)2184 size_t OatWriter::InitOatCode(size_t offset) {
2185   // calculate the offsets within OatHeader to executable code
2186   size_t old_offset = offset;
2187   // required to be on a new page boundary
2188   offset = RoundUp(offset, kPageSize);
2189   oat_header_->SetExecutableOffset(offset);
2190   size_executable_offset_alignment_ = offset - old_offset;
2191   if (GetCompilerOptions().IsBootImage() && primary_oat_file_) {
2192     InstructionSet instruction_set = compiler_options_.GetInstructionSet();
2193     const bool generate_debug_info = GetCompilerOptions().GenerateAnyDebugInfo();
2194     size_t adjusted_offset = offset;
2195 
2196     #define DO_TRAMPOLINE(field, fn_name)                                   \
2197       offset = CompiledCode::AlignCode(offset, instruction_set);            \
2198       adjusted_offset = offset + CompiledCode::CodeDelta(instruction_set);  \
2199       oat_header_->Set ## fn_name ## Offset(adjusted_offset);               \
2200       (field) = compiler_driver_->Create ## fn_name();                      \
2201       if (generate_debug_info) {                                            \
2202         debug::MethodDebugInfo info = {};                                   \
2203         info.custom_name = #fn_name;                                        \
2204         info.isa = instruction_set;                                         \
2205         info.is_code_address_text_relative = true;                          \
2206         /* Use the code offset rather than the `adjusted_offset`. */        \
2207         info.code_address = offset - oat_header_->GetExecutableOffset();    \
2208         info.code_size = (field)->size();                                   \
2209         method_info_.push_back(std::move(info));                            \
2210       }                                                                     \
2211       offset += (field)->size();
2212 
2213     DO_TRAMPOLINE(jni_dlsym_lookup_, JniDlsymLookup);
2214     DO_TRAMPOLINE(quick_generic_jni_trampoline_, QuickGenericJniTrampoline);
2215     DO_TRAMPOLINE(quick_imt_conflict_trampoline_, QuickImtConflictTrampoline);
2216     DO_TRAMPOLINE(quick_resolution_trampoline_, QuickResolutionTrampoline);
2217     DO_TRAMPOLINE(quick_to_interpreter_bridge_, QuickToInterpreterBridge);
2218 
2219     #undef DO_TRAMPOLINE
2220   } else {
2221     oat_header_->SetJniDlsymLookupOffset(0);
2222     oat_header_->SetQuickGenericJniTrampolineOffset(0);
2223     oat_header_->SetQuickImtConflictTrampolineOffset(0);
2224     oat_header_->SetQuickResolutionTrampolineOffset(0);
2225     oat_header_->SetQuickToInterpreterBridgeOffset(0);
2226   }
2227   return offset;
2228 }
2229 
InitOatCodeDexFiles(size_t offset)2230 size_t OatWriter::InitOatCodeDexFiles(size_t offset) {
2231   if (!GetCompilerOptions().IsAnyCompilationEnabled()) {
2232     if (kOatWriterDebugOatCodeLayout) {
2233       LOG(INFO) << "InitOatCodeDexFiles: OatWriter("
2234                 << this << "), "
2235                 << "compilation is disabled";
2236     }
2237 
2238     return offset;
2239   }
2240   bool success = false;
2241 
2242   {
2243     ScopedObjectAccess soa(Thread::Current());
2244 
2245     LayoutCodeMethodVisitor layout_code_visitor(this, offset);
2246     success = VisitDexMethods(&layout_code_visitor);
2247     DCHECK(success);
2248 
2249     LayoutReserveOffsetCodeMethodVisitor layout_reserve_code_visitor(
2250         this,
2251         offset,
2252         layout_code_visitor.ReleaseOrderedMethods());
2253     success = layout_reserve_code_visitor.Visit();
2254     DCHECK(success);
2255     offset = layout_reserve_code_visitor.GetOffset();
2256 
2257     // Save the method order because the WriteCodeMethodVisitor will need this
2258     // order again.
2259     DCHECK(ordered_methods_ == nullptr);
2260     ordered_methods_.reset(
2261         new OrderedMethodList(
2262             layout_reserve_code_visitor.ReleaseOrderedMethods()));
2263 
2264     if (kOatWriterDebugOatCodeLayout) {
2265       LOG(INFO) << "IniatOatCodeDexFiles: method order: ";
2266       for (const OrderedMethodData& ordered_method : *ordered_methods_) {
2267         std::string pretty_name = ordered_method.method_reference.PrettyMethod();
2268         LOG(INFO) << pretty_name
2269                   << "@ offset "
2270                   << relative_patcher_->GetOffset(ordered_method.method_reference)
2271                   << " X hotness "
2272                   << reinterpret_cast<void*>(ordered_method.method_hotness.GetFlags());
2273       }
2274     }
2275   }
2276 
2277   if (HasImage()) {
2278     ScopedAssertNoThreadSuspension sants("Init image method visitor", Thread::Current());
2279     InitImageMethodVisitor image_visitor(this, offset, dex_files_);
2280     success = VisitDexMethods(&image_visitor);
2281     image_visitor.Postprocess();
2282     DCHECK(success);
2283     offset = image_visitor.GetOffset();
2284   }
2285 
2286   return offset;
2287 }
2288 
InitDataBimgRelRoLayout(size_t offset)2289 size_t OatWriter::InitDataBimgRelRoLayout(size_t offset) {
2290   DCHECK_EQ(data_bimg_rel_ro_size_, 0u);
2291   if (data_bimg_rel_ro_entries_.empty()) {
2292     // Nothing to put to the .data.bimg.rel.ro section.
2293     return offset;
2294   }
2295 
2296   data_bimg_rel_ro_start_ = RoundUp(offset, kPageSize);
2297 
2298   for (auto& entry : data_bimg_rel_ro_entries_) {
2299     size_t& entry_offset = entry.second;
2300     entry_offset = data_bimg_rel_ro_size_;
2301     data_bimg_rel_ro_size_ += sizeof(uint32_t);
2302   }
2303 
2304   offset = data_bimg_rel_ro_start_ + data_bimg_rel_ro_size_;
2305   return offset;
2306 }
2307 
InitBssLayout(InstructionSet instruction_set)2308 void OatWriter::InitBssLayout(InstructionSet instruction_set) {
2309   {
2310     InitBssLayoutMethodVisitor visitor(this);
2311     bool success = VisitDexMethods(&visitor);
2312     DCHECK(success);
2313   }
2314 
2315   DCHECK_EQ(bss_size_, 0u);
2316   if (bss_method_entries_.empty() &&
2317       bss_type_entries_.empty() &&
2318       bss_string_entries_.empty()) {
2319     // Nothing to put to the .bss section.
2320     return;
2321   }
2322 
2323   PointerSize pointer_size = GetInstructionSetPointerSize(instruction_set);
2324   bss_methods_offset_ = bss_size_;
2325 
2326   // Prepare offsets for .bss ArtMethod entries.
2327   for (auto& entry : bss_method_entries_) {
2328     DCHECK_EQ(entry.second, 0u);
2329     entry.second = bss_size_;
2330     bss_size_ += static_cast<size_t>(pointer_size);
2331   }
2332 
2333   bss_roots_offset_ = bss_size_;
2334 
2335   // Prepare offsets for .bss Class entries.
2336   for (auto& entry : bss_type_entries_) {
2337     DCHECK_EQ(entry.second, 0u);
2338     entry.second = bss_size_;
2339     bss_size_ += sizeof(GcRoot<mirror::Class>);
2340   }
2341   // Prepare offsets for .bss String entries.
2342   for (auto& entry : bss_string_entries_) {
2343     DCHECK_EQ(entry.second, 0u);
2344     entry.second = bss_size_;
2345     bss_size_ += sizeof(GcRoot<mirror::String>);
2346   }
2347 }
2348 
WriteRodata(OutputStream * out)2349 bool OatWriter::WriteRodata(OutputStream* out) {
2350   CHECK(write_state_ == WriteState::kWriteRoData);
2351 
2352   size_t file_offset = oat_data_offset_;
2353   off_t current_offset = out->Seek(0, kSeekCurrent);
2354   if (current_offset == static_cast<off_t>(-1)) {
2355     PLOG(ERROR) << "Failed to retrieve current position in " << out->GetLocation();
2356   }
2357   DCHECK_GE(static_cast<size_t>(current_offset), file_offset + oat_header_->GetHeaderSize());
2358   size_t relative_offset = current_offset - file_offset;
2359 
2360   // Wrap out to update checksum with each write.
2361   ChecksumUpdatingOutputStream checksum_updating_out(out, this);
2362   out = &checksum_updating_out;
2363 
2364   relative_offset = WriteClassOffsets(out, file_offset, relative_offset);
2365   if (relative_offset == 0) {
2366     PLOG(ERROR) << "Failed to write class offsets to " << out->GetLocation();
2367     return false;
2368   }
2369 
2370   relative_offset = WriteClasses(out, file_offset, relative_offset);
2371   if (relative_offset == 0) {
2372     PLOG(ERROR) << "Failed to write classes to " << out->GetLocation();
2373     return false;
2374   }
2375 
2376   relative_offset = WriteIndexBssMappings(out, file_offset, relative_offset);
2377   if (relative_offset == 0) {
2378     PLOG(ERROR) << "Failed to write method bss mappings to " << out->GetLocation();
2379     return false;
2380   }
2381 
2382   relative_offset = WriteMaps(out, file_offset, relative_offset);
2383   if (relative_offset == 0) {
2384     PLOG(ERROR) << "Failed to write oat code to " << out->GetLocation();
2385     return false;
2386   }
2387 
2388   relative_offset = WriteOatDexFiles(out, file_offset, relative_offset);
2389   if (relative_offset == 0) {
2390     PLOG(ERROR) << "Failed to write oat dex information to " << out->GetLocation();
2391     return false;
2392   }
2393 
2394   // Write padding.
2395   off_t new_offset = out->Seek(size_executable_offset_alignment_, kSeekCurrent);
2396   relative_offset += size_executable_offset_alignment_;
2397   DCHECK_EQ(relative_offset, oat_header_->GetExecutableOffset());
2398   size_t expected_file_offset = file_offset + relative_offset;
2399   if (static_cast<uint32_t>(new_offset) != expected_file_offset) {
2400     PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
2401                 << " Expected: " << expected_file_offset << " File: " << out->GetLocation();
2402     return false;
2403   }
2404   DCHECK_OFFSET();
2405 
2406   write_state_ = WriteState::kWriteText;
2407   return true;
2408 }
2409 
2410 class OatWriter::WriteQuickeningInfoMethodVisitor {
2411  public:
WriteQuickeningInfoMethodVisitor(OatWriter * writer,OutputStream * out)2412   WriteQuickeningInfoMethodVisitor(OatWriter* writer, OutputStream* out)
2413       : writer_(writer),
2414         out_(out) {}
2415 
VisitDexMethods(const std::vector<const DexFile * > & dex_files)2416   bool VisitDexMethods(const std::vector<const DexFile*>& dex_files) {
2417     // Map of offsets for quicken info related to method indices.
2418     SafeMap<const uint8_t*, uint32_t> offset_map;
2419     // Use method index order to minimize the encoded size of the offset table.
2420     for (const DexFile* dex_file : dex_files) {
2421       std::vector<uint32_t>* const offsets =
2422           &quicken_info_offset_indices_.Put(dex_file, std::vector<uint32_t>())->second;
2423       for (uint32_t method_idx = 0; method_idx < dex_file->NumMethodIds(); ++method_idx) {
2424         uint32_t offset = 0u;
2425         MethodReference method_ref(dex_file, method_idx);
2426         CompiledMethod* compiled_method = writer_->compiler_driver_->GetCompiledMethod(method_ref);
2427         if (compiled_method != nullptr && HasQuickeningInfo(compiled_method)) {
2428           ArrayRef<const uint8_t> map = compiled_method->GetVmapTable();
2429 
2430           // Record each index if required. written_bytes_ is the offset from the start of the
2431           // quicken info data.
2432           // May be already inserted for deduplicate items.
2433           // Add offset of one to make sure 0 represents unused.
2434           auto pair = offset_map.emplace(map.data(), written_bytes_ + 1);
2435           offset = pair.first->second;
2436           // Write out the map if it's not already written.
2437           if (pair.second) {
2438             const uint32_t length = map.size() * sizeof(map.front());
2439             if (!out_->WriteFully(map.data(), length)) {
2440               PLOG(ERROR) << "Failed to write quickening info for " << method_ref.PrettyMethod()
2441                           << " to " << out_->GetLocation();
2442               return false;
2443             }
2444             written_bytes_ += length;
2445           }
2446         }
2447         offsets->push_back(offset);
2448       }
2449     }
2450     return true;
2451   }
2452 
GetNumberOfWrittenBytes() const2453   size_t GetNumberOfWrittenBytes() const {
2454     return written_bytes_;
2455   }
2456 
GetQuickenInfoOffsetIndicies()2457   SafeMap<const DexFile*, std::vector<uint32_t>>& GetQuickenInfoOffsetIndicies() {
2458     return quicken_info_offset_indices_;
2459   }
2460 
2461  private:
2462   OatWriter* const writer_;
2463   OutputStream* const out_;
2464   size_t written_bytes_ = 0u;
2465   SafeMap<const DexFile*, std::vector<uint32_t>> quicken_info_offset_indices_;
2466 };
2467 
2468 class OatWriter::WriteQuickeningInfoOffsetsMethodVisitor {
2469  public:
WriteQuickeningInfoOffsetsMethodVisitor(OutputStream * out,uint32_t start_offset,SafeMap<const DexFile *,std::vector<uint32_t>> * quicken_info_offset_indices,std::vector<uint32_t> * out_table_offsets)2470   WriteQuickeningInfoOffsetsMethodVisitor(
2471       OutputStream* out,
2472       uint32_t start_offset,
2473       SafeMap<const DexFile*, std::vector<uint32_t>>* quicken_info_offset_indices,
2474       std::vector<uint32_t>* out_table_offsets)
2475       : out_(out),
2476         start_offset_(start_offset),
2477         quicken_info_offset_indices_(quicken_info_offset_indices),
2478         out_table_offsets_(out_table_offsets) {}
2479 
VisitDexMethods(const std::vector<const DexFile * > & dex_files)2480   bool VisitDexMethods(const std::vector<const DexFile*>& dex_files) {
2481     for (const DexFile* dex_file : dex_files) {
2482       auto it = quicken_info_offset_indices_->find(dex_file);
2483       DCHECK(it != quicken_info_offset_indices_->end()) << "Failed to find dex file "
2484                                                         << dex_file->GetLocation();
2485       const std::vector<uint32_t>* const offsets = &it->second;
2486 
2487       const uint32_t current_offset = start_offset_ + written_bytes_;
2488       CHECK_ALIGNED_PARAM(current_offset, CompactOffsetTable::kAlignment);
2489 
2490       // Generate and write the data.
2491       std::vector<uint8_t> table_data;
2492       CompactOffsetTable::Build(*offsets, &table_data);
2493 
2494       // Store the offset since we need to put those after the dex file. Table offsets are relative
2495       // to the start of the quicken info section.
2496       out_table_offsets_->push_back(current_offset);
2497 
2498       const uint32_t length = table_data.size() * sizeof(table_data.front());
2499       if (!out_->WriteFully(table_data.data(), length)) {
2500         PLOG(ERROR) << "Failed to write quickening offset table for " << dex_file->GetLocation()
2501                     << " to " << out_->GetLocation();
2502         return false;
2503       }
2504       written_bytes_ += length;
2505     }
2506     return true;
2507   }
2508 
GetNumberOfWrittenBytes() const2509   size_t GetNumberOfWrittenBytes() const {
2510     return written_bytes_;
2511   }
2512 
2513  private:
2514   OutputStream* const out_;
2515   const uint32_t start_offset_;
2516   size_t written_bytes_ = 0u;
2517   // Maps containing the offsets for the tables.
2518   SafeMap<const DexFile*, std::vector<uint32_t>>* const quicken_info_offset_indices_;
2519   std::vector<uint32_t>* const out_table_offsets_;
2520 };
2521 
WriteQuickeningInfo(OutputStream * vdex_out)2522 bool OatWriter::WriteQuickeningInfo(OutputStream* vdex_out) {
2523   if (!extract_dex_files_into_vdex_) {
2524     // Nothing to write. Leave `vdex_size_` untouched and unaligned.
2525     vdex_quickening_info_offset_ = vdex_size_;
2526     size_quickening_info_alignment_ = 0;
2527     return true;
2528   }
2529   size_t initial_offset = vdex_size_;
2530   // Make sure the table is properly aligned.
2531   size_t start_offset = RoundUp(initial_offset, 4u);
2532 
2533   off_t actual_offset = vdex_out->Seek(start_offset, kSeekSet);
2534   if (actual_offset != static_cast<off_t>(start_offset)) {
2535     PLOG(ERROR) << "Failed to seek to quickening info section. Actual: " << actual_offset
2536                 << " Expected: " << start_offset
2537                 << " Output: " << vdex_out->GetLocation();
2538     return false;
2539   }
2540 
2541   size_t current_offset = start_offset;
2542   if (GetCompilerOptions().IsQuickeningCompilationEnabled()) {
2543     std::vector<uint32_t> dex_files_indices;
2544     WriteQuickeningInfoMethodVisitor write_quicken_info_visitor(this, vdex_out);
2545     if (!write_quicken_info_visitor.VisitDexMethods(*dex_files_)) {
2546       PLOG(ERROR) << "Failed to write the vdex quickening info. File: " << vdex_out->GetLocation();
2547       return false;
2548     }
2549 
2550     uint32_t quicken_info_offset = write_quicken_info_visitor.GetNumberOfWrittenBytes();
2551     current_offset = current_offset + quicken_info_offset;
2552     uint32_t before_offset = current_offset;
2553     current_offset = RoundUp(current_offset, CompactOffsetTable::kAlignment);
2554     const size_t extra_bytes = current_offset - before_offset;
2555     quicken_info_offset += extra_bytes;
2556     actual_offset = vdex_out->Seek(current_offset, kSeekSet);
2557     if (actual_offset != static_cast<off_t>(current_offset)) {
2558       PLOG(ERROR) << "Failed to seek to quickening offset table section. Actual: " << actual_offset
2559                   << " Expected: " << current_offset
2560                   << " Output: " << vdex_out->GetLocation();
2561       return false;
2562     }
2563 
2564     std::vector<uint32_t> table_offsets;
2565     WriteQuickeningInfoOffsetsMethodVisitor table_visitor(
2566         vdex_out,
2567         quicken_info_offset,
2568         &write_quicken_info_visitor.GetQuickenInfoOffsetIndicies(),
2569         /*out*/ &table_offsets);
2570     if (!table_visitor.VisitDexMethods(*dex_files_)) {
2571       PLOG(ERROR) << "Failed to write the vdex quickening info. File: "
2572                   << vdex_out->GetLocation();
2573       return false;
2574     }
2575 
2576     CHECK_EQ(table_offsets.size(), dex_files_->size());
2577 
2578     current_offset += table_visitor.GetNumberOfWrittenBytes();
2579 
2580     // Store the offset table offset as a preheader for each dex.
2581     size_t index = 0;
2582     for (const OatDexFile& oat_dex_file : oat_dex_files_) {
2583       const off_t desired_offset = oat_dex_file.dex_file_offset_ -
2584           sizeof(VdexFile::QuickeningTableOffsetType);
2585       actual_offset = vdex_out->Seek(desired_offset, kSeekSet);
2586       if (actual_offset != desired_offset) {
2587         PLOG(ERROR) << "Failed to seek to before dex file for writing offset table offset: "
2588                     << actual_offset << " Expected: " << desired_offset
2589                     << " Output: " << vdex_out->GetLocation();
2590         return false;
2591       }
2592       uint32_t offset = table_offsets[index];
2593       if (!vdex_out->WriteFully(reinterpret_cast<const uint8_t*>(&offset), sizeof(offset))) {
2594         PLOG(ERROR) << "Failed to write verifier deps."
2595                     << " File: " << vdex_out->GetLocation();
2596         return false;
2597       }
2598       ++index;
2599     }
2600     if (!vdex_out->Flush()) {
2601       PLOG(ERROR) << "Failed to flush stream after writing quickening info."
2602                   << " File: " << vdex_out->GetLocation();
2603       return false;
2604     }
2605     size_quickening_info_ = current_offset - start_offset;
2606   } else {
2607     // We know we did not quicken.
2608     size_quickening_info_ = 0;
2609   }
2610 
2611   if (size_quickening_info_ == 0) {
2612     // Nothing was written. Leave `vdex_size_` untouched and unaligned.
2613     vdex_quickening_info_offset_ = initial_offset;
2614     size_quickening_info_alignment_ = 0;
2615   } else {
2616     vdex_size_ = start_offset + size_quickening_info_;
2617     vdex_quickening_info_offset_ = start_offset;
2618     size_quickening_info_alignment_ = start_offset - initial_offset;
2619   }
2620 
2621   return true;
2622 }
2623 
WriteVerifierDeps(OutputStream * vdex_out,verifier::VerifierDeps * verifier_deps)2624 bool OatWriter::WriteVerifierDeps(OutputStream* vdex_out, verifier::VerifierDeps* verifier_deps) {
2625   if (verifier_deps == nullptr) {
2626     // Nothing to write. Record the offset, but no need
2627     // for alignment.
2628     vdex_verifier_deps_offset_ = vdex_size_;
2629     return true;
2630   }
2631 
2632   size_t initial_offset = vdex_size_;
2633   size_t start_offset = RoundUp(initial_offset, 4u);
2634 
2635   vdex_size_ = start_offset;
2636   vdex_verifier_deps_offset_ = vdex_size_;
2637   size_verifier_deps_alignment_ = start_offset - initial_offset;
2638 
2639   off_t actual_offset = vdex_out->Seek(start_offset, kSeekSet);
2640   if (actual_offset != static_cast<off_t>(start_offset)) {
2641     PLOG(ERROR) << "Failed to seek to verifier deps section. Actual: " << actual_offset
2642                 << " Expected: " << start_offset
2643                 << " Output: " << vdex_out->GetLocation();
2644     return false;
2645   }
2646 
2647   std::vector<uint8_t> buffer;
2648   verifier_deps->Encode(*dex_files_, &buffer);
2649 
2650   if (!vdex_out->WriteFully(buffer.data(), buffer.size())) {
2651     PLOG(ERROR) << "Failed to write verifier deps."
2652                 << " File: " << vdex_out->GetLocation();
2653     return false;
2654   }
2655   if (!vdex_out->Flush()) {
2656     PLOG(ERROR) << "Failed to flush stream after writing verifier deps."
2657                 << " File: " << vdex_out->GetLocation();
2658     return false;
2659   }
2660 
2661   size_verifier_deps_ = buffer.size();
2662   vdex_size_ += size_verifier_deps_;
2663   return true;
2664 }
2665 
WriteCode(OutputStream * out)2666 bool OatWriter::WriteCode(OutputStream* out) {
2667   CHECK(write_state_ == WriteState::kWriteText);
2668 
2669   // Wrap out to update checksum with each write.
2670   ChecksumUpdatingOutputStream checksum_updating_out(out, this);
2671   out = &checksum_updating_out;
2672 
2673   SetMultiOatRelativePatcherAdjustment();
2674 
2675   const size_t file_offset = oat_data_offset_;
2676   size_t relative_offset = oat_header_->GetExecutableOffset();
2677   DCHECK_OFFSET();
2678 
2679   relative_offset = WriteCode(out, file_offset, relative_offset);
2680   if (relative_offset == 0) {
2681     LOG(ERROR) << "Failed to write oat code to " << out->GetLocation();
2682     return false;
2683   }
2684 
2685   relative_offset = WriteCodeDexFiles(out, file_offset, relative_offset);
2686   if (relative_offset == 0) {
2687     LOG(ERROR) << "Failed to write oat code for dex files to " << out->GetLocation();
2688     return false;
2689   }
2690 
2691   if (data_bimg_rel_ro_size_ != 0u) {
2692     write_state_ = WriteState::kWriteDataBimgRelRo;
2693   } else {
2694     if (!CheckOatSize(out, file_offset, relative_offset)) {
2695       return false;
2696     }
2697     write_state_ = WriteState::kWriteHeader;
2698   }
2699   return true;
2700 }
2701 
WriteDataBimgRelRo(OutputStream * out)2702 bool OatWriter::WriteDataBimgRelRo(OutputStream* out) {
2703   CHECK(write_state_ == WriteState::kWriteDataBimgRelRo);
2704 
2705   // Wrap out to update checksum with each write.
2706   ChecksumUpdatingOutputStream checksum_updating_out(out, this);
2707   out = &checksum_updating_out;
2708 
2709   const size_t file_offset = oat_data_offset_;
2710   size_t relative_offset = data_bimg_rel_ro_start_;
2711 
2712   // Record the padding before the .data.bimg.rel.ro section.
2713   // Do not write anything, this zero-filled part was skipped (Seek()) when starting the section.
2714   size_t code_end = GetOatHeader().GetExecutableOffset() + code_size_;
2715   DCHECK_EQ(RoundUp(code_end, kPageSize), relative_offset);
2716   size_t padding_size = relative_offset - code_end;
2717   DCHECK_EQ(size_data_bimg_rel_ro_alignment_, 0u);
2718   size_data_bimg_rel_ro_alignment_ = padding_size;
2719 
2720   relative_offset = WriteDataBimgRelRo(out, file_offset, relative_offset);
2721   if (relative_offset == 0) {
2722     LOG(ERROR) << "Failed to write boot image relocations to " << out->GetLocation();
2723     return false;
2724   }
2725 
2726   if (!CheckOatSize(out, file_offset, relative_offset)) {
2727     return false;
2728   }
2729   write_state_ = WriteState::kWriteHeader;
2730   return true;
2731 }
2732 
CheckOatSize(OutputStream * out,size_t file_offset,size_t relative_offset)2733 bool OatWriter::CheckOatSize(OutputStream* out, size_t file_offset, size_t relative_offset) {
2734   const off_t oat_end_file_offset = out->Seek(0, kSeekCurrent);
2735   if (oat_end_file_offset == static_cast<off_t>(-1)) {
2736     LOG(ERROR) << "Failed to get oat end file offset in " << out->GetLocation();
2737     return false;
2738   }
2739 
2740   if (kIsDebugBuild) {
2741     uint32_t size_total = 0;
2742     #define DO_STAT(x) \
2743       VLOG(compiler) << #x "=" << PrettySize(x) << " (" << (x) << "B)"; \
2744       size_total += (x);
2745 
2746     DO_STAT(size_vdex_header_);
2747     DO_STAT(size_vdex_checksums_);
2748     DO_STAT(size_dex_file_alignment_);
2749     DO_STAT(size_executable_offset_alignment_);
2750     DO_STAT(size_oat_header_);
2751     DO_STAT(size_oat_header_key_value_store_);
2752     DO_STAT(size_dex_file_);
2753     DO_STAT(size_verifier_deps_);
2754     DO_STAT(size_verifier_deps_alignment_);
2755     DO_STAT(size_quickening_info_);
2756     DO_STAT(size_quickening_info_alignment_);
2757     DO_STAT(size_interpreter_to_interpreter_bridge_);
2758     DO_STAT(size_interpreter_to_compiled_code_bridge_);
2759     DO_STAT(size_jni_dlsym_lookup_);
2760     DO_STAT(size_quick_generic_jni_trampoline_);
2761     DO_STAT(size_quick_imt_conflict_trampoline_);
2762     DO_STAT(size_quick_resolution_trampoline_);
2763     DO_STAT(size_quick_to_interpreter_bridge_);
2764     DO_STAT(size_trampoline_alignment_);
2765     DO_STAT(size_method_header_);
2766     DO_STAT(size_code_);
2767     DO_STAT(size_code_alignment_);
2768     DO_STAT(size_data_bimg_rel_ro_);
2769     DO_STAT(size_data_bimg_rel_ro_alignment_);
2770     DO_STAT(size_relative_call_thunks_);
2771     DO_STAT(size_misc_thunks_);
2772     DO_STAT(size_vmap_table_);
2773     DO_STAT(size_method_info_);
2774     DO_STAT(size_oat_dex_file_location_size_);
2775     DO_STAT(size_oat_dex_file_location_data_);
2776     DO_STAT(size_oat_dex_file_location_checksum_);
2777     DO_STAT(size_oat_dex_file_offset_);
2778     DO_STAT(size_oat_dex_file_class_offsets_offset_);
2779     DO_STAT(size_oat_dex_file_lookup_table_offset_);
2780     DO_STAT(size_oat_dex_file_dex_layout_sections_offset_);
2781     DO_STAT(size_oat_dex_file_dex_layout_sections_);
2782     DO_STAT(size_oat_dex_file_dex_layout_sections_alignment_);
2783     DO_STAT(size_oat_dex_file_method_bss_mapping_offset_);
2784     DO_STAT(size_oat_dex_file_type_bss_mapping_offset_);
2785     DO_STAT(size_oat_dex_file_string_bss_mapping_offset_);
2786     DO_STAT(size_oat_lookup_table_alignment_);
2787     DO_STAT(size_oat_lookup_table_);
2788     DO_STAT(size_oat_class_offsets_alignment_);
2789     DO_STAT(size_oat_class_offsets_);
2790     DO_STAT(size_oat_class_type_);
2791     DO_STAT(size_oat_class_status_);
2792     DO_STAT(size_oat_class_method_bitmaps_);
2793     DO_STAT(size_oat_class_method_offsets_);
2794     DO_STAT(size_method_bss_mappings_);
2795     DO_STAT(size_type_bss_mappings_);
2796     DO_STAT(size_string_bss_mappings_);
2797     #undef DO_STAT
2798 
2799     VLOG(compiler) << "size_total=" << PrettySize(size_total) << " (" << size_total << "B)";
2800 
2801     CHECK_EQ(vdex_size_ + oat_size_, size_total);
2802     CHECK_EQ(file_offset + size_total - vdex_size_, static_cast<size_t>(oat_end_file_offset));
2803   }
2804 
2805   CHECK_EQ(file_offset + oat_size_, static_cast<size_t>(oat_end_file_offset));
2806   CHECK_EQ(oat_size_, relative_offset);
2807 
2808   write_state_ = WriteState::kWriteHeader;
2809   return true;
2810 }
2811 
WriteHeader(OutputStream * out)2812 bool OatWriter::WriteHeader(OutputStream* out) {
2813   CHECK(write_state_ == WriteState::kWriteHeader);
2814 
2815   // Update checksum with header data.
2816   DCHECK_EQ(oat_header_->GetChecksum(), 0u);  // For checksum calculation.
2817   const uint8_t* header_begin = reinterpret_cast<const uint8_t*>(oat_header_.get());
2818   const uint8_t* header_end = oat_header_->GetKeyValueStore() + oat_header_->GetKeyValueStoreSize();
2819   uint32_t old_checksum = oat_checksum_;
2820   oat_checksum_ = adler32(old_checksum, header_begin, header_end - header_begin);
2821   oat_header_->SetChecksum(oat_checksum_);
2822 
2823   const size_t file_offset = oat_data_offset_;
2824 
2825   off_t current_offset = out->Seek(0, kSeekCurrent);
2826   if (current_offset == static_cast<off_t>(-1)) {
2827     PLOG(ERROR) << "Failed to get current offset from " << out->GetLocation();
2828     return false;
2829   }
2830   if (out->Seek(file_offset, kSeekSet) == static_cast<off_t>(-1)) {
2831     PLOG(ERROR) << "Failed to seek to oat header position in " << out->GetLocation();
2832     return false;
2833   }
2834   DCHECK_EQ(file_offset, static_cast<size_t>(out->Seek(0, kSeekCurrent)));
2835 
2836   // Flush all other data before writing the header.
2837   if (!out->Flush()) {
2838     PLOG(ERROR) << "Failed to flush before writing oat header to " << out->GetLocation();
2839     return false;
2840   }
2841   // Write the header.
2842   size_t header_size = oat_header_->GetHeaderSize();
2843   if (!out->WriteFully(oat_header_.get(), header_size)) {
2844     PLOG(ERROR) << "Failed to write oat header to " << out->GetLocation();
2845     return false;
2846   }
2847   // Flush the header data.
2848   if (!out->Flush()) {
2849     PLOG(ERROR) << "Failed to flush after writing oat header to " << out->GetLocation();
2850     return false;
2851   }
2852 
2853   if (out->Seek(current_offset, kSeekSet) == static_cast<off_t>(-1)) {
2854     PLOG(ERROR) << "Failed to seek back after writing oat header to " << out->GetLocation();
2855     return false;
2856   }
2857   DCHECK_EQ(current_offset, out->Seek(0, kSeekCurrent));
2858 
2859   write_state_ = WriteState::kDone;
2860   return true;
2861 }
2862 
WriteClassOffsets(OutputStream * out,size_t file_offset,size_t relative_offset)2863 size_t OatWriter::WriteClassOffsets(OutputStream* out, size_t file_offset, size_t relative_offset) {
2864   for (OatDexFile& oat_dex_file : oat_dex_files_) {
2865     if (oat_dex_file.class_offsets_offset_ != 0u) {
2866       // Class offsets are required to be 4 byte aligned.
2867       if (UNLIKELY(!IsAligned<4u>(relative_offset))) {
2868         size_t padding_size =  RoundUp(relative_offset, 4u) - relative_offset;
2869         if (!WriteUpTo16BytesAlignment(out, padding_size, &size_oat_class_offsets_alignment_)) {
2870           return 0u;
2871         }
2872         relative_offset += padding_size;
2873       }
2874       DCHECK_OFFSET();
2875       if (!oat_dex_file.WriteClassOffsets(this, out)) {
2876         return 0u;
2877       }
2878       relative_offset += oat_dex_file.GetClassOffsetsRawSize();
2879     }
2880   }
2881   return relative_offset;
2882 }
2883 
WriteClasses(OutputStream * out,size_t file_offset,size_t relative_offset)2884 size_t OatWriter::WriteClasses(OutputStream* out, size_t file_offset, size_t relative_offset) {
2885   const bool may_have_compiled = MayHaveCompiledMethods();
2886   if (may_have_compiled) {
2887     CHECK_EQ(oat_class_headers_.size(), oat_classes_.size());
2888   }
2889   for (size_t i = 0; i < oat_class_headers_.size(); ++i) {
2890     // If there are any classes, the class offsets allocation aligns the offset.
2891     DCHECK_ALIGNED(relative_offset, 4u);
2892     DCHECK_OFFSET();
2893     if (!oat_class_headers_[i].Write(this, out, oat_data_offset_)) {
2894       return 0u;
2895     }
2896     relative_offset += oat_class_headers_[i].SizeOf();
2897     if (may_have_compiled) {
2898       if (!oat_classes_[i].Write(this, out)) {
2899         return 0u;
2900       }
2901       relative_offset += oat_classes_[i].SizeOf();
2902     }
2903   }
2904   return relative_offset;
2905 }
2906 
WriteMaps(OutputStream * out,size_t file_offset,size_t relative_offset)2907 size_t OatWriter::WriteMaps(OutputStream* out, size_t file_offset, size_t relative_offset) {
2908   {
2909     if (UNLIKELY(!out->WriteFully(code_info_data_.data(), code_info_data_.size()))) {
2910       return 0;
2911     }
2912     relative_offset += code_info_data_.size();
2913     size_vmap_table_ = code_info_data_.size();
2914     DCHECK_OFFSET();
2915   }
2916 
2917   return relative_offset;
2918 }
2919 
2920 
2921 template <typename GetBssOffset>
WriteIndexBssMapping(OutputStream * out,size_t number_of_indexes,size_t slot_size,const BitVector & indexes,GetBssOffset get_bss_offset)2922 size_t WriteIndexBssMapping(OutputStream* out,
2923                             size_t number_of_indexes,
2924                             size_t slot_size,
2925                             const BitVector& indexes,
2926                             GetBssOffset get_bss_offset) {
2927   // Allocate the IndexBssMapping.
2928   size_t number_of_entries = CalculateNumberOfIndexBssMappingEntries(
2929       number_of_indexes, slot_size, indexes, get_bss_offset);
2930   size_t mappings_size = IndexBssMapping::ComputeSize(number_of_entries);
2931   DCHECK_ALIGNED(mappings_size, sizeof(uint32_t));
2932   std::unique_ptr<uint32_t[]> storage(new uint32_t[mappings_size / sizeof(uint32_t)]);
2933   IndexBssMapping* mappings = new(storage.get()) IndexBssMapping(number_of_entries);
2934   mappings->ClearPadding();
2935   // Encode the IndexBssMapping.
2936   IndexBssMappingEncoder encoder(number_of_indexes, slot_size);
2937   auto init_it = mappings->begin();
2938   bool first_index = true;
2939   for (uint32_t index : indexes.Indexes()) {
2940     size_t bss_offset = get_bss_offset(index);
2941     if (first_index) {
2942       first_index = false;
2943       encoder.Reset(index, bss_offset);
2944     } else if (!encoder.TryMerge(index, bss_offset)) {
2945       *init_it = encoder.GetEntry();
2946       ++init_it;
2947       encoder.Reset(index, bss_offset);
2948     }
2949   }
2950   // Store the last entry.
2951   *init_it = encoder.GetEntry();
2952   ++init_it;
2953   DCHECK(init_it == mappings->end());
2954 
2955   if (!out->WriteFully(storage.get(), mappings_size)) {
2956     return 0u;
2957   }
2958   return mappings_size;
2959 }
2960 
WriteIndexBssMappings(OutputStream * out,size_t file_offset,size_t relative_offset)2961 size_t OatWriter::WriteIndexBssMappings(OutputStream* out,
2962                                         size_t file_offset,
2963                                         size_t relative_offset) {
2964   TimingLogger::ScopedTiming split("WriteMethodBssMappings", timings_);
2965   if (bss_method_entry_references_.empty() &&
2966       bss_type_entry_references_.empty() &&
2967       bss_string_entry_references_.empty()) {
2968     return relative_offset;
2969   }
2970   // If there are any classes, the class offsets allocation aligns the offset
2971   // and we cannot have method bss mappings without class offsets.
2972   static_assert(alignof(IndexBssMapping) == sizeof(uint32_t),
2973                 "IndexBssMapping alignment check.");
2974   DCHECK_ALIGNED(relative_offset, sizeof(uint32_t));
2975 
2976   PointerSize pointer_size = GetInstructionSetPointerSize(oat_header_->GetInstructionSet());
2977   for (size_t i = 0, size = dex_files_->size(); i != size; ++i) {
2978     const DexFile* dex_file = (*dex_files_)[i];
2979     OatDexFile* oat_dex_file = &oat_dex_files_[i];
2980     auto method_it = bss_method_entry_references_.find(dex_file);
2981     if (method_it != bss_method_entry_references_.end()) {
2982       const BitVector& method_indexes = method_it->second;
2983       DCHECK_EQ(relative_offset, oat_dex_file->method_bss_mapping_offset_);
2984       DCHECK_OFFSET();
2985       size_t method_mappings_size = WriteIndexBssMapping(
2986           out,
2987           dex_file->NumMethodIds(),
2988           static_cast<size_t>(pointer_size),
2989           method_indexes,
2990           [=](uint32_t index) {
2991             return bss_method_entries_.Get({dex_file, index});
2992           });
2993       if (method_mappings_size == 0u) {
2994         return 0u;
2995       }
2996       size_method_bss_mappings_ += method_mappings_size;
2997       relative_offset += method_mappings_size;
2998     } else {
2999       DCHECK_EQ(0u, oat_dex_file->method_bss_mapping_offset_);
3000     }
3001 
3002     auto type_it = bss_type_entry_references_.find(dex_file);
3003     if (type_it != bss_type_entry_references_.end()) {
3004       const BitVector& type_indexes = type_it->second;
3005       DCHECK_EQ(relative_offset, oat_dex_file->type_bss_mapping_offset_);
3006       DCHECK_OFFSET();
3007       size_t type_mappings_size = WriteIndexBssMapping(
3008           out,
3009           dex_file->NumTypeIds(),
3010           sizeof(GcRoot<mirror::Class>),
3011           type_indexes,
3012           [=](uint32_t index) {
3013             return bss_type_entries_.Get({dex_file, dex::TypeIndex(index)});
3014           });
3015       if (type_mappings_size == 0u) {
3016         return 0u;
3017       }
3018       size_type_bss_mappings_ += type_mappings_size;
3019       relative_offset += type_mappings_size;
3020     } else {
3021       DCHECK_EQ(0u, oat_dex_file->type_bss_mapping_offset_);
3022     }
3023 
3024     auto string_it = bss_string_entry_references_.find(dex_file);
3025     if (string_it != bss_string_entry_references_.end()) {
3026       const BitVector& string_indexes = string_it->second;
3027       DCHECK_EQ(relative_offset, oat_dex_file->string_bss_mapping_offset_);
3028       DCHECK_OFFSET();
3029       size_t string_mappings_size = WriteIndexBssMapping(
3030           out,
3031           dex_file->NumStringIds(),
3032           sizeof(GcRoot<mirror::String>),
3033           string_indexes,
3034           [=](uint32_t index) {
3035             return bss_string_entries_.Get({dex_file, dex::StringIndex(index)});
3036           });
3037       if (string_mappings_size == 0u) {
3038         return 0u;
3039       }
3040       size_string_bss_mappings_ += string_mappings_size;
3041       relative_offset += string_mappings_size;
3042     } else {
3043       DCHECK_EQ(0u, oat_dex_file->string_bss_mapping_offset_);
3044     }
3045   }
3046   return relative_offset;
3047 }
3048 
WriteOatDexFiles(OutputStream * out,size_t file_offset,size_t relative_offset)3049 size_t OatWriter::WriteOatDexFiles(OutputStream* out, size_t file_offset, size_t relative_offset) {
3050   TimingLogger::ScopedTiming split("WriteOatDexFiles", timings_);
3051 
3052   for (size_t i = 0, size = oat_dex_files_.size(); i != size; ++i) {
3053     OatDexFile* oat_dex_file = &oat_dex_files_[i];
3054     DCHECK_EQ(relative_offset, oat_dex_file->offset_);
3055     DCHECK_OFFSET();
3056 
3057     // Write OatDexFile.
3058     if (!oat_dex_file->Write(this, out)) {
3059       return 0u;
3060     }
3061     relative_offset += oat_dex_file->SizeOf();
3062   }
3063 
3064   return relative_offset;
3065 }
3066 
WriteCode(OutputStream * out,size_t file_offset,size_t relative_offset)3067 size_t OatWriter::WriteCode(OutputStream* out, size_t file_offset, size_t relative_offset) {
3068   if (GetCompilerOptions().IsBootImage() && primary_oat_file_) {
3069     InstructionSet instruction_set = compiler_options_.GetInstructionSet();
3070 
3071     #define DO_TRAMPOLINE(field) \
3072       do { \
3073         uint32_t aligned_offset = CompiledCode::AlignCode(relative_offset, instruction_set); \
3074         uint32_t alignment_padding = aligned_offset - relative_offset; \
3075         out->Seek(alignment_padding, kSeekCurrent); \
3076         size_trampoline_alignment_ += alignment_padding; \
3077         if (!out->WriteFully((field)->data(), (field)->size())) { \
3078           PLOG(ERROR) << "Failed to write " # field " to " << out->GetLocation(); \
3079           return false; \
3080         } \
3081         size_ ## field += (field)->size(); \
3082         relative_offset += alignment_padding + (field)->size(); \
3083         DCHECK_OFFSET(); \
3084       } while (false)
3085 
3086     DO_TRAMPOLINE(jni_dlsym_lookup_);
3087     DO_TRAMPOLINE(quick_generic_jni_trampoline_);
3088     DO_TRAMPOLINE(quick_imt_conflict_trampoline_);
3089     DO_TRAMPOLINE(quick_resolution_trampoline_);
3090     DO_TRAMPOLINE(quick_to_interpreter_bridge_);
3091     #undef DO_TRAMPOLINE
3092   }
3093   return relative_offset;
3094 }
3095 
WriteCodeDexFiles(OutputStream * out,size_t file_offset,size_t relative_offset)3096 size_t OatWriter::WriteCodeDexFiles(OutputStream* out,
3097                                     size_t file_offset,
3098                                     size_t relative_offset) {
3099   if (!GetCompilerOptions().IsAnyCompilationEnabled()) {
3100     // As with InitOatCodeDexFiles, also skip the writer if
3101     // compilation was disabled.
3102     if (kOatWriterDebugOatCodeLayout) {
3103       LOG(INFO) << "WriteCodeDexFiles: OatWriter("
3104                 << this << "), "
3105                 << "compilation is disabled";
3106     }
3107 
3108     return relative_offset;
3109   }
3110   ScopedObjectAccess soa(Thread::Current());
3111   DCHECK(ordered_methods_ != nullptr);
3112   std::unique_ptr<OrderedMethodList> ordered_methods_ptr =
3113       std::move(ordered_methods_);
3114   WriteCodeMethodVisitor visitor(this,
3115                                  out,
3116                                  file_offset,
3117                                  relative_offset,
3118                                  std::move(*ordered_methods_ptr));
3119   if (UNLIKELY(!visitor.Visit())) {
3120     return 0;
3121   }
3122   relative_offset = visitor.GetOffset();
3123 
3124   size_code_alignment_ += relative_patcher_->CodeAlignmentSize();
3125   size_relative_call_thunks_ += relative_patcher_->RelativeCallThunksSize();
3126   size_misc_thunks_ += relative_patcher_->MiscThunksSize();
3127 
3128   return relative_offset;
3129 }
3130 
WriteDataBimgRelRo(OutputStream * out,size_t file_offset,size_t relative_offset)3131 size_t OatWriter::WriteDataBimgRelRo(OutputStream* out,
3132                                      size_t file_offset,
3133                                      size_t relative_offset) {
3134   if (data_bimg_rel_ro_entries_.empty()) {
3135     return relative_offset;
3136   }
3137 
3138   // Write the entire .data.bimg.rel.ro with a single WriteFully().
3139   std::vector<uint32_t> data;
3140   data.reserve(data_bimg_rel_ro_entries_.size());
3141   for (const auto& entry : data_bimg_rel_ro_entries_) {
3142     uint32_t boot_image_offset = entry.first;
3143     data.push_back(boot_image_offset);
3144   }
3145   DCHECK_EQ(data.size(), data_bimg_rel_ro_entries_.size());
3146   DCHECK_OFFSET();
3147   if (!out->WriteFully(data.data(), data.size() * sizeof(data[0]))) {
3148     PLOG(ERROR) << "Failed to write .data.bimg.rel.ro in " << out->GetLocation();
3149     return 0u;
3150   }
3151   DCHECK_EQ(size_data_bimg_rel_ro_, 0u);
3152   size_data_bimg_rel_ro_ = data.size() * sizeof(data[0]);
3153   relative_offset += size_data_bimg_rel_ro_;
3154   return relative_offset;
3155 }
3156 
RecordOatDataOffset(OutputStream * out)3157 bool OatWriter::RecordOatDataOffset(OutputStream* out) {
3158   // Get the elf file offset of the oat file.
3159   const off_t raw_file_offset = out->Seek(0, kSeekCurrent);
3160   if (raw_file_offset == static_cast<off_t>(-1)) {
3161     LOG(ERROR) << "Failed to get file offset in " << out->GetLocation();
3162     return false;
3163   }
3164   oat_data_offset_ = static_cast<size_t>(raw_file_offset);
3165   return true;
3166 }
3167 
WriteDexFiles(OutputStream * out,File * file,bool update_input_vdex,CopyOption copy_dex_files)3168 bool OatWriter::WriteDexFiles(OutputStream* out,
3169                               File* file,
3170                               bool update_input_vdex,
3171                               CopyOption copy_dex_files) {
3172   TimingLogger::ScopedTiming split("Write Dex files", timings_);
3173 
3174   // If extraction is enabled, only do it if not all the dex files are aligned and uncompressed.
3175   if (copy_dex_files == CopyOption::kOnlyIfCompressed) {
3176     extract_dex_files_into_vdex_ = false;
3177     for (OatDexFile& oat_dex_file : oat_dex_files_) {
3178       if (!oat_dex_file.source_.IsZipEntry()) {
3179         extract_dex_files_into_vdex_ = true;
3180         break;
3181       }
3182       ZipEntry* entry = oat_dex_file.source_.GetZipEntry();
3183       if (!entry->IsUncompressed() || !entry->IsAlignedTo(alignof(DexFile::Header))) {
3184         extract_dex_files_into_vdex_ = true;
3185         break;
3186       }
3187     }
3188   } else if (copy_dex_files == CopyOption::kAlways) {
3189     extract_dex_files_into_vdex_ = true;
3190   } else {
3191     DCHECK(copy_dex_files == CopyOption::kNever);
3192     extract_dex_files_into_vdex_ = false;
3193   }
3194 
3195   if (extract_dex_files_into_vdex_) {
3196     // Add the dex section header.
3197     vdex_size_ += sizeof(VdexFile::DexSectionHeader);
3198     vdex_dex_files_offset_ = vdex_size_;
3199     // Write dex files.
3200     for (OatDexFile& oat_dex_file : oat_dex_files_) {
3201       if (!WriteDexFile(out, file, &oat_dex_file, update_input_vdex)) {
3202         return false;
3203       }
3204     }
3205 
3206     // Write shared dex file data section and fix up the dex file headers.
3207     vdex_dex_shared_data_offset_ = vdex_size_;
3208     uint32_t shared_data_size = 0u;
3209 
3210     if (dex_container_ != nullptr) {
3211       CHECK(!update_input_vdex) << "Update input vdex should have empty dex container";
3212       DexContainer::Section* const section = dex_container_->GetDataSection();
3213       if (section->Size() > 0) {
3214         CHECK(compact_dex_level_ != CompactDexLevel::kCompactDexLevelNone);
3215         const off_t existing_offset = out->Seek(0, kSeekCurrent);
3216         if (static_cast<uint32_t>(existing_offset) != vdex_dex_shared_data_offset_) {
3217           PLOG(ERROR) << "Expected offset " << vdex_dex_shared_data_offset_ << " but got "
3218                       << existing_offset;
3219           return false;
3220         }
3221         shared_data_size = section->Size();
3222         if (!out->WriteFully(section->Begin(), shared_data_size)) {
3223           PLOG(ERROR) << "Failed to write shared data!";
3224           return false;
3225         }
3226         if (!out->Flush()) {
3227           PLOG(ERROR) << "Failed to flush after writing shared dex section.";
3228           return false;
3229         }
3230         // Fix up the dex headers to have correct offsets to the data section.
3231         for (OatDexFile& oat_dex_file : oat_dex_files_) {
3232           // Overwrite the header by reading it, updating the offset, and writing it back out.
3233           DexFile::Header header;
3234           if (!file->PreadFully(&header, sizeof(header), oat_dex_file.dex_file_offset_)) {
3235             PLOG(ERROR) << "Failed to read dex header for updating";
3236             return false;
3237           }
3238           if (!CompactDexFile::IsMagicValid(header.magic_)) {
3239             // Non-compact dex file, probably failed to convert due to duplicate methods.
3240             continue;
3241           }
3242           CHECK_GT(vdex_dex_shared_data_offset_, oat_dex_file.dex_file_offset_);
3243           // Offset is from the dex file base.
3244           header.data_off_ = vdex_dex_shared_data_offset_ - oat_dex_file.dex_file_offset_;
3245           // The size should already be what part of the data buffer may be used by the dex.
3246           CHECK_LE(header.data_size_, shared_data_size);
3247           if (!file->PwriteFully(&header, sizeof(header), oat_dex_file.dex_file_offset_)) {
3248             PLOG(ERROR) << "Failed to write dex header for updating";
3249             return false;
3250           }
3251         }
3252         section->Clear();
3253       }
3254       dex_container_.reset();
3255     } else {
3256       const uint8_t* data_begin = nullptr;
3257       for (OatDexFile& oat_dex_file : oat_dex_files_) {
3258         DexFile::Header header;
3259         if (!file->PreadFully(&header, sizeof(header), oat_dex_file.dex_file_offset_)) {
3260           PLOG(ERROR) << "Failed to read dex header";
3261           return false;
3262         }
3263         if (!CompactDexFile::IsMagicValid(header.magic_)) {
3264           // Non compact dex does not have shared data section.
3265           continue;
3266         }
3267         const uint32_t expected_data_off = vdex_dex_shared_data_offset_ -
3268             oat_dex_file.dex_file_offset_;
3269         if (header.data_off_ != expected_data_off) {
3270           PLOG(ERROR) << "Shared data section offset " << header.data_off_
3271                       << " does not match expected value " << expected_data_off;
3272           return false;
3273         }
3274         if (oat_dex_file.source_.IsRawData()) {
3275           // Figure out the start of the shared data section so we can copy it below.
3276           const uint8_t* cur_data_begin = oat_dex_file.source_.GetRawData() + header.data_off_;
3277           if (data_begin != nullptr) {
3278             CHECK_EQ(data_begin, cur_data_begin);
3279           }
3280           data_begin = cur_data_begin;
3281         }
3282         // The different dex files currently can have different data sizes since
3283         // the dex writer writes them one at a time into the shared section.:w
3284         shared_data_size = std::max(shared_data_size, header.data_size_);
3285       }
3286       // If we are not updating the input vdex, write out the shared data section.
3287       if (!update_input_vdex) {
3288         const off_t existing_offset = out->Seek(0, kSeekCurrent);
3289         if (static_cast<uint32_t>(existing_offset) != vdex_dex_shared_data_offset_) {
3290           PLOG(ERROR) << "Expected offset " << vdex_dex_shared_data_offset_ << " but got "
3291                       << existing_offset;
3292           return false;
3293         }
3294         if (!out->WriteFully(data_begin, shared_data_size)) {
3295           PLOG(ERROR) << "Failed to write shared data!";
3296           return false;
3297         }
3298         if (!out->Flush()) {
3299           PLOG(ERROR) << "Failed to flush after writing shared dex section.";
3300           return false;
3301         }
3302       }
3303     }
3304     vdex_size_ += shared_data_size;
3305     size_dex_file_ += shared_data_size;
3306   } else {
3307     vdex_dex_shared_data_offset_ = vdex_size_;
3308   }
3309 
3310   return true;
3311 }
3312 
CloseSources()3313 void OatWriter::CloseSources() {
3314   for (OatDexFile& oat_dex_file : oat_dex_files_) {
3315     oat_dex_file.source_.Clear();  // Get rid of the reference, it's about to be invalidated.
3316   }
3317   zipped_dex_files_.clear();
3318   zip_archives_.clear();
3319   raw_dex_files_.clear();
3320 }
3321 
WriteDexFile(OutputStream * out,File * file,OatDexFile * oat_dex_file,bool update_input_vdex)3322 bool OatWriter::WriteDexFile(OutputStream* out,
3323                              File* file,
3324                              OatDexFile* oat_dex_file,
3325                              bool update_input_vdex) {
3326   if (!SeekToDexFile(out, file, oat_dex_file)) {
3327     return false;
3328   }
3329   // update_input_vdex disables compact dex and layout.
3330   if (profile_compilation_info_ != nullptr ||
3331       compact_dex_level_ != CompactDexLevel::kCompactDexLevelNone) {
3332     CHECK(!update_input_vdex)
3333         << "We should never update the input vdex when doing dexlayout or compact dex";
3334     if (!LayoutAndWriteDexFile(out, oat_dex_file)) {
3335       return false;
3336     }
3337   } else if (oat_dex_file->source_.IsZipEntry()) {
3338     DCHECK(!update_input_vdex);
3339     if (!WriteDexFile(out, file, oat_dex_file, oat_dex_file->source_.GetZipEntry())) {
3340       return false;
3341     }
3342   } else if (oat_dex_file->source_.IsRawFile()) {
3343     DCHECK(!update_input_vdex);
3344     if (!WriteDexFile(out, file, oat_dex_file, oat_dex_file->source_.GetRawFile())) {
3345       return false;
3346     }
3347   } else {
3348     DCHECK(oat_dex_file->source_.IsRawData());
3349     if (!WriteDexFile(out, oat_dex_file, oat_dex_file->source_.GetRawData(), update_input_vdex)) {
3350       return false;
3351     }
3352   }
3353 
3354   // Update current size and account for the written data.
3355   DCHECK_EQ(vdex_size_, oat_dex_file->dex_file_offset_);
3356   vdex_size_ += oat_dex_file->dex_file_size_;
3357   size_dex_file_ += oat_dex_file->dex_file_size_;
3358   return true;
3359 }
3360 
SeekToDexFile(OutputStream * out,File * file,OatDexFile * oat_dex_file)3361 bool OatWriter::SeekToDexFile(OutputStream* out, File* file, OatDexFile* oat_dex_file) {
3362   // Dex files are required to be 4 byte aligned.
3363   size_t initial_offset = vdex_size_;
3364   size_t start_offset = RoundUp(initial_offset, 4);
3365   size_dex_file_alignment_ += start_offset - initial_offset;
3366 
3367   // Leave extra room for the quicken offset table offset.
3368   start_offset += sizeof(VdexFile::QuickeningTableOffsetType);
3369   // TODO: Not count the offset as part of alignment.
3370   size_dex_file_alignment_ += sizeof(VdexFile::QuickeningTableOffsetType);
3371 
3372   size_t file_offset = start_offset;
3373 
3374   // Seek to the start of the dex file and flush any pending operations in the stream.
3375   // Verify that, after flushing the stream, the file is at the same offset as the stream.
3376   off_t actual_offset = out->Seek(file_offset, kSeekSet);
3377   if (actual_offset != static_cast<off_t>(file_offset)) {
3378     PLOG(ERROR) << "Failed to seek to dex file section. Actual: " << actual_offset
3379                 << " Expected: " << file_offset
3380                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
3381     return false;
3382   }
3383   if (!out->Flush()) {
3384     PLOG(ERROR) << "Failed to flush before writing dex file."
3385                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
3386     return false;
3387   }
3388   actual_offset = lseek(file->Fd(), 0, SEEK_CUR);
3389   if (actual_offset != static_cast<off_t>(file_offset)) {
3390     PLOG(ERROR) << "Stream/file position mismatch! Actual: " << actual_offset
3391                 << " Expected: " << file_offset
3392                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
3393     return false;
3394   }
3395 
3396   vdex_size_ = start_offset;
3397   oat_dex_file->dex_file_offset_ = start_offset;
3398   return true;
3399 }
3400 
LayoutAndWriteDexFile(OutputStream * out,OatDexFile * oat_dex_file)3401 bool OatWriter::LayoutAndWriteDexFile(OutputStream* out, OatDexFile* oat_dex_file) {
3402   TimingLogger::ScopedTiming split("Dex Layout", timings_);
3403   std::string error_msg;
3404   std::string location(oat_dex_file->GetLocation());
3405   std::unique_ptr<const DexFile> dex_file;
3406   const ArtDexFileLoader dex_file_loader;
3407   if (oat_dex_file->source_.IsZipEntry()) {
3408     ZipEntry* zip_entry = oat_dex_file->source_.GetZipEntry();
3409     MemMap mem_map;
3410     {
3411       TimingLogger::ScopedTiming extract("Unzip", timings_);
3412       mem_map = zip_entry->ExtractToMemMap(location.c_str(), "classes.dex", &error_msg);
3413     }
3414     if (!mem_map.IsValid()) {
3415       LOG(ERROR) << "Failed to extract dex file to mem map for layout: " << error_msg;
3416       return false;
3417     }
3418     TimingLogger::ScopedTiming extract("Open", timings_);
3419     dex_file = dex_file_loader.Open(location,
3420                                     zip_entry->GetCrc32(),
3421                                     std::move(mem_map),
3422                                     /* verify */ true,
3423                                     /* verify_checksum */ true,
3424                                     &error_msg);
3425   } else if (oat_dex_file->source_.IsRawFile()) {
3426     File* raw_file = oat_dex_file->source_.GetRawFile();
3427     int dup_fd = DupCloexec(raw_file->Fd());
3428     if (dup_fd < 0) {
3429       PLOG(ERROR) << "Failed to dup dex file descriptor (" << raw_file->Fd() << ") at " << location;
3430       return false;
3431     }
3432     TimingLogger::ScopedTiming extract("Open", timings_);
3433     dex_file = dex_file_loader.OpenDex(dup_fd, location,
3434                                        /* verify */ true,
3435                                        /* verify_checksum */ true,
3436                                        /* mmap_shared */ false,
3437                                        &error_msg);
3438   } else {
3439     // The source data is a vdex file.
3440     CHECK(oat_dex_file->source_.IsRawData())
3441         << static_cast<size_t>(oat_dex_file->source_.GetType());
3442     const uint8_t* raw_dex_file = oat_dex_file->source_.GetRawData();
3443     // Note: The raw data has already been checked to contain the header
3444     // and all the data that the header specifies as the file size.
3445     DCHECK(raw_dex_file != nullptr);
3446     DCHECK(ValidateDexFileHeader(raw_dex_file, oat_dex_file->GetLocation()));
3447     const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_dex_file);
3448     // Since the source may have had its layout changed, or may be quickened, don't verify it.
3449     dex_file = dex_file_loader.Open(raw_dex_file,
3450                                     header->file_size_,
3451                                     location,
3452                                     oat_dex_file->dex_file_location_checksum_,
3453                                     nullptr,
3454                                     /* verify */ false,
3455                                     /* verify_checksum */ false,
3456                                     &error_msg);
3457   }
3458   if (dex_file == nullptr) {
3459     LOG(ERROR) << "Failed to open dex file for layout: " << error_msg;
3460     return false;
3461   }
3462   Options options;
3463   options.compact_dex_level_ = compact_dex_level_;
3464   options.update_checksum_ = true;
3465   DexLayout dex_layout(options, profile_compilation_info_, /*file*/ nullptr, /*header*/ nullptr);
3466   const uint8_t* dex_src = nullptr;
3467   {
3468     TimingLogger::ScopedTiming extract("ProcessDexFile", timings_);
3469     if (dex_layout.ProcessDexFile(location.c_str(),
3470                                   dex_file.get(),
3471                                   0,
3472                                   &dex_container_,
3473                                   &error_msg)) {
3474       oat_dex_file->dex_sections_layout_ = dex_layout.GetSections();
3475       // Dex layout can affect the size of the dex file, so we update here what we have set
3476       // when adding the dex file as a source.
3477       const UnalignedDexFileHeader* header =
3478           AsUnalignedDexFileHeader(dex_container_->GetMainSection()->Begin());
3479       oat_dex_file->dex_file_size_ = header->file_size_;
3480       dex_src = dex_container_->GetMainSection()->Begin();
3481     } else {
3482       LOG(WARNING) << "Failed to run dex layout, reason:" << error_msg;
3483       // Since we failed to convert the dex, just copy the input dex.
3484       dex_src = dex_file->Begin();
3485     }
3486   }
3487   {
3488     TimingLogger::ScopedTiming extract("WriteDexFile", timings_);
3489     if (!WriteDexFile(out, oat_dex_file, dex_src, /* update_input_vdex */ false)) {
3490       return false;
3491     }
3492   }
3493   if (dex_container_ != nullptr) {
3494     // Clear the main section in case we write more data into the container.
3495     dex_container_->GetMainSection()->Clear();
3496   }
3497   CHECK_EQ(oat_dex_file->dex_file_location_checksum_, dex_file->GetLocationChecksum());
3498   return true;
3499 }
3500 
WriteDexFile(OutputStream * out,File * file,OatDexFile * oat_dex_file,ZipEntry * dex_file)3501 bool OatWriter::WriteDexFile(OutputStream* out,
3502                              File* file,
3503                              OatDexFile* oat_dex_file,
3504                              ZipEntry* dex_file) {
3505   size_t start_offset = vdex_size_;
3506   DCHECK_EQ(static_cast<off_t>(start_offset), out->Seek(0, kSeekCurrent));
3507 
3508   // Extract the dex file and get the extracted size.
3509   std::string error_msg;
3510   if (!dex_file->ExtractToFile(*file, &error_msg)) {
3511     LOG(ERROR) << "Failed to extract dex file from ZIP entry: " << error_msg
3512                << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
3513     return false;
3514   }
3515   if (file->Flush() != 0) {
3516     PLOG(ERROR) << "Failed to flush dex file from ZIP entry."
3517                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
3518     return false;
3519   }
3520   off_t extracted_end = lseek(file->Fd(), 0, SEEK_CUR);
3521   if (extracted_end == static_cast<off_t>(-1)) {
3522     PLOG(ERROR) << "Failed get end offset after writing dex file from ZIP entry."
3523                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
3524     return false;
3525   }
3526   if (extracted_end < static_cast<off_t>(start_offset)) {
3527     LOG(ERROR) << "Dex file end position is before start position! End: " << extracted_end
3528                << " Start: " << start_offset
3529                << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
3530     return false;
3531   }
3532   uint64_t extracted_size = static_cast<uint64_t>(extracted_end - start_offset);
3533   if (extracted_size < sizeof(DexFile::Header)) {
3534     LOG(ERROR) << "Extracted dex file is shorter than dex file header. size: "
3535                << extracted_size << " File: " << oat_dex_file->GetLocation();
3536     return false;
3537   }
3538 
3539   // Read the dex file header and extract required data to OatDexFile.
3540   off_t actual_offset = lseek(file->Fd(), start_offset, SEEK_SET);
3541   if (actual_offset != static_cast<off_t>(start_offset)) {
3542     PLOG(ERROR) << "Failed to seek back to dex file header. Actual: " << actual_offset
3543                 << " Expected: " << start_offset
3544                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
3545     return false;
3546   }
3547   if (extracted_size < oat_dex_file->dex_file_size_) {
3548     LOG(ERROR) << "Extracted truncated dex file. Extracted size: " << extracted_size
3549                << " file size from header: " << oat_dex_file->dex_file_size_
3550                << " File: " << oat_dex_file->GetLocation();
3551     return false;
3552   }
3553 
3554   // Seek both file and stream to the end offset.
3555   size_t end_offset = start_offset + oat_dex_file->dex_file_size_;
3556   actual_offset = lseek(file->Fd(), end_offset, SEEK_SET);
3557   if (actual_offset != static_cast<off_t>(end_offset)) {
3558     PLOG(ERROR) << "Failed to seek to end of dex file. Actual: " << actual_offset
3559                 << " Expected: " << end_offset
3560                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
3561     return false;
3562   }
3563   actual_offset = out->Seek(end_offset, kSeekSet);
3564   if (actual_offset != static_cast<off_t>(end_offset)) {
3565     PLOG(ERROR) << "Failed to seek stream to end of dex file. Actual: " << actual_offset
3566                 << " Expected: " << end_offset << " File: " << oat_dex_file->GetLocation();
3567     return false;
3568   }
3569   if (!out->Flush()) {
3570     PLOG(ERROR) << "Failed to flush stream after seeking over dex file."
3571                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
3572     return false;
3573   }
3574 
3575   // If we extracted more than the size specified in the header, truncate the file.
3576   if (extracted_size > oat_dex_file->dex_file_size_) {
3577     if (file->SetLength(end_offset) != 0) {
3578       PLOG(ERROR) << "Failed to truncate excessive dex file length."
3579                   << " File: " << oat_dex_file->GetLocation()
3580                   << " Output: " << file->GetPath();
3581       return false;
3582     }
3583   }
3584 
3585   return true;
3586 }
3587 
WriteDexFile(OutputStream * out,File * file,OatDexFile * oat_dex_file,File * dex_file)3588 bool OatWriter::WriteDexFile(OutputStream* out,
3589                              File* file,
3590                              OatDexFile* oat_dex_file,
3591                              File* dex_file) {
3592   size_t start_offset = vdex_size_;
3593   DCHECK_EQ(static_cast<off_t>(start_offset), out->Seek(0, kSeekCurrent));
3594 
3595   off_t input_offset = lseek(dex_file->Fd(), 0, SEEK_SET);
3596   if (input_offset != static_cast<off_t>(0)) {
3597     PLOG(ERROR) << "Failed to seek to dex file header. Actual: " << input_offset
3598                 << " Expected: 0"
3599                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
3600     return false;
3601   }
3602 
3603   // Copy the input dex file using sendfile().
3604   if (!file->Copy(dex_file, 0, oat_dex_file->dex_file_size_)) {
3605     PLOG(ERROR) << "Failed to copy dex file to oat file."
3606                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
3607     return false;
3608   }
3609   if (file->Flush() != 0) {
3610     PLOG(ERROR) << "Failed to flush dex file."
3611                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
3612     return false;
3613   }
3614 
3615   // Check file position and seek the stream to the end offset.
3616   size_t end_offset = start_offset + oat_dex_file->dex_file_size_;
3617   off_t actual_offset = lseek(file->Fd(), 0, SEEK_CUR);
3618   if (actual_offset != static_cast<off_t>(end_offset)) {
3619     PLOG(ERROR) << "Unexpected file position after copying dex file. Actual: " << actual_offset
3620                 << " Expected: " << end_offset
3621                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
3622     return false;
3623   }
3624   actual_offset = out->Seek(end_offset, kSeekSet);
3625   if (actual_offset != static_cast<off_t>(end_offset)) {
3626     PLOG(ERROR) << "Failed to seek stream to end of dex file. Actual: " << actual_offset
3627                 << " Expected: " << end_offset << " File: " << oat_dex_file->GetLocation();
3628     return false;
3629   }
3630   if (!out->Flush()) {
3631     PLOG(ERROR) << "Failed to flush stream after seeking over dex file."
3632                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
3633     return false;
3634   }
3635 
3636   return true;
3637 }
3638 
WriteDexFile(OutputStream * out,OatDexFile * oat_dex_file,const uint8_t * dex_file,bool update_input_vdex)3639 bool OatWriter::WriteDexFile(OutputStream* out,
3640                              OatDexFile* oat_dex_file,
3641                              const uint8_t* dex_file,
3642                              bool update_input_vdex) {
3643   // Note: The raw data has already been checked to contain the header
3644   // and all the data that the header specifies as the file size.
3645   DCHECK(dex_file != nullptr);
3646   DCHECK(ValidateDexFileHeader(dex_file, oat_dex_file->GetLocation()));
3647   const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(dex_file);
3648 
3649   if (update_input_vdex) {
3650     // The vdex already contains the dex code, no need to write it again.
3651   } else {
3652     if (!out->WriteFully(dex_file, header->file_size_)) {
3653       PLOG(ERROR) << "Failed to write dex file " << oat_dex_file->GetLocation()
3654                   << " to " << out->GetLocation();
3655       return false;
3656     }
3657     if (!out->Flush()) {
3658       PLOG(ERROR) << "Failed to flush stream after writing dex file."
3659                   << " File: " << oat_dex_file->GetLocation();
3660       return false;
3661     }
3662   }
3663   return true;
3664 }
3665 
OpenDexFiles(File * file,bool verify,std::vector<MemMap> * opened_dex_files_map,std::vector<std::unique_ptr<const DexFile>> * opened_dex_files)3666 bool OatWriter::OpenDexFiles(
3667     File* file,
3668     bool verify,
3669     /*out*/ std::vector<MemMap>* opened_dex_files_map,
3670     /*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files) {
3671   TimingLogger::ScopedTiming split("OpenDexFiles", timings_);
3672 
3673   if (oat_dex_files_.empty()) {
3674     // Nothing to do.
3675     return true;
3676   }
3677 
3678   if (!extract_dex_files_into_vdex_) {
3679     std::vector<std::unique_ptr<const DexFile>> dex_files;
3680     std::vector<MemMap> maps;
3681     for (OatDexFile& oat_dex_file : oat_dex_files_) {
3682       std::string error_msg;
3683       maps.emplace_back(oat_dex_file.source_.GetZipEntry()->MapDirectlyOrExtract(
3684           oat_dex_file.dex_file_location_data_, "zipped dex", &error_msg, alignof(DexFile)));
3685       MemMap* map = &maps.back();
3686       if (!map->IsValid()) {
3687         LOG(ERROR) << error_msg;
3688         return false;
3689       }
3690       // Now, open the dex file.
3691       const ArtDexFileLoader dex_file_loader;
3692       dex_files.emplace_back(dex_file_loader.Open(map->Begin(),
3693                                                   map->Size(),
3694                                                   oat_dex_file.GetLocation(),
3695                                                   oat_dex_file.dex_file_location_checksum_,
3696                                                   /* oat_dex_file */ nullptr,
3697                                                   verify,
3698                                                   verify,
3699                                                   &error_msg));
3700       if (dex_files.back() == nullptr) {
3701         LOG(ERROR) << "Failed to open dex file from oat file. File: " << oat_dex_file.GetLocation()
3702                    << " Error: " << error_msg;
3703         return false;
3704       }
3705       oat_dex_file.class_offsets_.resize(dex_files.back()->GetHeader().class_defs_size_);
3706     }
3707     *opened_dex_files_map = std::move(maps);
3708     *opened_dex_files = std::move(dex_files);
3709     CloseSources();
3710     return true;
3711   }
3712   // We could have closed the sources at the point of writing the dex files, but to
3713   // make it consistent with the case we're not writing the dex files, we close them now.
3714   CloseSources();
3715 
3716   size_t map_offset = oat_dex_files_[0].dex_file_offset_;
3717   size_t length = vdex_size_ - map_offset;
3718 
3719   std::string error_msg;
3720   MemMap dex_files_map = MemMap::MapFile(
3721       length,
3722       PROT_READ | PROT_WRITE,
3723       MAP_SHARED,
3724       file->Fd(),
3725       map_offset,
3726       /* low_4gb */ false,
3727       file->GetPath().c_str(),
3728       &error_msg);
3729   if (!dex_files_map.IsValid()) {
3730     LOG(ERROR) << "Failed to mmap() dex files from oat file. File: " << file->GetPath()
3731                << " error: " << error_msg;
3732     return false;
3733   }
3734   const ArtDexFileLoader dex_file_loader;
3735   std::vector<std::unique_ptr<const DexFile>> dex_files;
3736   for (OatDexFile& oat_dex_file : oat_dex_files_) {
3737     const uint8_t* raw_dex_file =
3738         dex_files_map.Begin() + oat_dex_file.dex_file_offset_ - map_offset;
3739 
3740     if (kIsDebugBuild) {
3741       // Sanity check our input files.
3742       // Note that ValidateDexFileHeader() logs error messages.
3743       CHECK(ValidateDexFileHeader(raw_dex_file, oat_dex_file.GetLocation()))
3744           << "Failed to verify written dex file header!"
3745           << " Output: " << file->GetPath() << " ~ " << std::hex << map_offset
3746           << " ~ " << static_cast<const void*>(raw_dex_file);
3747 
3748       const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_dex_file);
3749       CHECK_EQ(header->file_size_, oat_dex_file.dex_file_size_)
3750           << "File size mismatch in written dex file header! Expected: "
3751           << oat_dex_file.dex_file_size_ << " Actual: " << header->file_size_
3752           << " Output: " << file->GetPath();
3753     }
3754 
3755     // Now, open the dex file.
3756     dex_files.emplace_back(dex_file_loader.Open(raw_dex_file,
3757                                                 oat_dex_file.dex_file_size_,
3758                                                 oat_dex_file.GetLocation(),
3759                                                 oat_dex_file.dex_file_location_checksum_,
3760                                                 /* oat_dex_file */ nullptr,
3761                                                 verify,
3762                                                 verify,
3763                                                 &error_msg));
3764     if (dex_files.back() == nullptr) {
3765       LOG(ERROR) << "Failed to open dex file from oat file. File: " << oat_dex_file.GetLocation()
3766                  << " Error: " << error_msg;
3767       return false;
3768     }
3769 
3770     // Set the class_offsets size now that we have easy access to the DexFile and
3771     // it has been verified in dex_file_loader.Open.
3772     oat_dex_file.class_offsets_.resize(dex_files.back()->GetHeader().class_defs_size_);
3773   }
3774 
3775   opened_dex_files_map->push_back(std::move(dex_files_map));
3776   *opened_dex_files = std::move(dex_files);
3777   return true;
3778 }
3779 
WriteTypeLookupTables(OutputStream * oat_rodata,const std::vector<std::unique_ptr<const DexFile>> & opened_dex_files)3780 bool OatWriter::WriteTypeLookupTables(
3781     OutputStream* oat_rodata,
3782     const std::vector<std::unique_ptr<const DexFile>>& opened_dex_files) {
3783   TimingLogger::ScopedTiming split("WriteTypeLookupTables", timings_);
3784 
3785   uint32_t expected_offset = oat_data_offset_ + oat_size_;
3786   off_t actual_offset = oat_rodata->Seek(expected_offset, kSeekSet);
3787   if (static_cast<uint32_t>(actual_offset) != expected_offset) {
3788     PLOG(ERROR) << "Failed to seek to TypeLookupTable section. Actual: " << actual_offset
3789                 << " Expected: " << expected_offset << " File: " << oat_rodata->GetLocation();
3790     return false;
3791   }
3792 
3793   DCHECK_EQ(opened_dex_files.size(), oat_dex_files_.size());
3794   for (size_t i = 0, size = opened_dex_files.size(); i != size; ++i) {
3795     OatDexFile* oat_dex_file = &oat_dex_files_[i];
3796     DCHECK_EQ(oat_dex_file->lookup_table_offset_, 0u);
3797 
3798     if (oat_dex_file->create_type_lookup_table_ != CreateTypeLookupTable::kCreate ||
3799         oat_dex_file->class_offsets_.empty()) {
3800       continue;
3801     }
3802 
3803     size_t table_size = TypeLookupTable::RawDataLength(oat_dex_file->class_offsets_.size());
3804     if (table_size == 0u) {
3805       continue;
3806     }
3807 
3808     // Create the lookup table. When `nullptr` is given as the storage buffer,
3809     // TypeLookupTable allocates its own and OatDexFile takes ownership.
3810     const DexFile& dex_file = *opened_dex_files[i];
3811     {
3812       TypeLookupTable type_lookup_table = TypeLookupTable::Create(dex_file);
3813       type_lookup_table_oat_dex_files_.push_back(
3814           std::make_unique<art::OatDexFile>(std::move(type_lookup_table)));
3815       dex_file.SetOatDexFile(type_lookup_table_oat_dex_files_.back().get());
3816     }
3817     const TypeLookupTable& table = type_lookup_table_oat_dex_files_.back()->GetTypeLookupTable();
3818     DCHECK(table.Valid());
3819 
3820     // Type tables are required to be 4 byte aligned.
3821     size_t initial_offset = oat_size_;
3822     size_t rodata_offset = RoundUp(initial_offset, 4);
3823     size_t padding_size = rodata_offset - initial_offset;
3824 
3825     if (padding_size != 0u) {
3826       std::vector<uint8_t> buffer(padding_size, 0u);
3827       if (!oat_rodata->WriteFully(buffer.data(), padding_size)) {
3828         PLOG(ERROR) << "Failed to write lookup table alignment padding."
3829                     << " File: " << oat_dex_file->GetLocation()
3830                     << " Output: " << oat_rodata->GetLocation();
3831         return false;
3832       }
3833     }
3834 
3835     DCHECK_EQ(oat_data_offset_ + rodata_offset,
3836               static_cast<size_t>(oat_rodata->Seek(0u, kSeekCurrent)));
3837     DCHECK_EQ(table_size, table.RawDataLength());
3838 
3839     if (!oat_rodata->WriteFully(table.RawData(), table_size)) {
3840       PLOG(ERROR) << "Failed to write lookup table."
3841                   << " File: " << oat_dex_file->GetLocation()
3842                   << " Output: " << oat_rodata->GetLocation();
3843       return false;
3844     }
3845 
3846     oat_dex_file->lookup_table_offset_ = rodata_offset;
3847 
3848     oat_size_ += padding_size + table_size;
3849     size_oat_lookup_table_ += table_size;
3850     size_oat_lookup_table_alignment_ += padding_size;
3851   }
3852 
3853   if (!oat_rodata->Flush()) {
3854     PLOG(ERROR) << "Failed to flush stream after writing type lookup tables."
3855                 << " File: " << oat_rodata->GetLocation();
3856     return false;
3857   }
3858 
3859   return true;
3860 }
3861 
WriteDexLayoutSections(OutputStream * oat_rodata,const std::vector<std::unique_ptr<const DexFile>> & opened_dex_files)3862 bool OatWriter::WriteDexLayoutSections(
3863     OutputStream* oat_rodata,
3864     const std::vector<std::unique_ptr<const DexFile>>& opened_dex_files) {
3865   TimingLogger::ScopedTiming split(__FUNCTION__, timings_);
3866 
3867   if (!kWriteDexLayoutInfo) {
3868     return true;;
3869   }
3870 
3871   uint32_t expected_offset = oat_data_offset_ + oat_size_;
3872   off_t actual_offset = oat_rodata->Seek(expected_offset, kSeekSet);
3873   if (static_cast<uint32_t>(actual_offset) != expected_offset) {
3874     PLOG(ERROR) << "Failed to seek to dex layout section offset section. Actual: " << actual_offset
3875                 << " Expected: " << expected_offset << " File: " << oat_rodata->GetLocation();
3876     return false;
3877   }
3878 
3879   DCHECK_EQ(opened_dex_files.size(), oat_dex_files_.size());
3880   size_t rodata_offset = oat_size_;
3881   for (size_t i = 0, size = opened_dex_files.size(); i != size; ++i) {
3882     OatDexFile* oat_dex_file = &oat_dex_files_[i];
3883     DCHECK_EQ(oat_dex_file->dex_sections_layout_offset_, 0u);
3884 
3885     // Write dex layout section alignment bytes.
3886     const size_t padding_size =
3887         RoundUp(rodata_offset, alignof(DexLayoutSections)) - rodata_offset;
3888     if (padding_size != 0u) {
3889       std::vector<uint8_t> buffer(padding_size, 0u);
3890       if (!oat_rodata->WriteFully(buffer.data(), padding_size)) {
3891         PLOG(ERROR) << "Failed to write lookup table alignment padding."
3892                     << " File: " << oat_dex_file->GetLocation()
3893                     << " Output: " << oat_rodata->GetLocation();
3894         return false;
3895       }
3896       size_oat_dex_file_dex_layout_sections_alignment_ += padding_size;
3897       rodata_offset += padding_size;
3898     }
3899 
3900     DCHECK_ALIGNED(rodata_offset, alignof(DexLayoutSections));
3901     DCHECK_EQ(oat_data_offset_ + rodata_offset,
3902               static_cast<size_t>(oat_rodata->Seek(0u, kSeekCurrent)));
3903     DCHECK(oat_dex_file != nullptr);
3904     if (!oat_rodata->WriteFully(&oat_dex_file->dex_sections_layout_,
3905                                 sizeof(oat_dex_file->dex_sections_layout_))) {
3906       PLOG(ERROR) << "Failed to write dex layout sections."
3907                   << " File: " << oat_dex_file->GetLocation()
3908                   << " Output: " << oat_rodata->GetLocation();
3909       return false;
3910     }
3911     oat_dex_file->dex_sections_layout_offset_ = rodata_offset;
3912     size_oat_dex_file_dex_layout_sections_ += sizeof(oat_dex_file->dex_sections_layout_);
3913     rodata_offset += sizeof(oat_dex_file->dex_sections_layout_);
3914   }
3915   oat_size_ = rodata_offset;
3916 
3917   if (!oat_rodata->Flush()) {
3918     PLOG(ERROR) << "Failed to flush stream after writing type dex layout sections."
3919                 << " File: " << oat_rodata->GetLocation();
3920     return false;
3921   }
3922 
3923   return true;
3924 }
3925 
WriteChecksumsAndVdexHeader(OutputStream * vdex_out)3926 bool OatWriter::WriteChecksumsAndVdexHeader(OutputStream* vdex_out) {
3927   // Write checksums
3928   off_t checksums_offset = sizeof(VdexFile::VerifierDepsHeader);
3929   off_t actual_offset = vdex_out->Seek(checksums_offset, kSeekSet);
3930   if (actual_offset != checksums_offset) {
3931     PLOG(ERROR) << "Failed to seek to the checksum location of vdex file. Actual: " << actual_offset
3932                 << " File: " << vdex_out->GetLocation();
3933     return false;
3934   }
3935 
3936   for (size_t i = 0, size = oat_dex_files_.size(); i != size; ++i) {
3937     OatDexFile* oat_dex_file = &oat_dex_files_[i];
3938     if (!vdex_out->WriteFully(
3939             &oat_dex_file->dex_file_location_checksum_, sizeof(VdexFile::VdexChecksum))) {
3940       PLOG(ERROR) << "Failed to write dex file location checksum. File: "
3941                   << vdex_out->GetLocation();
3942       return false;
3943     }
3944     size_vdex_checksums_ += sizeof(VdexFile::VdexChecksum);
3945   }
3946 
3947   // Maybe write dex section header.
3948   DCHECK_NE(vdex_verifier_deps_offset_, 0u);
3949   DCHECK_NE(vdex_quickening_info_offset_, 0u);
3950 
3951   bool has_dex_section = extract_dex_files_into_vdex_;
3952   if (has_dex_section) {
3953     DCHECK_NE(vdex_dex_files_offset_, 0u);
3954     size_t dex_section_size = vdex_dex_shared_data_offset_ - vdex_dex_files_offset_;
3955     size_t dex_shared_data_size = vdex_verifier_deps_offset_ - vdex_dex_shared_data_offset_;
3956     size_t quickening_info_section_size = vdex_size_ - vdex_quickening_info_offset_;
3957 
3958     VdexFile::DexSectionHeader dex_section_header(dex_section_size,
3959                                                   dex_shared_data_size,
3960                                                   quickening_info_section_size);
3961     if (!vdex_out->WriteFully(&dex_section_header, sizeof(VdexFile::DexSectionHeader))) {
3962       PLOG(ERROR) << "Failed to write vdex header. File: " << vdex_out->GetLocation();
3963       return false;
3964     }
3965     size_vdex_header_ += sizeof(VdexFile::DexSectionHeader);
3966   }
3967 
3968   // Write header.
3969   actual_offset = vdex_out->Seek(0, kSeekSet);
3970   if (actual_offset != 0) {
3971     PLOG(ERROR) << "Failed to seek to the beginning of vdex file. Actual: " << actual_offset
3972                 << " File: " << vdex_out->GetLocation();
3973     return false;
3974   }
3975 
3976   size_t verifier_deps_section_size = vdex_quickening_info_offset_ - vdex_verifier_deps_offset_;
3977 
3978   VdexFile::VerifierDepsHeader deps_header(
3979       oat_dex_files_.size(), verifier_deps_section_size, has_dex_section);
3980   if (!vdex_out->WriteFully(&deps_header, sizeof(VdexFile::VerifierDepsHeader))) {
3981     PLOG(ERROR) << "Failed to write vdex header. File: " << vdex_out->GetLocation();
3982     return false;
3983   }
3984   size_vdex_header_ += sizeof(VdexFile::VerifierDepsHeader);
3985 
3986   if (!vdex_out->Flush()) {
3987     PLOG(ERROR) << "Failed to flush stream after writing to vdex file."
3988                 << " File: " << vdex_out->GetLocation();
3989     return false;
3990   }
3991 
3992   return true;
3993 }
3994 
WriteCodeAlignment(OutputStream * out,uint32_t aligned_code_delta)3995 bool OatWriter::WriteCodeAlignment(OutputStream* out, uint32_t aligned_code_delta) {
3996   return WriteUpTo16BytesAlignment(out, aligned_code_delta, &size_code_alignment_);
3997 }
3998 
WriteUpTo16BytesAlignment(OutputStream * out,uint32_t size,uint32_t * stat)3999 bool OatWriter::WriteUpTo16BytesAlignment(OutputStream* out, uint32_t size, uint32_t* stat) {
4000   static const uint8_t kPadding[] = {
4001       0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u
4002   };
4003   DCHECK_LE(size, sizeof(kPadding));
4004   if (UNLIKELY(!out->WriteFully(kPadding, size))) {
4005     return false;
4006   }
4007   *stat += size;
4008   return true;
4009 }
4010 
SetMultiOatRelativePatcherAdjustment()4011 void OatWriter::SetMultiOatRelativePatcherAdjustment() {
4012   DCHECK(dex_files_ != nullptr);
4013   DCHECK(relative_patcher_ != nullptr);
4014   DCHECK_NE(oat_data_offset_, 0u);
4015   if (image_writer_ != nullptr && !dex_files_->empty()) {
4016     // The oat data begin may not be initialized yet but the oat file offset is ready.
4017     size_t oat_index = image_writer_->GetOatIndexForDexFile(dex_files_->front());
4018     size_t elf_file_offset = image_writer_->GetOatFileOffset(oat_index);
4019     relative_patcher_->StartOatFile(elf_file_offset + oat_data_offset_);
4020   }
4021 }
4022 
OatDexFile(const char * dex_file_location,DexFileSource source,CreateTypeLookupTable create_type_lookup_table,uint32_t dex_file_location_checksum,size_t dex_file_size)4023 OatWriter::OatDexFile::OatDexFile(const char* dex_file_location,
4024                                   DexFileSource source,
4025                                   CreateTypeLookupTable create_type_lookup_table,
4026                                   uint32_t dex_file_location_checksum,
4027                                   size_t dex_file_size)
4028     : source_(source),
4029       create_type_lookup_table_(create_type_lookup_table),
4030       dex_file_size_(dex_file_size),
4031       offset_(0),
4032       dex_file_location_size_(strlen(dex_file_location)),
4033       dex_file_location_data_(dex_file_location),
4034       dex_file_location_checksum_(dex_file_location_checksum),
4035       dex_file_offset_(0u),
4036       lookup_table_offset_(0u),
4037       class_offsets_offset_(0u),
4038       method_bss_mapping_offset_(0u),
4039       type_bss_mapping_offset_(0u),
4040       string_bss_mapping_offset_(0u),
4041       dex_sections_layout_offset_(0u),
4042       class_offsets_() {
4043 }
4044 
SizeOf() const4045 size_t OatWriter::OatDexFile::SizeOf() const {
4046   return sizeof(dex_file_location_size_)
4047           + dex_file_location_size_
4048           + sizeof(dex_file_location_checksum_)
4049           + sizeof(dex_file_offset_)
4050           + sizeof(class_offsets_offset_)
4051           + sizeof(lookup_table_offset_)
4052           + sizeof(method_bss_mapping_offset_)
4053           + sizeof(type_bss_mapping_offset_)
4054           + sizeof(string_bss_mapping_offset_)
4055           + sizeof(dex_sections_layout_offset_);
4056 }
4057 
Write(OatWriter * oat_writer,OutputStream * out) const4058 bool OatWriter::OatDexFile::Write(OatWriter* oat_writer, OutputStream* out) const {
4059   const size_t file_offset = oat_writer->oat_data_offset_;
4060   DCHECK_OFFSET_();
4061 
4062   if (!out->WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) {
4063     PLOG(ERROR) << "Failed to write dex file location length to " << out->GetLocation();
4064     return false;
4065   }
4066   oat_writer->size_oat_dex_file_location_size_ += sizeof(dex_file_location_size_);
4067 
4068   if (!out->WriteFully(dex_file_location_data_, dex_file_location_size_)) {
4069     PLOG(ERROR) << "Failed to write dex file location data to " << out->GetLocation();
4070     return false;
4071   }
4072   oat_writer->size_oat_dex_file_location_data_ += dex_file_location_size_;
4073 
4074   if (!out->WriteFully(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_))) {
4075     PLOG(ERROR) << "Failed to write dex file location checksum to " << out->GetLocation();
4076     return false;
4077   }
4078   oat_writer->size_oat_dex_file_location_checksum_ += sizeof(dex_file_location_checksum_);
4079 
4080   if (!out->WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) {
4081     PLOG(ERROR) << "Failed to write dex file offset to " << out->GetLocation();
4082     return false;
4083   }
4084   oat_writer->size_oat_dex_file_offset_ += sizeof(dex_file_offset_);
4085 
4086   if (!out->WriteFully(&class_offsets_offset_, sizeof(class_offsets_offset_))) {
4087     PLOG(ERROR) << "Failed to write class offsets offset to " << out->GetLocation();
4088     return false;
4089   }
4090   oat_writer->size_oat_dex_file_class_offsets_offset_ += sizeof(class_offsets_offset_);
4091 
4092   if (!out->WriteFully(&lookup_table_offset_, sizeof(lookup_table_offset_))) {
4093     PLOG(ERROR) << "Failed to write lookup table offset to " << out->GetLocation();
4094     return false;
4095   }
4096   oat_writer->size_oat_dex_file_lookup_table_offset_ += sizeof(lookup_table_offset_);
4097 
4098   if (!out->WriteFully(&dex_sections_layout_offset_, sizeof(dex_sections_layout_offset_))) {
4099     PLOG(ERROR) << "Failed to write dex section layout info to " << out->GetLocation();
4100     return false;
4101   }
4102   oat_writer->size_oat_dex_file_dex_layout_sections_offset_ += sizeof(dex_sections_layout_offset_);
4103 
4104   if (!out->WriteFully(&method_bss_mapping_offset_, sizeof(method_bss_mapping_offset_))) {
4105     PLOG(ERROR) << "Failed to write method bss mapping offset to " << out->GetLocation();
4106     return false;
4107   }
4108   oat_writer->size_oat_dex_file_method_bss_mapping_offset_ += sizeof(method_bss_mapping_offset_);
4109 
4110   if (!out->WriteFully(&type_bss_mapping_offset_, sizeof(type_bss_mapping_offset_))) {
4111     PLOG(ERROR) << "Failed to write type bss mapping offset to " << out->GetLocation();
4112     return false;
4113   }
4114   oat_writer->size_oat_dex_file_type_bss_mapping_offset_ += sizeof(type_bss_mapping_offset_);
4115 
4116   if (!out->WriteFully(&string_bss_mapping_offset_, sizeof(string_bss_mapping_offset_))) {
4117     PLOG(ERROR) << "Failed to write string bss mapping offset to " << out->GetLocation();
4118     return false;
4119   }
4120   oat_writer->size_oat_dex_file_string_bss_mapping_offset_ += sizeof(string_bss_mapping_offset_);
4121 
4122   return true;
4123 }
4124 
WriteClassOffsets(OatWriter * oat_writer,OutputStream * out)4125 bool OatWriter::OatDexFile::WriteClassOffsets(OatWriter* oat_writer, OutputStream* out) {
4126   if (!out->WriteFully(class_offsets_.data(), GetClassOffsetsRawSize())) {
4127     PLOG(ERROR) << "Failed to write oat class offsets for " << GetLocation()
4128                 << " to " << out->GetLocation();
4129     return false;
4130   }
4131   oat_writer->size_oat_class_offsets_ += GetClassOffsetsRawSize();
4132   return true;
4133 }
4134 
OatClass(const dchecked_vector<CompiledMethod * > & compiled_methods,uint32_t compiled_methods_with_code,uint16_t oat_class_type)4135 OatWriter::OatClass::OatClass(const dchecked_vector<CompiledMethod*>& compiled_methods,
4136                               uint32_t compiled_methods_with_code,
4137                               uint16_t oat_class_type)
4138     : compiled_methods_(compiled_methods) {
4139   const uint32_t num_methods = compiled_methods.size();
4140   CHECK_LE(compiled_methods_with_code, num_methods);
4141 
4142   oat_method_offsets_offsets_from_oat_class_.resize(num_methods);
4143 
4144   method_offsets_.resize(compiled_methods_with_code);
4145   method_headers_.resize(compiled_methods_with_code);
4146 
4147   uint32_t oat_method_offsets_offset_from_oat_class = OatClassHeader::SizeOf();
4148   // We only create this instance if there are at least some compiled.
4149   if (oat_class_type == kOatClassSomeCompiled) {
4150     method_bitmap_.reset(new BitVector(num_methods, false, Allocator::GetMallocAllocator()));
4151     method_bitmap_size_ = method_bitmap_->GetSizeOf();
4152     oat_method_offsets_offset_from_oat_class += sizeof(method_bitmap_size_);
4153     oat_method_offsets_offset_from_oat_class += method_bitmap_size_;
4154   } else {
4155     method_bitmap_ = nullptr;
4156     method_bitmap_size_ = 0;
4157   }
4158 
4159   for (size_t i = 0; i < num_methods; i++) {
4160     CompiledMethod* compiled_method = compiled_methods_[i];
4161     if (HasCompiledCode(compiled_method)) {
4162       oat_method_offsets_offsets_from_oat_class_[i] = oat_method_offsets_offset_from_oat_class;
4163       oat_method_offsets_offset_from_oat_class += sizeof(OatMethodOffsets);
4164       if (oat_class_type == kOatClassSomeCompiled) {
4165         method_bitmap_->SetBit(i);
4166       }
4167     } else {
4168       oat_method_offsets_offsets_from_oat_class_[i] = 0;
4169     }
4170   }
4171 }
4172 
SizeOf() const4173 size_t OatWriter::OatClass::SizeOf() const {
4174   return ((method_bitmap_size_ == 0) ? 0 : sizeof(method_bitmap_size_))
4175           + method_bitmap_size_
4176           + (sizeof(method_offsets_[0]) * method_offsets_.size());
4177 }
4178 
Write(OatWriter * oat_writer,OutputStream * out,const size_t file_offset) const4179 bool OatWriter::OatClassHeader::Write(OatWriter* oat_writer,
4180                                       OutputStream* out,
4181                                       const size_t file_offset) const {
4182   DCHECK_OFFSET_();
4183   if (!out->WriteFully(&status_, sizeof(status_))) {
4184     PLOG(ERROR) << "Failed to write class status to " << out->GetLocation();
4185     return false;
4186   }
4187   oat_writer->size_oat_class_status_ += sizeof(status_);
4188 
4189   if (!out->WriteFully(&type_, sizeof(type_))) {
4190     PLOG(ERROR) << "Failed to write oat class type to " << out->GetLocation();
4191     return false;
4192   }
4193   oat_writer->size_oat_class_type_ += sizeof(type_);
4194   return true;
4195 }
4196 
Write(OatWriter * oat_writer,OutputStream * out) const4197 bool OatWriter::OatClass::Write(OatWriter* oat_writer, OutputStream* out) const {
4198   if (method_bitmap_size_ != 0) {
4199     if (!out->WriteFully(&method_bitmap_size_, sizeof(method_bitmap_size_))) {
4200       PLOG(ERROR) << "Failed to write method bitmap size to " << out->GetLocation();
4201       return false;
4202     }
4203     oat_writer->size_oat_class_method_bitmaps_ += sizeof(method_bitmap_size_);
4204 
4205     if (!out->WriteFully(method_bitmap_->GetRawStorage(), method_bitmap_size_)) {
4206       PLOG(ERROR) << "Failed to write method bitmap to " << out->GetLocation();
4207       return false;
4208     }
4209     oat_writer->size_oat_class_method_bitmaps_ += method_bitmap_size_;
4210   }
4211 
4212   if (!out->WriteFully(method_offsets_.data(), GetMethodOffsetsRawSize())) {
4213     PLOG(ERROR) << "Failed to write method offsets to " << out->GetLocation();
4214     return false;
4215   }
4216   oat_writer->size_oat_class_method_offsets_ += GetMethodOffsetsRawSize();
4217   return true;
4218 }
4219 
GetDebugInfo() const4220 debug::DebugInfo OatWriter::GetDebugInfo() const {
4221   debug::DebugInfo debug_info{};
4222   debug_info.compiled_methods = ArrayRef<const debug::MethodDebugInfo>(method_info_);
4223   if (VdexWillContainDexFiles()) {
4224     DCHECK_EQ(dex_files_->size(), oat_dex_files_.size());
4225     for (size_t i = 0, size = dex_files_->size(); i != size; ++i) {
4226       const DexFile* dex_file = (*dex_files_)[i];
4227       const OatDexFile& oat_dex_file = oat_dex_files_[i];
4228       uint32_t dex_file_offset = oat_dex_file.dex_file_offset_;
4229       if (dex_file_offset != 0) {
4230         debug_info.dex_files.emplace(dex_file_offset, dex_file);
4231       }
4232     }
4233   }
4234   return debug_info;
4235 }
4236 
4237 }  // namespace linker
4238 }  // namespace art
4239