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 <unistd.h>
20 #include <zlib.h>
21 
22 #include "arch/arm64/instruction_set_features_arm64.h"
23 #include "art_method-inl.h"
24 #include "base/allocator.h"
25 #include "base/bit_vector.h"
26 #include "base/enums.h"
27 #include "base/file_magic.h"
28 #include "base/stl_util.h"
29 #include "base/unix_file/fd_file.h"
30 #include "class_linker.h"
31 #include "compiled_class.h"
32 #include "compiled_method.h"
33 #include "debug/method_debug_info.h"
34 #include "dex/verification_results.h"
35 #include "dex_file-inl.h"
36 #include "dexlayout.h"
37 #include "driver/compiler_driver.h"
38 #include "driver/compiler_options.h"
39 #include "gc/space/image_space.h"
40 #include "gc/space/space.h"
41 #include "handle_scope-inl.h"
42 #include "image_writer.h"
43 #include "linker/buffered_output_stream.h"
44 #include "linker/file_output_stream.h"
45 #include "linker/multi_oat_relative_patcher.h"
46 #include "linker/output_stream.h"
47 #include "mirror/array.h"
48 #include "mirror/class_loader.h"
49 #include "mirror/dex_cache-inl.h"
50 #include "mirror/object-inl.h"
51 #include "oat_quick_method_header.h"
52 #include "os.h"
53 #include "safe_map.h"
54 #include "scoped_thread_state_change-inl.h"
55 #include "type_lookup_table.h"
56 #include "utils/dex_cache_arrays_layout-inl.h"
57 #include "vdex_file.h"
58 #include "verifier/verifier_deps.h"
59 #include "zip_archive.h"
60 
61 namespace art {
62 
63 namespace {  // anonymous namespace
64 
65 typedef DexFile::Header __attribute__((aligned(1))) UnalignedDexFileHeader;
66 
AsUnalignedDexFileHeader(const uint8_t * raw_data)67 const UnalignedDexFileHeader* AsUnalignedDexFileHeader(const uint8_t* raw_data) {
68     return reinterpret_cast<const UnalignedDexFileHeader*>(raw_data);
69 }
70 
71 class ChecksumUpdatingOutputStream : public OutputStream {
72  public:
ChecksumUpdatingOutputStream(OutputStream * out,OatHeader * oat_header)73   ChecksumUpdatingOutputStream(OutputStream* out, OatHeader* oat_header)
74       : OutputStream(out->GetLocation()), out_(out), oat_header_(oat_header) { }
75 
WriteFully(const void * buffer,size_t byte_count)76   bool WriteFully(const void* buffer, size_t byte_count) OVERRIDE {
77     oat_header_->UpdateChecksum(buffer, byte_count);
78     return out_->WriteFully(buffer, byte_count);
79   }
80 
Seek(off_t offset,Whence whence)81   off_t Seek(off_t offset, Whence whence) OVERRIDE {
82     return out_->Seek(offset, whence);
83   }
84 
Flush()85   bool Flush() OVERRIDE {
86     return out_->Flush();
87   }
88 
89  private:
90   OutputStream* const out_;
91   OatHeader* const oat_header_;
92 };
93 
CodeAlignmentSize(uint32_t header_offset,const CompiledMethod & compiled_method)94 inline uint32_t CodeAlignmentSize(uint32_t header_offset, const CompiledMethod& compiled_method) {
95   // We want to align the code rather than the preheader.
96   uint32_t unaligned_code_offset = header_offset + sizeof(OatQuickMethodHeader);
97   uint32_t aligned_code_offset =  compiled_method.AlignCode(unaligned_code_offset);
98   return aligned_code_offset - unaligned_code_offset;
99 }
100 
101 }  // anonymous namespace
102 
103 // Defines the location of the raw dex file to write.
104 class OatWriter::DexFileSource {
105  public:
106   enum Type {
107     kNone,
108     kZipEntry,
109     kRawFile,
110     kRawData,
111   };
112 
DexFileSource(ZipEntry * zip_entry)113   explicit DexFileSource(ZipEntry* zip_entry)
114       : type_(kZipEntry), source_(zip_entry) {
115     DCHECK(source_ != nullptr);
116   }
117 
DexFileSource(File * raw_file)118   explicit DexFileSource(File* raw_file)
119       : type_(kRawFile), source_(raw_file) {
120     DCHECK(source_ != nullptr);
121   }
122 
DexFileSource(const uint8_t * dex_file)123   explicit DexFileSource(const uint8_t* dex_file)
124       : type_(kRawData), source_(dex_file) {
125     DCHECK(source_ != nullptr);
126   }
127 
GetType() const128   Type GetType() const { return type_; }
IsZipEntry() const129   bool IsZipEntry() const { return type_ == kZipEntry; }
IsRawFile() const130   bool IsRawFile() const { return type_ == kRawFile; }
IsRawData() const131   bool IsRawData() const { return type_ == kRawData; }
132 
GetZipEntry() const133   ZipEntry* GetZipEntry() const {
134     DCHECK(IsZipEntry());
135     DCHECK(source_ != nullptr);
136     return static_cast<ZipEntry*>(const_cast<void*>(source_));
137   }
138 
GetRawFile() const139   File* GetRawFile() const {
140     DCHECK(IsRawFile());
141     DCHECK(source_ != nullptr);
142     return static_cast<File*>(const_cast<void*>(source_));
143   }
144 
GetRawData() const145   const uint8_t* GetRawData() const {
146     DCHECK(IsRawData());
147     DCHECK(source_ != nullptr);
148     return static_cast<const uint8_t*>(source_);
149   }
150 
Clear()151   void Clear() {
152     type_ = kNone;
153     source_ = nullptr;
154   }
155 
156  private:
157   Type type_;
158   const void* source_;
159 };
160 
161 class OatWriter::OatClass {
162  public:
163   OatClass(size_t offset,
164            const dchecked_vector<CompiledMethod*>& compiled_methods,
165            uint32_t num_non_null_compiled_methods,
166            mirror::Class::Status status);
167   OatClass(OatClass&& src) = default;
168   size_t GetOatMethodOffsetsOffsetFromOatHeader(size_t class_def_method_index_) const;
169   size_t GetOatMethodOffsetsOffsetFromOatClass(size_t class_def_method_index_) const;
170   size_t SizeOf() const;
171   bool Write(OatWriter* oat_writer, OutputStream* out, const size_t file_offset) const;
172 
GetCompiledMethod(size_t class_def_method_index) const173   CompiledMethod* GetCompiledMethod(size_t class_def_method_index) const {
174     return compiled_methods_[class_def_method_index];
175   }
176 
177   // Offset of start of OatClass from beginning of OatHeader. It is
178   // used to validate file position when writing.
179   size_t offset_;
180 
181   // CompiledMethods for each class_def_method_index, or null if no method is available.
182   dchecked_vector<CompiledMethod*> compiled_methods_;
183 
184   // Offset from OatClass::offset_ to the OatMethodOffsets for the
185   // class_def_method_index. If 0, it means the corresponding
186   // CompiledMethod entry in OatClass::compiled_methods_ should be
187   // null and that the OatClass::type_ should be kOatClassBitmap.
188   dchecked_vector<uint32_t> oat_method_offsets_offsets_from_oat_class_;
189 
190   // Data to write.
191 
192   static_assert(mirror::Class::Status::kStatusMax < (1 << 16), "class status won't fit in 16bits");
193   int16_t status_;
194 
195   static_assert(OatClassType::kOatClassMax < (1 << 16), "oat_class type won't fit in 16bits");
196   uint16_t type_;
197 
198   uint32_t method_bitmap_size_;
199 
200   // bit vector indexed by ClassDef method index. When
201   // OatClassType::type_ is kOatClassBitmap, a set bit indicates the
202   // method has an OatMethodOffsets in methods_offsets_, otherwise
203   // the entry was ommited to save space. If OatClassType::type_ is
204   // not is kOatClassBitmap, the bitmap will be null.
205   std::unique_ptr<BitVector> method_bitmap_;
206 
207   // OatMethodOffsets and OatMethodHeaders for each CompiledMethod
208   // present in the OatClass. Note that some may be missing if
209   // OatClass::compiled_methods_ contains null values (and
210   // oat_method_offsets_offsets_from_oat_class_ should contain 0
211   // values in this case).
212   dchecked_vector<OatMethodOffsets> method_offsets_;
213   dchecked_vector<OatQuickMethodHeader> method_headers_;
214 
215  private:
GetMethodOffsetsRawSize() const216   size_t GetMethodOffsetsRawSize() const {
217     return method_offsets_.size() * sizeof(method_offsets_[0]);
218   }
219 
220   DISALLOW_COPY_AND_ASSIGN(OatClass);
221 };
222 
223 class OatWriter::OatDexFile {
224  public:
225   OatDexFile(const char* dex_file_location,
226              DexFileSource source,
227              CreateTypeLookupTable create_type_lookup_table);
228   OatDexFile(OatDexFile&& src) = default;
229 
GetLocation() const230   const char* GetLocation() const {
231     return dex_file_location_data_;
232   }
233 
234   void ReserveClassOffsets(OatWriter* oat_writer);
235 
236   size_t SizeOf() const;
237   bool Write(OatWriter* oat_writer, OutputStream* out) const;
238   bool WriteClassOffsets(OatWriter* oat_writer, OutputStream* out);
239 
240   // The source of the dex file.
241   DexFileSource source_;
242 
243   // Whether to create the type lookup table.
244   CreateTypeLookupTable create_type_lookup_table_;
245 
246   // Dex file size. Initialized when writing the dex file.
247   size_t dex_file_size_;
248 
249   // Offset of start of OatDexFile from beginning of OatHeader. It is
250   // used to validate file position when writing.
251   size_t offset_;
252 
253   // Data to write.
254   uint32_t dex_file_location_size_;
255   const char* dex_file_location_data_;
256   uint32_t dex_file_location_checksum_;
257   uint32_t dex_file_offset_;
258   uint32_t class_offsets_offset_;
259   uint32_t lookup_table_offset_;
260 
261   // Data to write to a separate section.
262   dchecked_vector<uint32_t> class_offsets_;
263 
264  private:
GetClassOffsetsRawSize() const265   size_t GetClassOffsetsRawSize() const {
266     return class_offsets_.size() * sizeof(class_offsets_[0]);
267   }
268 
269   DISALLOW_COPY_AND_ASSIGN(OatDexFile);
270 };
271 
272 #define DCHECK_OFFSET() \
273   DCHECK_EQ(static_cast<off_t>(file_offset + relative_offset), out->Seek(0, kSeekCurrent)) \
274     << "file_offset=" << file_offset << " relative_offset=" << relative_offset
275 
276 #define DCHECK_OFFSET_() \
277   DCHECK_EQ(static_cast<off_t>(file_offset + offset_), out->Seek(0, kSeekCurrent)) \
278     << "file_offset=" << file_offset << " offset_=" << offset_
279 
OatWriter(bool compiling_boot_image,TimingLogger * timings,ProfileCompilationInfo * info)280 OatWriter::OatWriter(bool compiling_boot_image, TimingLogger* timings, ProfileCompilationInfo* info)
281   : write_state_(WriteState::kAddingDexFileSources),
282     timings_(timings),
283     raw_dex_files_(),
284     zip_archives_(),
285     zipped_dex_files_(),
286     zipped_dex_file_locations_(),
287     compiler_driver_(nullptr),
288     image_writer_(nullptr),
289     compiling_boot_image_(compiling_boot_image),
290     dex_files_(nullptr),
291     vdex_size_(0u),
292     vdex_dex_files_offset_(0u),
293     vdex_verifier_deps_offset_(0u),
294     vdex_quickening_info_offset_(0u),
295     oat_size_(0u),
296     bss_start_(0u),
297     bss_size_(0u),
298     bss_roots_offset_(0u),
299     bss_type_entries_(),
300     bss_string_entries_(),
301     oat_data_offset_(0u),
302     oat_header_(nullptr),
303     size_vdex_header_(0),
304     size_vdex_checksums_(0),
305     size_dex_file_alignment_(0),
306     size_executable_offset_alignment_(0),
307     size_oat_header_(0),
308     size_oat_header_key_value_store_(0),
309     size_dex_file_(0),
310     size_verifier_deps_(0),
311     size_verifier_deps_alignment_(0),
312     size_quickening_info_(0),
313     size_quickening_info_alignment_(0),
314     size_interpreter_to_interpreter_bridge_(0),
315     size_interpreter_to_compiled_code_bridge_(0),
316     size_jni_dlsym_lookup_(0),
317     size_quick_generic_jni_trampoline_(0),
318     size_quick_imt_conflict_trampoline_(0),
319     size_quick_resolution_trampoline_(0),
320     size_quick_to_interpreter_bridge_(0),
321     size_trampoline_alignment_(0),
322     size_method_header_(0),
323     size_code_(0),
324     size_code_alignment_(0),
325     size_relative_call_thunks_(0),
326     size_misc_thunks_(0),
327     size_vmap_table_(0),
328     size_method_info_(0),
329     size_oat_dex_file_location_size_(0),
330     size_oat_dex_file_location_data_(0),
331     size_oat_dex_file_location_checksum_(0),
332     size_oat_dex_file_offset_(0),
333     size_oat_dex_file_class_offsets_offset_(0),
334     size_oat_dex_file_lookup_table_offset_(0),
335     size_oat_lookup_table_alignment_(0),
336     size_oat_lookup_table_(0),
337     size_oat_class_offsets_alignment_(0),
338     size_oat_class_offsets_(0),
339     size_oat_class_type_(0),
340     size_oat_class_status_(0),
341     size_oat_class_method_bitmaps_(0),
342     size_oat_class_method_offsets_(0),
343     relative_patcher_(nullptr),
344     absolute_patch_locations_(),
345     profile_compilation_info_(info) {
346 }
347 
AddDexFileSource(const char * filename,const char * location,CreateTypeLookupTable create_type_lookup_table)348 bool OatWriter::AddDexFileSource(const char* filename,
349                                  const char* location,
350                                  CreateTypeLookupTable create_type_lookup_table) {
351   DCHECK(write_state_ == WriteState::kAddingDexFileSources);
352   uint32_t magic;
353   std::string error_msg;
354   File fd = OpenAndReadMagic(filename, &magic, &error_msg);
355   if (fd.Fd() == -1) {
356     PLOG(ERROR) << "Failed to read magic number from dex file: '" << filename << "'";
357     return false;
358   } else if (IsDexMagic(magic)) {
359     // The file is open for reading, not writing, so it's OK to let the File destructor
360     // close it without checking for explicit Close(), so pass checkUsage = false.
361     raw_dex_files_.emplace_back(new File(fd.Release(), location, /* checkUsage */ false));
362     oat_dex_files_.emplace_back(location,
363                                 DexFileSource(raw_dex_files_.back().get()),
364                                 create_type_lookup_table);
365   } else if (IsZipMagic(magic)) {
366     if (!AddZippedDexFilesSource(std::move(fd), location, create_type_lookup_table)) {
367       return false;
368     }
369   } else {
370     LOG(ERROR) << "Expected valid zip or dex file: '" << filename << "'";
371     return false;
372   }
373   return true;
374 }
375 
376 // 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)377 bool OatWriter::AddZippedDexFilesSource(File&& zip_fd,
378                                         const char* location,
379                                         CreateTypeLookupTable create_type_lookup_table) {
380   DCHECK(write_state_ == WriteState::kAddingDexFileSources);
381   std::string error_msg;
382   zip_archives_.emplace_back(ZipArchive::OpenFromFd(zip_fd.Release(), location, &error_msg));
383   ZipArchive* zip_archive = zip_archives_.back().get();
384   if (zip_archive == nullptr) {
385     LOG(ERROR) << "Failed to open zip from file descriptor for '" << location << "': "
386         << error_msg;
387     return false;
388   }
389   for (size_t i = 0; ; ++i) {
390     std::string entry_name = DexFile::GetMultiDexClassesDexName(i);
391     std::unique_ptr<ZipEntry> entry(zip_archive->Find(entry_name.c_str(), &error_msg));
392     if (entry == nullptr) {
393       break;
394     }
395     zipped_dex_files_.push_back(std::move(entry));
396     zipped_dex_file_locations_.push_back(DexFile::GetMultiDexLocation(i, location));
397     const char* full_location = zipped_dex_file_locations_.back().c_str();
398     oat_dex_files_.emplace_back(full_location,
399                                 DexFileSource(zipped_dex_files_.back().get()),
400                                 create_type_lookup_table);
401   }
402   if (zipped_dex_file_locations_.empty()) {
403     LOG(ERROR) << "No dex files in zip file '" << location << "': " << error_msg;
404     return false;
405   }
406   return true;
407 }
408 
409 // 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)410 bool OatWriter::AddVdexDexFilesSource(const VdexFile& vdex_file,
411                                       const char* location,
412                                       CreateTypeLookupTable create_type_lookup_table) {
413   DCHECK(write_state_ == WriteState::kAddingDexFileSources);
414   const uint8_t* current_dex_data = nullptr;
415   for (size_t i = 0; i < vdex_file.GetHeader().GetNumberOfDexFiles(); ++i) {
416     current_dex_data = vdex_file.GetNextDexFileData(current_dex_data);
417     if (current_dex_data == nullptr) {
418       LOG(ERROR) << "Unexpected number of dex files in vdex " << location;
419       return false;
420     }
421     if (!DexFile::IsMagicValid(current_dex_data)) {
422       LOG(ERROR) << "Invalid magic in vdex file created from " << location;
423       return false;
424     }
425     // We used `zipped_dex_file_locations_` to keep the strings in memory.
426     zipped_dex_file_locations_.push_back(DexFile::GetMultiDexLocation(i, location));
427     const char* full_location = zipped_dex_file_locations_.back().c_str();
428     oat_dex_files_.emplace_back(full_location,
429                                 DexFileSource(current_dex_data),
430                                 create_type_lookup_table);
431     oat_dex_files_.back().dex_file_location_checksum_ = vdex_file.GetLocationChecksum(i);
432   }
433 
434   if (vdex_file.GetNextDexFileData(current_dex_data) != nullptr) {
435     LOG(ERROR) << "Unexpected number of dex files in vdex " << location;
436     return false;
437   }
438 
439   if (oat_dex_files_.empty()) {
440     LOG(ERROR) << "No dex files in vdex file created from " << location;
441     return false;
442   }
443   return true;
444 }
445 
446 // 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)447 bool OatWriter::AddRawDexFileSource(const ArrayRef<const uint8_t>& data,
448                                     const char* location,
449                                     uint32_t location_checksum,
450                                     CreateTypeLookupTable create_type_lookup_table) {
451   DCHECK(write_state_ == WriteState::kAddingDexFileSources);
452   if (data.size() < sizeof(DexFile::Header)) {
453     LOG(ERROR) << "Provided data is shorter than dex file header. size: "
454                << data.size() << " File: " << location;
455     return false;
456   }
457   if (!ValidateDexFileHeader(data.data(), location)) {
458     return false;
459   }
460   const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(data.data());
461   if (data.size() < header->file_size_) {
462     LOG(ERROR) << "Truncated dex file data. Data size: " << data.size()
463                << " file size from header: " << header->file_size_ << " File: " << location;
464     return false;
465   }
466 
467   oat_dex_files_.emplace_back(location, DexFileSource(data.data()), create_type_lookup_table);
468   oat_dex_files_.back().dex_file_location_checksum_ = location_checksum;
469   return true;
470 }
471 
GetSourceLocations() const472 dchecked_vector<const char*> OatWriter::GetSourceLocations() const {
473   dchecked_vector<const char*> locations;
474   locations.reserve(oat_dex_files_.size());
475   for (const OatDexFile& oat_dex_file : oat_dex_files_) {
476     locations.push_back(oat_dex_file.GetLocation());
477   }
478   return locations;
479 }
480 
WriteAndOpenDexFiles(File * vdex_file,OutputStream * oat_rodata,InstructionSet instruction_set,const InstructionSetFeatures * instruction_set_features,SafeMap<std::string,std::string> * key_value_store,bool verify,bool update_input_vdex,std::unique_ptr<MemMap> * opened_dex_files_map,std::vector<std::unique_ptr<const DexFile>> * opened_dex_files)481 bool OatWriter::WriteAndOpenDexFiles(
482     File* vdex_file,
483     OutputStream* oat_rodata,
484     InstructionSet instruction_set,
485     const InstructionSetFeatures* instruction_set_features,
486     SafeMap<std::string, std::string>* key_value_store,
487     bool verify,
488     bool update_input_vdex,
489     /*out*/ std::unique_ptr<MemMap>* opened_dex_files_map,
490     /*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files) {
491   CHECK(write_state_ == WriteState::kAddingDexFileSources);
492 
493   // Record the ELF rodata section offset, i.e. the beginning of the OAT data.
494   if (!RecordOatDataOffset(oat_rodata)) {
495      return false;
496   }
497 
498   std::unique_ptr<MemMap> dex_files_map;
499   std::vector<std::unique_ptr<const DexFile>> dex_files;
500 
501   // Initialize VDEX and OAT headers.
502   if (kIsVdexEnabled) {
503     // Reserve space for Vdex header and checksums.
504     vdex_size_ = sizeof(VdexFile::Header) + oat_dex_files_.size() * sizeof(VdexFile::VdexChecksum);
505   }
506   size_t oat_data_offset = InitOatHeader(instruction_set,
507                                         instruction_set_features,
508                                         dchecked_integral_cast<uint32_t>(oat_dex_files_.size()),
509                                         key_value_store);
510   oat_size_ = InitOatDexFiles(oat_data_offset);
511 
512   ChecksumUpdatingOutputStream checksum_updating_rodata(oat_rodata, oat_header_.get());
513 
514   if (kIsVdexEnabled) {
515     std::unique_ptr<BufferedOutputStream> vdex_out(
516         MakeUnique<BufferedOutputStream>(MakeUnique<FileOutputStream>(vdex_file)));
517     // Write DEX files into VDEX, mmap and open them.
518     if (!WriteDexFiles(vdex_out.get(), vdex_file, update_input_vdex) ||
519         !OpenDexFiles(vdex_file, verify, &dex_files_map, &dex_files)) {
520       return false;
521     }
522   } else {
523     DCHECK(!update_input_vdex);
524     // Write DEX files into OAT, mmap and open them.
525     if (!WriteDexFiles(oat_rodata, vdex_file, update_input_vdex) ||
526         !OpenDexFiles(vdex_file, verify, &dex_files_map, &dex_files)) {
527       return false;
528     }
529 
530     // Do a bulk checksum update for Dex[]. Doing it piece by piece would be
531     // difficult because we're not using the OutputStream directly.
532     if (!oat_dex_files_.empty()) {
533       size_t size = oat_size_ - oat_dex_files_[0].dex_file_offset_;
534       oat_header_->UpdateChecksum(dex_files_map->Begin(), size);
535     }
536   }
537 
538   // Write TypeLookupTables into OAT.
539   if (!WriteTypeLookupTables(&checksum_updating_rodata, dex_files)) {
540     return false;
541   }
542 
543   // Reserve space for class offsets in OAT and update class_offsets_offset_.
544   for (OatDexFile& oat_dex_file : oat_dex_files_) {
545     oat_dex_file.ReserveClassOffsets(this);
546   }
547 
548   // Write OatDexFiles into OAT. Needs to be done last, once offsets are collected.
549   if (!WriteOatDexFiles(&checksum_updating_rodata)) {
550     return false;
551   }
552 
553   *opened_dex_files_map = std::move(dex_files_map);
554   *opened_dex_files = std::move(dex_files);
555   write_state_ = WriteState::kPrepareLayout;
556   return true;
557 }
558 
PrepareLayout(linker::MultiOatRelativePatcher * relative_patcher)559 void OatWriter::PrepareLayout(linker::MultiOatRelativePatcher* relative_patcher) {
560   CHECK(write_state_ == WriteState::kPrepareLayout);
561 
562   relative_patcher_ = relative_patcher;
563   SetMultiOatRelativePatcherAdjustment();
564 
565   if (compiling_boot_image_) {
566     CHECK(image_writer_ != nullptr);
567   }
568   InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
569   CHECK_EQ(instruction_set, oat_header_->GetInstructionSet());
570 
571   uint32_t offset = oat_size_;
572   {
573     TimingLogger::ScopedTiming split("InitOatClasses", timings_);
574     offset = InitOatClasses(offset);
575   }
576   {
577     TimingLogger::ScopedTiming split("InitOatMaps", timings_);
578     offset = InitOatMaps(offset);
579   }
580   {
581     TimingLogger::ScopedTiming split("InitOatCode", timings_);
582     offset = InitOatCode(offset);
583   }
584   {
585     TimingLogger::ScopedTiming split("InitOatCodeDexFiles", timings_);
586     offset = InitOatCodeDexFiles(offset);
587   }
588   oat_size_ = offset;
589 
590   {
591     TimingLogger::ScopedTiming split("InitBssLayout", timings_);
592     InitBssLayout(instruction_set);
593   }
594 
595   CHECK_EQ(dex_files_->size(), oat_dex_files_.size());
596   if (compiling_boot_image_) {
597     CHECK_EQ(image_writer_ != nullptr,
598              oat_header_->GetStoreValueByKey(OatHeader::kImageLocationKey) == nullptr);
599   }
600 
601   write_state_ = WriteState::kWriteRoData;
602 }
603 
~OatWriter()604 OatWriter::~OatWriter() {
605 }
606 
607 class OatWriter::DexMethodVisitor {
608  public:
DexMethodVisitor(OatWriter * writer,size_t offset)609   DexMethodVisitor(OatWriter* writer, size_t offset)
610     : writer_(writer),
611       offset_(offset),
612       dex_file_(nullptr),
613       class_def_index_(DexFile::kDexNoIndex) {
614   }
615 
StartClass(const DexFile * dex_file,size_t class_def_index)616   virtual bool StartClass(const DexFile* dex_file, size_t class_def_index) {
617     DCHECK(dex_file_ == nullptr);
618     DCHECK_EQ(class_def_index_, DexFile::kDexNoIndex);
619     dex_file_ = dex_file;
620     class_def_index_ = class_def_index;
621     return true;
622   }
623 
624   virtual bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) = 0;
625 
EndClass()626   virtual bool EndClass() {
627     if (kIsDebugBuild) {
628       dex_file_ = nullptr;
629       class_def_index_ = DexFile::kDexNoIndex;
630     }
631     return true;
632   }
633 
GetOffset() const634   size_t GetOffset() const {
635     return offset_;
636   }
637 
638  protected:
~DexMethodVisitor()639   virtual ~DexMethodVisitor() { }
640 
641   OatWriter* const writer_;
642 
643   // The offset is usually advanced for each visited method by the derived class.
644   size_t offset_;
645 
646   // The dex file and class def index are set in StartClass().
647   const DexFile* dex_file_;
648   size_t class_def_index_;
649 };
650 
651 class OatWriter::OatDexMethodVisitor : public DexMethodVisitor {
652  public:
OatDexMethodVisitor(OatWriter * writer,size_t offset)653   OatDexMethodVisitor(OatWriter* writer, size_t offset)
654     : DexMethodVisitor(writer, offset),
655       oat_class_index_(0u),
656       method_offsets_index_(0u) {
657   }
658 
StartClass(const DexFile * dex_file,size_t class_def_index)659   bool StartClass(const DexFile* dex_file, size_t class_def_index) {
660     DexMethodVisitor::StartClass(dex_file, class_def_index);
661     DCHECK_LT(oat_class_index_, writer_->oat_classes_.size());
662     method_offsets_index_ = 0u;
663     return true;
664   }
665 
EndClass()666   bool EndClass() {
667     ++oat_class_index_;
668     return DexMethodVisitor::EndClass();
669   }
670 
671  protected:
672   size_t oat_class_index_;
673   size_t method_offsets_index_;
674 };
675 
676 class OatWriter::InitOatClassesMethodVisitor : public DexMethodVisitor {
677  public:
InitOatClassesMethodVisitor(OatWriter * writer,size_t offset)678   InitOatClassesMethodVisitor(OatWriter* writer, size_t offset)
679     : DexMethodVisitor(writer, offset),
680       compiled_methods_(),
681       num_non_null_compiled_methods_(0u) {
682     size_t num_classes = 0u;
683     for (const OatDexFile& oat_dex_file : writer_->oat_dex_files_) {
684       num_classes += oat_dex_file.class_offsets_.size();
685     }
686     writer_->oat_classes_.reserve(num_classes);
687     compiled_methods_.reserve(256u);
688   }
689 
StartClass(const DexFile * dex_file,size_t class_def_index)690   bool StartClass(const DexFile* dex_file, size_t class_def_index) {
691     DexMethodVisitor::StartClass(dex_file, class_def_index);
692     compiled_methods_.clear();
693     num_non_null_compiled_methods_ = 0u;
694     return true;
695   }
696 
VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED,const ClassDataItemIterator & it)697   bool VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED,
698                    const ClassDataItemIterator& it) {
699     // Fill in the compiled_methods_ array for methods that have a
700     // CompiledMethod. We track the number of non-null entries in
701     // num_non_null_compiled_methods_ since we only want to allocate
702     // OatMethodOffsets for the compiled methods.
703     uint32_t method_idx = it.GetMemberIndex();
704     CompiledMethod* compiled_method =
705         writer_->compiler_driver_->GetCompiledMethod(MethodReference(dex_file_, method_idx));
706     compiled_methods_.push_back(compiled_method);
707     if (compiled_method != nullptr) {
708         ++num_non_null_compiled_methods_;
709     }
710     return true;
711   }
712 
EndClass()713   bool EndClass() {
714     ClassReference class_ref(dex_file_, class_def_index_);
715     CompiledClass* compiled_class = writer_->compiler_driver_->GetCompiledClass(class_ref);
716     mirror::Class::Status status;
717     if (compiled_class != nullptr) {
718       status = compiled_class->GetStatus();
719     } else if (writer_->compiler_driver_->GetVerificationResults()->IsClassRejected(class_ref)) {
720       // The oat class status is used only for verification of resolved classes,
721       // so use kStatusErrorResolved whether the class was resolved or unresolved
722       // during compile-time verification.
723       status = mirror::Class::kStatusErrorResolved;
724     } else {
725       status = mirror::Class::kStatusNotReady;
726     }
727 
728     writer_->oat_classes_.emplace_back(offset_,
729                                        compiled_methods_,
730                                        num_non_null_compiled_methods_,
731                                        status);
732     offset_ += writer_->oat_classes_.back().SizeOf();
733     return DexMethodVisitor::EndClass();
734   }
735 
736  private:
737   dchecked_vector<CompiledMethod*> compiled_methods_;
738   size_t num_non_null_compiled_methods_;
739 };
740 
741 class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor {
742  public:
InitCodeMethodVisitor(OatWriter * writer,size_t offset,size_t quickening_info_offset)743   InitCodeMethodVisitor(OatWriter* writer, size_t offset, size_t quickening_info_offset)
744     : OatDexMethodVisitor(writer, offset),
745       debuggable_(writer->GetCompilerDriver()->GetCompilerOptions().GetDebuggable()),
746       current_quickening_info_offset_(quickening_info_offset) {
747     writer_->absolute_patch_locations_.reserve(
748         writer_->compiler_driver_->GetNonRelativeLinkerPatchCount());
749   }
750 
EndClass()751   bool EndClass() {
752     OatDexMethodVisitor::EndClass();
753     if (oat_class_index_ == writer_->oat_classes_.size()) {
754       offset_ = writer_->relative_patcher_->ReserveSpaceEnd(offset_);
755     }
756     return true;
757   }
758 
VisitMethod(size_t class_def_method_index,const ClassDataItemIterator & it)759   bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it)
760       REQUIRES_SHARED(Locks::mutator_lock_) {
761     OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
762     CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
763 
764     if (it.GetMethodCodeItem() != nullptr) {
765       current_quickening_info_offset_ += sizeof(uint32_t);
766     }
767     if (compiled_method != nullptr) {
768       // Derived from CompiledMethod.
769       uint32_t quick_code_offset = 0;
770 
771       ArrayRef<const uint8_t> quick_code = compiled_method->GetQuickCode();
772       uint32_t code_size = quick_code.size() * sizeof(uint8_t);
773       uint32_t thumb_offset = compiled_method->CodeDelta();
774 
775       // Deduplicate code arrays if we are not producing debuggable code.
776       bool deduped = true;
777       MethodReference method_ref(dex_file_, it.GetMemberIndex());
778       if (debuggable_) {
779         quick_code_offset = writer_->relative_patcher_->GetOffset(method_ref);
780         if (quick_code_offset != 0u) {
781           // Duplicate methods, we want the same code for both of them so that the oat writer puts
782           // the same code in both ArtMethods so that we do not get different oat code at runtime.
783         } else {
784           quick_code_offset = NewQuickCodeOffset(compiled_method, it, thumb_offset);
785           deduped = false;
786         }
787       } else {
788         quick_code_offset = dedupe_map_.GetOrCreate(
789             compiled_method,
790             [this, &deduped, compiled_method, &it, thumb_offset]() {
791               deduped = false;
792               return NewQuickCodeOffset(compiled_method, it, thumb_offset);
793             });
794       }
795 
796       if (code_size != 0) {
797         if (writer_->relative_patcher_->GetOffset(method_ref) != 0u) {
798           // TODO: Should this be a hard failure?
799           LOG(WARNING) << "Multiple definitions of "
800               << method_ref.dex_file->PrettyMethod(method_ref.dex_method_index)
801               << " offsets " << writer_->relative_patcher_->GetOffset(method_ref)
802               << " " << quick_code_offset;
803         } else {
804           writer_->relative_patcher_->SetOffset(method_ref, quick_code_offset);
805         }
806       }
807 
808       // Update quick method header.
809       DCHECK_LT(method_offsets_index_, oat_class->method_headers_.size());
810       OatQuickMethodHeader* method_header = &oat_class->method_headers_[method_offsets_index_];
811       uint32_t vmap_table_offset = method_header->GetVmapTableOffset();
812       uint32_t method_info_offset = method_header->GetMethodInfoOffset();
813       // The code offset was 0 when the mapping/vmap table offset was set, so it's set
814       // to 0-offset and we need to adjust it by code_offset.
815       uint32_t code_offset = quick_code_offset - thumb_offset;
816       if (!compiled_method->GetQuickCode().empty()) {
817         // If the code is compiled, we write the offset of the stack map relative
818         // to the code,
819         if (vmap_table_offset != 0u) {
820           vmap_table_offset += code_offset;
821           DCHECK_LT(vmap_table_offset, code_offset);
822         }
823         if (method_info_offset != 0u) {
824           method_info_offset += code_offset;
825           DCHECK_LT(method_info_offset, code_offset);
826         }
827       } else {
828         CHECK(compiled_method->GetMethodInfo().empty());
829         if (kIsVdexEnabled) {
830           // We write the offset in the .vdex file.
831           DCHECK_EQ(vmap_table_offset, 0u);
832           vmap_table_offset = current_quickening_info_offset_;
833           ArrayRef<const uint8_t> vmap_table = compiled_method->GetVmapTable();
834           current_quickening_info_offset_ += vmap_table.size() * sizeof(vmap_table.front());
835         } else {
836           // We write the offset of the quickening info relative to the code.
837           vmap_table_offset += code_offset;
838           DCHECK_LT(vmap_table_offset, code_offset);
839         }
840       }
841       uint32_t frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
842       uint32_t core_spill_mask = compiled_method->GetCoreSpillMask();
843       uint32_t fp_spill_mask = compiled_method->GetFpSpillMask();
844       *method_header = OatQuickMethodHeader(vmap_table_offset,
845                                             method_info_offset,
846                                             frame_size_in_bytes,
847                                             core_spill_mask,
848                                             fp_spill_mask,
849                                             code_size);
850 
851       if (!deduped) {
852         // Update offsets. (Checksum is updated when writing.)
853         offset_ += sizeof(*method_header);  // Method header is prepended before code.
854         offset_ += code_size;
855         // Record absolute patch locations.
856         if (!compiled_method->GetPatches().empty()) {
857           uintptr_t base_loc = offset_ - code_size - writer_->oat_header_->GetExecutableOffset();
858           for (const LinkerPatch& patch : compiled_method->GetPatches()) {
859             if (!patch.IsPcRelative()) {
860               writer_->absolute_patch_locations_.push_back(base_loc + patch.LiteralOffset());
861             }
862             if (patch.GetType() == LinkerPatch::Type::kTypeBssEntry) {
863               TypeReference ref(patch.TargetTypeDexFile(), patch.TargetTypeIndex());
864               writer_->bss_type_entries_.Overwrite(ref, /* placeholder */ 0u);
865             }
866             if (patch.GetType() == LinkerPatch::Type::kStringBssEntry) {
867               StringReference ref(patch.TargetStringDexFile(), patch.TargetStringIndex());
868               writer_->bss_string_entries_.Overwrite(ref, /* placeholder */ 0u);
869             }
870           }
871         }
872       }
873 
874       const CompilerOptions& compiler_options = writer_->compiler_driver_->GetCompilerOptions();
875       // Exclude quickened dex methods (code_size == 0) since they have no native code.
876       if (compiler_options.GenerateAnyDebugInfo() && code_size != 0) {
877         bool has_code_info = method_header->IsOptimized();
878         // Record debug information for this function if we are doing that.
879         debug::MethodDebugInfo info = debug::MethodDebugInfo();
880         info.trampoline_name = nullptr;
881         info.dex_file = dex_file_;
882         info.class_def_index = class_def_index_;
883         info.dex_method_index = it.GetMemberIndex();
884         info.access_flags = it.GetMethodAccessFlags();
885         info.code_item = it.GetMethodCodeItem();
886         info.isa = compiled_method->GetInstructionSet();
887         info.deduped = deduped;
888         info.is_native_debuggable = compiler_options.GetNativeDebuggable();
889         info.is_optimized = method_header->IsOptimized();
890         info.is_code_address_text_relative = true;
891         info.code_address = code_offset - writer_->oat_header_->GetExecutableOffset();
892         info.code_size = code_size;
893         info.frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
894         info.code_info = has_code_info ? compiled_method->GetVmapTable().data() : nullptr;
895         info.cfi = compiled_method->GetCFIInfo();
896         writer_->method_info_.push_back(info);
897       }
898 
899       DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
900       OatMethodOffsets* offsets = &oat_class->method_offsets_[method_offsets_index_];
901       offsets->code_offset_ = quick_code_offset;
902       ++method_offsets_index_;
903     }
904 
905     return true;
906   }
907 
908  private:
909   struct CodeOffsetsKeyComparator {
operator ()art::OatWriter::InitCodeMethodVisitor::CodeOffsetsKeyComparator910     bool operator()(const CompiledMethod* lhs, const CompiledMethod* rhs) const {
911       // Code is deduplicated by CompilerDriver, compare only data pointers.
912       if (lhs->GetQuickCode().data() != rhs->GetQuickCode().data()) {
913         return lhs->GetQuickCode().data() < rhs->GetQuickCode().data();
914       }
915       // If the code is the same, all other fields are likely to be the same as well.
916       if (UNLIKELY(lhs->GetVmapTable().data() != rhs->GetVmapTable().data())) {
917         return lhs->GetVmapTable().data() < rhs->GetVmapTable().data();
918       }
919       if (UNLIKELY(lhs->GetMethodInfo().data() != rhs->GetMethodInfo().data())) {
920         return lhs->GetMethodInfo().data() < rhs->GetMethodInfo().data();
921       }
922       if (UNLIKELY(lhs->GetPatches().data() != rhs->GetPatches().data())) {
923         return lhs->GetPatches().data() < rhs->GetPatches().data();
924       }
925       return false;
926     }
927   };
928 
NewQuickCodeOffset(CompiledMethod * compiled_method,const ClassDataItemIterator & it,uint32_t thumb_offset)929   uint32_t NewQuickCodeOffset(CompiledMethod* compiled_method,
930                               const ClassDataItemIterator& it,
931                               uint32_t thumb_offset) {
932     offset_ = writer_->relative_patcher_->ReserveSpace(
933         offset_, compiled_method, MethodReference(dex_file_, it.GetMemberIndex()));
934     offset_ += CodeAlignmentSize(offset_, *compiled_method);
935     DCHECK_ALIGNED_PARAM(offset_ + sizeof(OatQuickMethodHeader),
936                          GetInstructionSetAlignment(compiled_method->GetInstructionSet()));
937     return offset_ + sizeof(OatQuickMethodHeader) + thumb_offset;
938   }
939 
940   // Deduplication is already done on a pointer basis by the compiler driver,
941   // so we can simply compare the pointers to find out if things are duplicated.
942   SafeMap<const CompiledMethod*, uint32_t, CodeOffsetsKeyComparator> dedupe_map_;
943 
944   // Cache of compiler's --debuggable option.
945   const bool debuggable_;
946 
947   // Offset in the vdex file for the quickening info.
948   uint32_t current_quickening_info_offset_;
949 };
950 
951 class OatWriter::InitMapMethodVisitor : public OatDexMethodVisitor {
952  public:
InitMapMethodVisitor(OatWriter * writer,size_t offset)953   InitMapMethodVisitor(OatWriter* writer, size_t offset)
954     : OatDexMethodVisitor(writer, offset) {
955   }
956 
VisitMethod(size_t class_def_method_index,const ClassDataItemIterator & it ATTRIBUTE_UNUSED)957   bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it ATTRIBUTE_UNUSED)
958       REQUIRES_SHARED(Locks::mutator_lock_) {
959     OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
960     CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
961 
962     if (compiled_method != nullptr) {
963       DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
964       // If vdex is enabled, we only emit the stack map of compiled code. The quickening info will
965       // be in the vdex file.
966       if (!compiled_method->GetQuickCode().empty() || !kIsVdexEnabled) {
967         DCHECK_EQ(oat_class->method_headers_[method_offsets_index_].GetVmapTableOffset(), 0u);
968 
969         ArrayRef<const uint8_t> map = compiled_method->GetVmapTable();
970         uint32_t map_size = map.size() * sizeof(map[0]);
971         if (map_size != 0u) {
972           size_t offset = dedupe_map_.GetOrCreate(
973               map.data(),
974               [this, map_size]() {
975                 uint32_t new_offset = offset_;
976                 offset_ += map_size;
977                 return new_offset;
978               });
979           // Code offset is not initialized yet, so set the map offset to 0u-offset.
980           DCHECK_EQ(oat_class->method_offsets_[method_offsets_index_].code_offset_, 0u);
981           oat_class->method_headers_[method_offsets_index_].SetVmapTableOffset(0u - offset);
982         }
983       }
984       ++method_offsets_index_;
985     }
986 
987     return true;
988   }
989 
990  private:
991   // Deduplication is already done on a pointer basis by the compiler driver,
992   // so we can simply compare the pointers to find out if things are duplicated.
993   SafeMap<const uint8_t*, uint32_t> dedupe_map_;
994 };
995 
996 class OatWriter::InitMethodInfoVisitor : public OatDexMethodVisitor {
997  public:
InitMethodInfoVisitor(OatWriter * writer,size_t offset)998   InitMethodInfoVisitor(OatWriter* writer, size_t offset) : OatDexMethodVisitor(writer, offset) {}
999 
VisitMethod(size_t class_def_method_index,const ClassDataItemIterator & it ATTRIBUTE_UNUSED)1000   bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it ATTRIBUTE_UNUSED)
1001       REQUIRES_SHARED(Locks::mutator_lock_) {
1002     OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
1003     CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1004 
1005     if (compiled_method != nullptr) {
1006       DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
1007       DCHECK_EQ(oat_class->method_headers_[method_offsets_index_].GetMethodInfoOffset(), 0u);
1008       ArrayRef<const uint8_t> map = compiled_method->GetMethodInfo();
1009       const uint32_t map_size = map.size() * sizeof(map[0]);
1010       if (map_size != 0u) {
1011         size_t offset = dedupe_map_.GetOrCreate(
1012             map.data(),
1013             [this, map_size]() {
1014               uint32_t new_offset = offset_;
1015               offset_ += map_size;
1016               return new_offset;
1017             });
1018         // Code offset is not initialized yet, so set the map offset to 0u-offset.
1019         DCHECK_EQ(oat_class->method_offsets_[method_offsets_index_].code_offset_, 0u);
1020         oat_class->method_headers_[method_offsets_index_].SetMethodInfoOffset(0u - offset);
1021       }
1022       ++method_offsets_index_;
1023     }
1024 
1025     return true;
1026   }
1027 
1028  private:
1029   // Deduplication is already done on a pointer basis by the compiler driver,
1030   // so we can simply compare the pointers to find out if things are duplicated.
1031   SafeMap<const uint8_t*, uint32_t> dedupe_map_;
1032 };
1033 
1034 class OatWriter::InitImageMethodVisitor : public OatDexMethodVisitor {
1035  public:
InitImageMethodVisitor(OatWriter * writer,size_t offset,const std::vector<const DexFile * > * dex_files)1036   InitImageMethodVisitor(OatWriter* writer,
1037                          size_t offset,
1038                          const std::vector<const DexFile*>* dex_files)
1039     : OatDexMethodVisitor(writer, offset),
1040       pointer_size_(GetInstructionSetPointerSize(writer_->compiler_driver_->GetInstructionSet())),
1041       dex_files_(dex_files),
1042       class_linker_(Runtime::Current()->GetClassLinker()) {
1043     }
1044 
1045   // Handle copied methods here. Copy pointer to quick code from
1046   // an origin method to a copied method only if they are
1047   // in the same oat file. If the origin and the copied methods are
1048   // in different oat files don't touch the copied method.
1049   // References to other oat files are not supported yet.
StartClass(const DexFile * dex_file,size_t class_def_index)1050   bool StartClass(const DexFile* dex_file, size_t class_def_index)
1051       REQUIRES_SHARED(Locks::mutator_lock_) {
1052     OatDexMethodVisitor::StartClass(dex_file, class_def_index);
1053     // Skip classes that are not in the image.
1054     if (!IsImageClass()) {
1055       return true;
1056     }
1057     ScopedObjectAccessUnchecked soa(Thread::Current());
1058     StackHandleScope<1> hs(soa.Self());
1059     Handle<mirror::DexCache> dex_cache = hs.NewHandle(
1060         class_linker_->FindDexCache(Thread::Current(), *dex_file));
1061     const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
1062     mirror::Class* klass = dex_cache->GetResolvedType(class_def.class_idx_);
1063     if (klass != nullptr) {
1064       for (ArtMethod& method : klass->GetCopiedMethods(pointer_size_)) {
1065         // Find origin method. Declaring class and dex_method_idx
1066         // in the copied method should be the same as in the origin
1067         // method.
1068         mirror::Class* declaring_class = method.GetDeclaringClass();
1069         ArtMethod* origin = declaring_class->FindDeclaredVirtualMethod(
1070             declaring_class->GetDexCache(),
1071             method.GetDexMethodIndex(),
1072             pointer_size_);
1073         CHECK(origin != nullptr);
1074         if (IsInOatFile(&declaring_class->GetDexFile())) {
1075           const void* code_ptr =
1076               origin->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size_);
1077           if (code_ptr == nullptr) {
1078             methods_to_process_.push_back(std::make_pair(&method, origin));
1079           } else {
1080             method.SetEntryPointFromQuickCompiledCodePtrSize(
1081                 code_ptr, pointer_size_);
1082           }
1083         }
1084       }
1085     }
1086     return true;
1087   }
1088 
VisitMethod(size_t class_def_method_index,const ClassDataItemIterator & it)1089   bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it)
1090       REQUIRES_SHARED(Locks::mutator_lock_) {
1091     // Skip methods that are not in the image.
1092     if (!IsImageClass()) {
1093       return true;
1094     }
1095 
1096     OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
1097     CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1098 
1099     OatMethodOffsets offsets(0u);
1100     if (compiled_method != nullptr) {
1101       DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
1102       offsets = oat_class->method_offsets_[method_offsets_index_];
1103       ++method_offsets_index_;
1104     }
1105 
1106     // Unchecked as we hold mutator_lock_ on entry.
1107     ScopedObjectAccessUnchecked soa(Thread::Current());
1108     StackHandleScope<1> hs(soa.Self());
1109     Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker_->FindDexCache(
1110         Thread::Current(), *dex_file_)));
1111     ArtMethod* method;
1112     if (writer_->HasBootImage()) {
1113       const InvokeType invoke_type = it.GetMethodInvokeType(
1114           dex_file_->GetClassDef(class_def_index_));
1115       method = class_linker_->ResolveMethod<ClassLinker::kNoICCECheckForCache>(
1116           *dex_file_,
1117           it.GetMemberIndex(),
1118           dex_cache,
1119           ScopedNullHandle<mirror::ClassLoader>(),
1120           nullptr,
1121           invoke_type);
1122       if (method == nullptr) {
1123         LOG(FATAL_WITHOUT_ABORT) << "Unexpected failure to resolve a method: "
1124             << dex_file_->PrettyMethod(it.GetMemberIndex(), true);
1125         soa.Self()->AssertPendingException();
1126         mirror::Throwable* exc = soa.Self()->GetException();
1127         std::string dump = exc->Dump();
1128         LOG(FATAL) << dump;
1129         UNREACHABLE();
1130       }
1131     } else {
1132       // Should already have been resolved by the compiler, just peek into the dex cache.
1133       // It may not be resolved if the class failed to verify, in this case, don't set the
1134       // entrypoint. This is not fatal since the dex cache will contain a resolution method.
1135       method = dex_cache->GetResolvedMethod(it.GetMemberIndex(),
1136           class_linker_->GetImagePointerSize());
1137     }
1138     if (method != nullptr &&
1139         compiled_method != nullptr &&
1140         compiled_method->GetQuickCode().size() != 0) {
1141       method->SetEntryPointFromQuickCompiledCodePtrSize(
1142           reinterpret_cast<void*>(offsets.code_offset_), pointer_size_);
1143     }
1144 
1145     return true;
1146   }
1147 
1148   // Check whether current class is image class
IsImageClass()1149   bool IsImageClass() {
1150     const DexFile::TypeId& type_id =
1151         dex_file_->GetTypeId(dex_file_->GetClassDef(class_def_index_).class_idx_);
1152     const char* class_descriptor = dex_file_->GetTypeDescriptor(type_id);
1153     return writer_->GetCompilerDriver()->IsImageClass(class_descriptor);
1154   }
1155 
1156   // Check whether specified dex file is in the compiled oat file.
IsInOatFile(const DexFile * dex_file)1157   bool IsInOatFile(const DexFile* dex_file) {
1158     return ContainsElement(*dex_files_, dex_file);
1159   }
1160 
1161   // Assign a pointer to quick code for copied methods
1162   // not handled in the method StartClass
Postprocess()1163   void Postprocess() {
1164     for (std::pair<ArtMethod*, ArtMethod*>& p : methods_to_process_) {
1165       ArtMethod* method = p.first;
1166       ArtMethod* origin = p.second;
1167       const void* code_ptr =
1168           origin->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size_);
1169       if (code_ptr != nullptr) {
1170         method->SetEntryPointFromQuickCompiledCodePtrSize(code_ptr, pointer_size_);
1171       }
1172     }
1173   }
1174 
1175  protected:
1176   const PointerSize pointer_size_;
1177   const std::vector<const DexFile*>* dex_files_;
1178   ClassLinker* const class_linker_;
1179   std::vector<std::pair<ArtMethod*, ArtMethod*>> methods_to_process_;
1180 };
1181 
1182 class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor {
1183  public:
WriteCodeMethodVisitor(OatWriter * writer,OutputStream * out,const size_t file_offset,size_t relative_offset)1184   WriteCodeMethodVisitor(OatWriter* writer, OutputStream* out, const size_t file_offset,
1185                          size_t relative_offset) SHARED_LOCK_FUNCTION(Locks::mutator_lock_)
1186     : OatDexMethodVisitor(writer, relative_offset),
1187       class_loader_(writer->HasImage() ? writer->image_writer_->GetClassLoader() : nullptr),
1188       out_(out),
1189       file_offset_(file_offset),
1190       soa_(Thread::Current()),
1191       no_thread_suspension_("OatWriter patching"),
1192       class_linker_(Runtime::Current()->GetClassLinker()),
1193       dex_cache_(nullptr) {
1194     patched_code_.reserve(16 * KB);
1195     if (writer_->HasBootImage()) {
1196       // If we're creating the image, the address space must be ready so that we can apply patches.
1197       CHECK(writer_->image_writer_->IsImageAddressSpaceReady());
1198     }
1199   }
1200 
UNLOCK_FUNCTION(Locks::mutator_lock_)1201   ~WriteCodeMethodVisitor() UNLOCK_FUNCTION(Locks::mutator_lock_) {
1202   }
1203 
StartClass(const DexFile * dex_file,size_t class_def_index)1204   bool StartClass(const DexFile* dex_file, size_t class_def_index)
1205       REQUIRES_SHARED(Locks::mutator_lock_) {
1206     OatDexMethodVisitor::StartClass(dex_file, class_def_index);
1207     if (dex_cache_ == nullptr || dex_cache_->GetDexFile() != dex_file) {
1208       dex_cache_ = class_linker_->FindDexCache(Thread::Current(), *dex_file);
1209       DCHECK(dex_cache_ != nullptr);
1210     }
1211     return true;
1212   }
1213 
EndClass()1214   bool EndClass() REQUIRES_SHARED(Locks::mutator_lock_) {
1215     bool result = OatDexMethodVisitor::EndClass();
1216     if (oat_class_index_ == writer_->oat_classes_.size()) {
1217       DCHECK(result);  // OatDexMethodVisitor::EndClass() never fails.
1218       offset_ = writer_->relative_patcher_->WriteThunks(out_, offset_);
1219       if (UNLIKELY(offset_ == 0u)) {
1220         PLOG(ERROR) << "Failed to write final relative call thunks";
1221         result = false;
1222       }
1223     }
1224     return result;
1225   }
1226 
VisitMethod(size_t class_def_method_index,const ClassDataItemIterator & it)1227   bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it)
1228       REQUIRES_SHARED(Locks::mutator_lock_) {
1229     OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
1230     const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1231 
1232     // No thread suspension since dex_cache_ that may get invalidated if that occurs.
1233     ScopedAssertNoThreadSuspension tsc(__FUNCTION__);
1234     if (compiled_method != nullptr) {  // ie. not an abstract method
1235       size_t file_offset = file_offset_;
1236       OutputStream* out = out_;
1237 
1238       ArrayRef<const uint8_t> quick_code = compiled_method->GetQuickCode();
1239       uint32_t code_size = quick_code.size() * sizeof(uint8_t);
1240 
1241       // Deduplicate code arrays.
1242       const OatMethodOffsets& method_offsets = oat_class->method_offsets_[method_offsets_index_];
1243       if (method_offsets.code_offset_ > offset_) {
1244         offset_ = writer_->relative_patcher_->WriteThunks(out, offset_);
1245         if (offset_ == 0u) {
1246           ReportWriteFailure("relative call thunk", it);
1247           return false;
1248         }
1249         uint32_t alignment_size = CodeAlignmentSize(offset_, *compiled_method);
1250         if (alignment_size != 0) {
1251           if (!writer_->WriteCodeAlignment(out, alignment_size)) {
1252             ReportWriteFailure("code alignment padding", it);
1253             return false;
1254           }
1255           offset_ += alignment_size;
1256           DCHECK_OFFSET_();
1257         }
1258         DCHECK_ALIGNED_PARAM(offset_ + sizeof(OatQuickMethodHeader),
1259                              GetInstructionSetAlignment(compiled_method->GetInstructionSet()));
1260         DCHECK_EQ(method_offsets.code_offset_,
1261                   offset_ + sizeof(OatQuickMethodHeader) + compiled_method->CodeDelta())
1262             << dex_file_->PrettyMethod(it.GetMemberIndex());
1263         const OatQuickMethodHeader& method_header =
1264             oat_class->method_headers_[method_offsets_index_];
1265         if (!out->WriteFully(&method_header, sizeof(method_header))) {
1266           ReportWriteFailure("method header", it);
1267           return false;
1268         }
1269         writer_->size_method_header_ += sizeof(method_header);
1270         offset_ += sizeof(method_header);
1271         DCHECK_OFFSET_();
1272 
1273         if (!compiled_method->GetPatches().empty()) {
1274           patched_code_.assign(quick_code.begin(), quick_code.end());
1275           quick_code = ArrayRef<const uint8_t>(patched_code_);
1276           for (const LinkerPatch& patch : compiled_method->GetPatches()) {
1277             uint32_t literal_offset = patch.LiteralOffset();
1278             switch (patch.GetType()) {
1279               case LinkerPatch::Type::kCallRelative: {
1280                 // NOTE: Relative calls across oat files are not supported.
1281                 uint32_t target_offset = GetTargetOffset(patch);
1282                 writer_->relative_patcher_->PatchCall(&patched_code_,
1283                                                       literal_offset,
1284                                                       offset_ + literal_offset,
1285                                                       target_offset);
1286                 break;
1287               }
1288               case LinkerPatch::Type::kDexCacheArray: {
1289                 uint32_t target_offset = GetDexCacheOffset(patch);
1290                 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1291                                                                      patch,
1292                                                                      offset_ + literal_offset,
1293                                                                      target_offset);
1294                 break;
1295               }
1296               case LinkerPatch::Type::kStringRelative: {
1297                 uint32_t target_offset = GetTargetObjectOffset(GetTargetString(patch));
1298                 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1299                                                                      patch,
1300                                                                      offset_ + literal_offset,
1301                                                                      target_offset);
1302                 break;
1303               }
1304               case LinkerPatch::Type::kStringBssEntry: {
1305                 StringReference ref(patch.TargetStringDexFile(), patch.TargetStringIndex());
1306                 uint32_t target_offset = writer_->bss_string_entries_.Get(ref);
1307                 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1308                                                                      patch,
1309                                                                      offset_ + literal_offset,
1310                                                                      target_offset);
1311                 break;
1312               }
1313               case LinkerPatch::Type::kTypeRelative: {
1314                 uint32_t target_offset = GetTargetObjectOffset(GetTargetType(patch));
1315                 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1316                                                                      patch,
1317                                                                      offset_ + literal_offset,
1318                                                                      target_offset);
1319                 break;
1320               }
1321               case LinkerPatch::Type::kTypeBssEntry: {
1322                 TypeReference ref(patch.TargetTypeDexFile(), patch.TargetTypeIndex());
1323                 uint32_t target_offset = writer_->bss_type_entries_.Get(ref);
1324                 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1325                                                                      patch,
1326                                                                      offset_ + literal_offset,
1327                                                                      target_offset);
1328                 break;
1329               }
1330               case LinkerPatch::Type::kCall: {
1331                 uint32_t target_offset = GetTargetOffset(patch);
1332                 PatchCodeAddress(&patched_code_, literal_offset, target_offset);
1333                 break;
1334               }
1335               case LinkerPatch::Type::kMethod: {
1336                 ArtMethod* method = GetTargetMethod(patch);
1337                 PatchMethodAddress(&patched_code_, literal_offset, method);
1338                 break;
1339               }
1340               case LinkerPatch::Type::kString: {
1341                 mirror::String* string = GetTargetString(patch);
1342                 PatchObjectAddress(&patched_code_, literal_offset, string);
1343                 break;
1344               }
1345               case LinkerPatch::Type::kType: {
1346                 mirror::Class* type = GetTargetType(patch);
1347                 PatchObjectAddress(&patched_code_, literal_offset, type);
1348                 break;
1349               }
1350               case LinkerPatch::Type::kBakerReadBarrierBranch: {
1351                 writer_->relative_patcher_->PatchBakerReadBarrierBranch(&patched_code_,
1352                                                                         patch,
1353                                                                         offset_ + literal_offset);
1354                 break;
1355               }
1356               default: {
1357                 DCHECK(false) << "Unexpected linker patch type: " << patch.GetType();
1358                 break;
1359               }
1360             }
1361           }
1362         }
1363 
1364         if (!out->WriteFully(quick_code.data(), code_size)) {
1365           ReportWriteFailure("method code", it);
1366           return false;
1367         }
1368         writer_->size_code_ += code_size;
1369         offset_ += code_size;
1370       }
1371       DCHECK_OFFSET_();
1372       ++method_offsets_index_;
1373     }
1374 
1375     return true;
1376   }
1377 
1378  private:
1379   ObjPtr<mirror::ClassLoader> class_loader_;
1380   OutputStream* const out_;
1381   const size_t file_offset_;
1382   const ScopedObjectAccess soa_;
1383   const ScopedAssertNoThreadSuspension no_thread_suspension_;
1384   ClassLinker* const class_linker_;
1385   ObjPtr<mirror::DexCache> dex_cache_;
1386   std::vector<uint8_t> patched_code_;
1387 
ReportWriteFailure(const char * what,const ClassDataItemIterator & it)1388   void ReportWriteFailure(const char* what, const ClassDataItemIterator& it) {
1389     PLOG(ERROR) << "Failed to write " << what << " for "
1390         << dex_file_->PrettyMethod(it.GetMemberIndex()) << " to " << out_->GetLocation();
1391   }
1392 
GetTargetMethod(const LinkerPatch & patch)1393   ArtMethod* GetTargetMethod(const LinkerPatch& patch)
1394       REQUIRES_SHARED(Locks::mutator_lock_) {
1395     MethodReference ref = patch.TargetMethod();
1396     ObjPtr<mirror::DexCache> dex_cache =
1397         (dex_file_ == ref.dex_file) ? dex_cache_ : class_linker_->FindDexCache(
1398             Thread::Current(), *ref.dex_file);
1399     ArtMethod* method = dex_cache->GetResolvedMethod(
1400         ref.dex_method_index, class_linker_->GetImagePointerSize());
1401     CHECK(method != nullptr);
1402     return method;
1403   }
1404 
GetTargetOffset(const LinkerPatch & patch)1405   uint32_t GetTargetOffset(const LinkerPatch& patch) REQUIRES_SHARED(Locks::mutator_lock_) {
1406     uint32_t target_offset = writer_->relative_patcher_->GetOffset(patch.TargetMethod());
1407     // If there's no new compiled code, either we're compiling an app and the target method
1408     // is in the boot image, or we need to point to the correct trampoline.
1409     if (UNLIKELY(target_offset == 0)) {
1410       ArtMethod* target = GetTargetMethod(patch);
1411       DCHECK(target != nullptr);
1412       PointerSize size =
1413           GetInstructionSetPointerSize(writer_->compiler_driver_->GetInstructionSet());
1414       const void* oat_code_offset = target->GetEntryPointFromQuickCompiledCodePtrSize(size);
1415       if (oat_code_offset != 0) {
1416         DCHECK(!writer_->HasBootImage());
1417         DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickResolutionStub(oat_code_offset));
1418         DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickToInterpreterBridge(oat_code_offset));
1419         DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickGenericJniStub(oat_code_offset));
1420         target_offset = PointerToLowMemUInt32(oat_code_offset);
1421       } else {
1422         target_offset = target->IsNative()
1423             ? writer_->oat_header_->GetQuickGenericJniTrampolineOffset()
1424             : writer_->oat_header_->GetQuickToInterpreterBridgeOffset();
1425       }
1426     }
1427     return target_offset;
1428   }
1429 
GetDexCache(const DexFile * target_dex_file)1430   ObjPtr<mirror::DexCache> GetDexCache(const DexFile* target_dex_file)
1431       REQUIRES_SHARED(Locks::mutator_lock_) {
1432     return (target_dex_file == dex_file_)
1433         ? dex_cache_
1434         : class_linker_->FindDexCache(Thread::Current(), *target_dex_file);
1435   }
1436 
GetTargetType(const LinkerPatch & patch)1437   mirror::Class* GetTargetType(const LinkerPatch& patch) REQUIRES_SHARED(Locks::mutator_lock_) {
1438     DCHECK(writer_->HasImage());
1439     ObjPtr<mirror::DexCache> dex_cache = GetDexCache(patch.TargetTypeDexFile());
1440     ObjPtr<mirror::Class> type =
1441         ClassLinker::LookupResolvedType(patch.TargetTypeIndex(), dex_cache, class_loader_);
1442     CHECK(type != nullptr);
1443     return type.Ptr();
1444   }
1445 
GetTargetString(const LinkerPatch & patch)1446   mirror::String* GetTargetString(const LinkerPatch& patch) REQUIRES_SHARED(Locks::mutator_lock_) {
1447     ScopedObjectAccessUnchecked soa(Thread::Current());
1448     ClassLinker* linker = Runtime::Current()->GetClassLinker();
1449     mirror::String* string = linker->LookupString(*patch.TargetStringDexFile(),
1450                                                   patch.TargetStringIndex(),
1451                                                   GetDexCache(patch.TargetStringDexFile()));
1452     DCHECK(string != nullptr);
1453     DCHECK(writer_->HasBootImage() ||
1454            Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(string));
1455     return string;
1456   }
1457 
GetDexCacheOffset(const LinkerPatch & patch)1458   uint32_t GetDexCacheOffset(const LinkerPatch& patch) REQUIRES_SHARED(Locks::mutator_lock_) {
1459     if (writer_->HasBootImage()) {
1460       uintptr_t element = writer_->image_writer_->GetDexCacheArrayElementImageAddress<uintptr_t>(
1461           patch.TargetDexCacheDexFile(), patch.TargetDexCacheElementOffset());
1462       size_t oat_index = writer_->image_writer_->GetOatIndexForDexCache(dex_cache_);
1463       uintptr_t oat_data = writer_->image_writer_->GetOatDataBegin(oat_index);
1464       return element - oat_data;
1465     } else {
1466       size_t start = writer_->dex_cache_arrays_offsets_.Get(patch.TargetDexCacheDexFile());
1467       return start + patch.TargetDexCacheElementOffset();
1468     }
1469   }
1470 
GetTargetObjectOffset(mirror::Object * object)1471   uint32_t GetTargetObjectOffset(mirror::Object* object) REQUIRES_SHARED(Locks::mutator_lock_) {
1472     DCHECK(writer_->HasBootImage());
1473     object = writer_->image_writer_->GetImageAddress(object);
1474     size_t oat_index = writer_->image_writer_->GetOatIndexForDexFile(dex_file_);
1475     uintptr_t oat_data_begin = writer_->image_writer_->GetOatDataBegin(oat_index);
1476     // TODO: Clean up offset types. The target offset must be treated as signed.
1477     return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(object) - oat_data_begin);
1478   }
1479 
PatchObjectAddress(std::vector<uint8_t> * code,uint32_t offset,mirror::Object * object)1480   void PatchObjectAddress(std::vector<uint8_t>* code, uint32_t offset, mirror::Object* object)
1481       REQUIRES_SHARED(Locks::mutator_lock_) {
1482     if (writer_->HasBootImage()) {
1483       object = writer_->image_writer_->GetImageAddress(object);
1484     } else {
1485       // NOTE: We're using linker patches for app->boot references when the image can
1486       // be relocated and therefore we need to emit .oat_patches. We're not using this
1487       // for app->app references, so check that the object is in the image space.
1488       DCHECK(Runtime::Current()->GetHeap()->FindSpaceFromObject(object, false)->IsImageSpace());
1489     }
1490     // Note: We only patch targeting Objects in image which is in the low 4gb.
1491     uint32_t address = PointerToLowMemUInt32(object);
1492     DCHECK_LE(offset + 4, code->size());
1493     uint8_t* data = &(*code)[offset];
1494     data[0] = address & 0xffu;
1495     data[1] = (address >> 8) & 0xffu;
1496     data[2] = (address >> 16) & 0xffu;
1497     data[3] = (address >> 24) & 0xffu;
1498   }
1499 
PatchMethodAddress(std::vector<uint8_t> * code,uint32_t offset,ArtMethod * method)1500   void PatchMethodAddress(std::vector<uint8_t>* code, uint32_t offset, ArtMethod* method)
1501       REQUIRES_SHARED(Locks::mutator_lock_) {
1502     if (writer_->HasBootImage()) {
1503       method = writer_->image_writer_->GetImageMethodAddress(method);
1504     } else if (kIsDebugBuild) {
1505       // NOTE: We're using linker patches for app->boot references when the image can
1506       // be relocated and therefore we need to emit .oat_patches. We're not using this
1507       // for app->app references, so check that the method is an image method.
1508       std::vector<gc::space::ImageSpace*> image_spaces =
1509           Runtime::Current()->GetHeap()->GetBootImageSpaces();
1510       bool contains_method = false;
1511       for (gc::space::ImageSpace* image_space : image_spaces) {
1512         size_t method_offset = reinterpret_cast<const uint8_t*>(method) - image_space->Begin();
1513         contains_method |=
1514             image_space->GetImageHeader().GetMethodsSection().Contains(method_offset);
1515       }
1516       CHECK(contains_method);
1517     }
1518     // Note: We only patch targeting ArtMethods in image which is in the low 4gb.
1519     uint32_t address = PointerToLowMemUInt32(method);
1520     DCHECK_LE(offset + 4, code->size());
1521     uint8_t* data = &(*code)[offset];
1522     data[0] = address & 0xffu;
1523     data[1] = (address >> 8) & 0xffu;
1524     data[2] = (address >> 16) & 0xffu;
1525     data[3] = (address >> 24) & 0xffu;
1526   }
1527 
PatchCodeAddress(std::vector<uint8_t> * code,uint32_t offset,uint32_t target_offset)1528   void PatchCodeAddress(std::vector<uint8_t>* code, uint32_t offset, uint32_t target_offset)
1529       REQUIRES_SHARED(Locks::mutator_lock_) {
1530     uint32_t address = target_offset;
1531     if (writer_->HasBootImage()) {
1532       size_t oat_index = writer_->image_writer_->GetOatIndexForDexCache(dex_cache_);
1533       // TODO: Clean up offset types.
1534       // The target_offset must be treated as signed for cross-oat patching.
1535       const void* target = reinterpret_cast<const void*>(
1536           writer_->image_writer_->GetOatDataBegin(oat_index) +
1537           static_cast<int32_t>(target_offset));
1538       address = PointerToLowMemUInt32(target);
1539     }
1540     DCHECK_LE(offset + 4, code->size());
1541     uint8_t* data = &(*code)[offset];
1542     data[0] = address & 0xffu;
1543     data[1] = (address >> 8) & 0xffu;
1544     data[2] = (address >> 16) & 0xffu;
1545     data[3] = (address >> 24) & 0xffu;
1546   }
1547 };
1548 
1549 class OatWriter::WriteMapMethodVisitor : public OatDexMethodVisitor {
1550  public:
WriteMapMethodVisitor(OatWriter * writer,OutputStream * out,const size_t file_offset,size_t relative_offset)1551   WriteMapMethodVisitor(OatWriter* writer,
1552                         OutputStream* out,
1553                         const size_t file_offset,
1554                         size_t relative_offset)
1555     : OatDexMethodVisitor(writer, relative_offset),
1556       out_(out),
1557       file_offset_(file_offset) {
1558   }
1559 
VisitMethod(size_t class_def_method_index,const ClassDataItemIterator & it)1560   bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) {
1561     OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
1562     const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1563 
1564     if (compiled_method != nullptr) {  // i.e. not an abstract method
1565       size_t file_offset = file_offset_;
1566       OutputStream* out = out_;
1567 
1568       uint32_t map_offset = oat_class->method_headers_[method_offsets_index_].GetVmapTableOffset();
1569       uint32_t code_offset = oat_class->method_offsets_[method_offsets_index_].code_offset_;
1570       ++method_offsets_index_;
1571 
1572       DCHECK((compiled_method->GetVmapTable().size() == 0u && map_offset == 0u) ||
1573              (compiled_method->GetVmapTable().size() != 0u && map_offset != 0u))
1574           << compiled_method->GetVmapTable().size() << " " << map_offset << " "
1575           << dex_file_->PrettyMethod(it.GetMemberIndex());
1576 
1577       // If vdex is enabled, only emit the map for compiled code. The quickening info
1578       // is emitted in the vdex already.
1579       if (map_offset != 0u &&
1580           !(kIsVdexEnabled && compiled_method->GetQuickCode().empty())) {
1581         // Transform map_offset to actual oat data offset.
1582         map_offset = (code_offset - compiled_method->CodeDelta()) - map_offset;
1583         DCHECK_NE(map_offset, 0u);
1584         DCHECK_LE(map_offset, offset_) << dex_file_->PrettyMethod(it.GetMemberIndex());
1585 
1586         ArrayRef<const uint8_t> map = compiled_method->GetVmapTable();
1587         size_t map_size = map.size() * sizeof(map[0]);
1588         if (map_offset == offset_) {
1589           // Write deduplicated map (code info for Optimizing or transformation info for dex2dex).
1590           if (UNLIKELY(!out->WriteFully(map.data(), map_size))) {
1591             ReportWriteFailure(it);
1592             return false;
1593           }
1594           offset_ += map_size;
1595         }
1596       }
1597       DCHECK_OFFSET_();
1598     }
1599 
1600     return true;
1601   }
1602 
1603  private:
1604   OutputStream* const out_;
1605   size_t const file_offset_;
1606 
ReportWriteFailure(const ClassDataItemIterator & it)1607   void ReportWriteFailure(const ClassDataItemIterator& it) {
1608     PLOG(ERROR) << "Failed to write map for "
1609         << dex_file_->PrettyMethod(it.GetMemberIndex()) << " to " << out_->GetLocation();
1610   }
1611 };
1612 
1613 class OatWriter::WriteMethodInfoVisitor : public OatDexMethodVisitor {
1614  public:
WriteMethodInfoVisitor(OatWriter * writer,OutputStream * out,const size_t file_offset,size_t relative_offset)1615   WriteMethodInfoVisitor(OatWriter* writer,
1616                          OutputStream* out,
1617                          const size_t file_offset,
1618                          size_t relative_offset)
1619     : OatDexMethodVisitor(writer, relative_offset),
1620       out_(out),
1621       file_offset_(file_offset) {}
1622 
VisitMethod(size_t class_def_method_index,const ClassDataItemIterator & it)1623   bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) {
1624     OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
1625     const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1626 
1627     if (compiled_method != nullptr) {  // i.e. not an abstract method
1628       size_t file_offset = file_offset_;
1629       OutputStream* out = out_;
1630       uint32_t map_offset = oat_class->method_headers_[method_offsets_index_].GetMethodInfoOffset();
1631       uint32_t code_offset = oat_class->method_offsets_[method_offsets_index_].code_offset_;
1632       ++method_offsets_index_;
1633       DCHECK((compiled_method->GetMethodInfo().size() == 0u && map_offset == 0u) ||
1634              (compiled_method->GetMethodInfo().size() != 0u && map_offset != 0u))
1635           << compiled_method->GetMethodInfo().size() << " " << map_offset << " "
1636           << dex_file_->PrettyMethod(it.GetMemberIndex());
1637       if (map_offset != 0u) {
1638         // Transform map_offset to actual oat data offset.
1639         map_offset = (code_offset - compiled_method->CodeDelta()) - map_offset;
1640         DCHECK_NE(map_offset, 0u);
1641         DCHECK_LE(map_offset, offset_) << dex_file_->PrettyMethod(it.GetMemberIndex());
1642 
1643         ArrayRef<const uint8_t> map = compiled_method->GetMethodInfo();
1644         size_t map_size = map.size() * sizeof(map[0]);
1645         if (map_offset == offset_) {
1646           // Write deduplicated map (code info for Optimizing or transformation info for dex2dex).
1647           if (UNLIKELY(!out->WriteFully(map.data(), map_size))) {
1648             ReportWriteFailure(it);
1649             return false;
1650           }
1651           offset_ += map_size;
1652         }
1653       }
1654       DCHECK_OFFSET_();
1655     }
1656 
1657     return true;
1658   }
1659 
1660  private:
1661   OutputStream* const out_;
1662   size_t const file_offset_;
1663 
ReportWriteFailure(const ClassDataItemIterator & it)1664   void ReportWriteFailure(const ClassDataItemIterator& it) {
1665     PLOG(ERROR) << "Failed to write map for "
1666         << dex_file_->PrettyMethod(it.GetMemberIndex()) << " to " << out_->GetLocation();
1667   }
1668 };
1669 
1670 // Visit all methods from all classes in all dex files with the specified visitor.
VisitDexMethods(DexMethodVisitor * visitor)1671 bool OatWriter::VisitDexMethods(DexMethodVisitor* visitor) {
1672   for (const DexFile* dex_file : *dex_files_) {
1673     const size_t class_def_count = dex_file->NumClassDefs();
1674     for (size_t class_def_index = 0; class_def_index != class_def_count; ++class_def_index) {
1675       if (UNLIKELY(!visitor->StartClass(dex_file, class_def_index))) {
1676         return false;
1677       }
1678       if (compiler_driver_->GetCompilerOptions().IsAnyCompilationEnabled()) {
1679         const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
1680         const uint8_t* class_data = dex_file->GetClassData(class_def);
1681         if (class_data != nullptr) {  // ie not an empty class, such as a marker interface
1682           ClassDataItemIterator it(*dex_file, class_data);
1683           while (it.HasNextStaticField()) {
1684             it.Next();
1685           }
1686           while (it.HasNextInstanceField()) {
1687             it.Next();
1688           }
1689           size_t class_def_method_index = 0u;
1690           while (it.HasNextDirectMethod()) {
1691             if (!visitor->VisitMethod(class_def_method_index, it)) {
1692               return false;
1693             }
1694             ++class_def_method_index;
1695             it.Next();
1696           }
1697           while (it.HasNextVirtualMethod()) {
1698             if (UNLIKELY(!visitor->VisitMethod(class_def_method_index, it))) {
1699               return false;
1700             }
1701             ++class_def_method_index;
1702             it.Next();
1703           }
1704         }
1705       }
1706       if (UNLIKELY(!visitor->EndClass())) {
1707         return false;
1708       }
1709     }
1710   }
1711   return true;
1712 }
1713 
InitOatHeader(InstructionSet instruction_set,const InstructionSetFeatures * instruction_set_features,uint32_t num_dex_files,SafeMap<std::string,std::string> * key_value_store)1714 size_t OatWriter::InitOatHeader(InstructionSet instruction_set,
1715                                 const InstructionSetFeatures* instruction_set_features,
1716                                 uint32_t num_dex_files,
1717                                 SafeMap<std::string, std::string>* key_value_store) {
1718   TimingLogger::ScopedTiming split("InitOatHeader", timings_);
1719   oat_header_.reset(OatHeader::Create(instruction_set,
1720                                       instruction_set_features,
1721                                       num_dex_files,
1722                                       key_value_store));
1723   size_oat_header_ += sizeof(OatHeader);
1724   size_oat_header_key_value_store_ += oat_header_->GetHeaderSize() - sizeof(OatHeader);
1725   return oat_header_->GetHeaderSize();
1726 }
1727 
InitOatDexFiles(size_t offset)1728 size_t OatWriter::InitOatDexFiles(size_t offset) {
1729   TimingLogger::ScopedTiming split("InitOatDexFiles", timings_);
1730   // Initialize offsets of dex files.
1731   for (OatDexFile& oat_dex_file : oat_dex_files_) {
1732     oat_dex_file.offset_ = offset;
1733     offset += oat_dex_file.SizeOf();
1734   }
1735   return offset;
1736 }
1737 
InitOatClasses(size_t offset)1738 size_t OatWriter::InitOatClasses(size_t offset) {
1739   // calculate the offsets within OatDexFiles to OatClasses
1740   InitOatClassesMethodVisitor visitor(this, offset);
1741   bool success = VisitDexMethods(&visitor);
1742   CHECK(success);
1743   offset = visitor.GetOffset();
1744 
1745   // Update oat_dex_files_.
1746   auto oat_class_it = oat_classes_.begin();
1747   for (OatDexFile& oat_dex_file : oat_dex_files_) {
1748     for (uint32_t& class_offset : oat_dex_file.class_offsets_) {
1749       DCHECK(oat_class_it != oat_classes_.end());
1750       class_offset = oat_class_it->offset_;
1751       ++oat_class_it;
1752     }
1753   }
1754   CHECK(oat_class_it == oat_classes_.end());
1755 
1756   return offset;
1757 }
1758 
InitOatMaps(size_t offset)1759 size_t OatWriter::InitOatMaps(size_t offset) {
1760   if (!compiler_driver_->GetCompilerOptions().IsAnyCompilationEnabled()) {
1761     return offset;
1762   }
1763   {
1764     InitMapMethodVisitor visitor(this, offset);
1765     bool success = VisitDexMethods(&visitor);
1766     DCHECK(success);
1767     offset = visitor.GetOffset();
1768   }
1769   {
1770     InitMethodInfoVisitor visitor(this, offset);
1771     bool success = VisitDexMethods(&visitor);
1772     DCHECK(success);
1773     offset = visitor.GetOffset();
1774   }
1775   return offset;
1776 }
1777 
InitOatCode(size_t offset)1778 size_t OatWriter::InitOatCode(size_t offset) {
1779   // calculate the offsets within OatHeader to executable code
1780   size_t old_offset = offset;
1781   size_t adjusted_offset = offset;
1782   // required to be on a new page boundary
1783   offset = RoundUp(offset, kPageSize);
1784   oat_header_->SetExecutableOffset(offset);
1785   size_executable_offset_alignment_ = offset - old_offset;
1786   if (compiler_driver_->GetCompilerOptions().IsBootImage()) {
1787     InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
1788 
1789     #define DO_TRAMPOLINE(field, fn_name) \
1790       offset = CompiledCode::AlignCode(offset, instruction_set); \
1791       adjusted_offset = offset + CompiledCode::CodeDelta(instruction_set); \
1792       oat_header_->Set ## fn_name ## Offset(adjusted_offset); \
1793       (field) = compiler_driver_->Create ## fn_name(); \
1794       offset += (field)->size();
1795 
1796     DO_TRAMPOLINE(jni_dlsym_lookup_, JniDlsymLookup);
1797     DO_TRAMPOLINE(quick_generic_jni_trampoline_, QuickGenericJniTrampoline);
1798     DO_TRAMPOLINE(quick_imt_conflict_trampoline_, QuickImtConflictTrampoline);
1799     DO_TRAMPOLINE(quick_resolution_trampoline_, QuickResolutionTrampoline);
1800     DO_TRAMPOLINE(quick_to_interpreter_bridge_, QuickToInterpreterBridge);
1801 
1802     #undef DO_TRAMPOLINE
1803   } else {
1804     oat_header_->SetInterpreterToInterpreterBridgeOffset(0);
1805     oat_header_->SetInterpreterToCompiledCodeBridgeOffset(0);
1806     oat_header_->SetJniDlsymLookupOffset(0);
1807     oat_header_->SetQuickGenericJniTrampolineOffset(0);
1808     oat_header_->SetQuickImtConflictTrampolineOffset(0);
1809     oat_header_->SetQuickResolutionTrampolineOffset(0);
1810     oat_header_->SetQuickToInterpreterBridgeOffset(0);
1811   }
1812   return offset;
1813 }
1814 
InitOatCodeDexFiles(size_t offset)1815 size_t OatWriter::InitOatCodeDexFiles(size_t offset) {
1816   if (!compiler_driver_->GetCompilerOptions().IsAnyCompilationEnabled()) {
1817     return offset;
1818   }
1819   InitCodeMethodVisitor code_visitor(this, offset, vdex_quickening_info_offset_);
1820   bool success = VisitDexMethods(&code_visitor);
1821   DCHECK(success);
1822   offset = code_visitor.GetOffset();
1823 
1824   if (HasImage()) {
1825     InitImageMethodVisitor image_visitor(this, offset, dex_files_);
1826     success = VisitDexMethods(&image_visitor);
1827     image_visitor.Postprocess();
1828     DCHECK(success);
1829     offset = image_visitor.GetOffset();
1830   }
1831 
1832   return offset;
1833 }
1834 
InitBssLayout(InstructionSet instruction_set)1835 void OatWriter::InitBssLayout(InstructionSet instruction_set) {
1836   if (HasBootImage()) {
1837     DCHECK(bss_string_entries_.empty());
1838     if (bss_type_entries_.empty()) {
1839       // Nothing to put to the .bss section.
1840       return;
1841     }
1842   }
1843 
1844   // Allocate space for app dex cache arrays in the .bss section.
1845   bss_start_ = RoundUp(oat_size_, kPageSize);
1846   bss_size_ = 0u;
1847   if (!HasBootImage()) {
1848     PointerSize pointer_size = GetInstructionSetPointerSize(instruction_set);
1849     for (const DexFile* dex_file : *dex_files_) {
1850       dex_cache_arrays_offsets_.Put(dex_file, bss_start_ + bss_size_);
1851       DexCacheArraysLayout layout(pointer_size, dex_file);
1852       bss_size_ += layout.Size();
1853     }
1854   }
1855 
1856   bss_roots_offset_ = bss_size_;
1857 
1858   // Prepare offsets for .bss Class entries.
1859   for (auto& entry : bss_type_entries_) {
1860     DCHECK_EQ(entry.second, 0u);
1861     entry.second = bss_start_ + bss_size_;
1862     bss_size_ += sizeof(GcRoot<mirror::Class>);
1863   }
1864   // Prepare offsets for .bss String entries.
1865   for (auto& entry : bss_string_entries_) {
1866     DCHECK_EQ(entry.second, 0u);
1867     entry.second = bss_start_ + bss_size_;
1868     bss_size_ += sizeof(GcRoot<mirror::String>);
1869   }
1870 }
1871 
WriteRodata(OutputStream * out)1872 bool OatWriter::WriteRodata(OutputStream* out) {
1873   CHECK(write_state_ == WriteState::kWriteRoData);
1874 
1875   // Wrap out to update checksum with each write.
1876   ChecksumUpdatingOutputStream checksum_updating_out(out, oat_header_.get());
1877   out = &checksum_updating_out;
1878 
1879   if (!WriteClassOffsets(out)) {
1880     LOG(ERROR) << "Failed to write class offsets to " << out->GetLocation();
1881     return false;
1882   }
1883 
1884   if (!WriteClasses(out)) {
1885     LOG(ERROR) << "Failed to write classes to " << out->GetLocation();
1886     return false;
1887   }
1888 
1889   off_t tables_end_offset = out->Seek(0, kSeekCurrent);
1890   if (tables_end_offset == static_cast<off_t>(-1)) {
1891     LOG(ERROR) << "Failed to get oat code position in " << out->GetLocation();
1892     return false;
1893   }
1894   size_t file_offset = oat_data_offset_;
1895   size_t relative_offset = static_cast<size_t>(tables_end_offset) - file_offset;
1896   relative_offset = WriteMaps(out, file_offset, relative_offset);
1897   if (relative_offset == 0) {
1898     LOG(ERROR) << "Failed to write oat code to " << out->GetLocation();
1899     return false;
1900   }
1901 
1902   // Write padding.
1903   off_t new_offset = out->Seek(size_executable_offset_alignment_, kSeekCurrent);
1904   relative_offset += size_executable_offset_alignment_;
1905   DCHECK_EQ(relative_offset, oat_header_->GetExecutableOffset());
1906   size_t expected_file_offset = file_offset + relative_offset;
1907   if (static_cast<uint32_t>(new_offset) != expected_file_offset) {
1908     PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
1909                 << " Expected: " << expected_file_offset << " File: " << out->GetLocation();
1910     return 0;
1911   }
1912   DCHECK_OFFSET();
1913 
1914   write_state_ = WriteState::kWriteText;
1915   return true;
1916 }
1917 
1918 class OatWriter::WriteQuickeningInfoMethodVisitor : public DexMethodVisitor {
1919  public:
WriteQuickeningInfoMethodVisitor(OatWriter * writer,OutputStream * out,uint32_t offset)1920   WriteQuickeningInfoMethodVisitor(OatWriter* writer, OutputStream* out, uint32_t offset)
1921     : DexMethodVisitor(writer, offset),
1922       out_(out),
1923       written_bytes_(0u) {}
1924 
VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED,const ClassDataItemIterator & it)1925   bool VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED,
1926                    const ClassDataItemIterator& it) {
1927     if (it.GetMethodCodeItem() == nullptr) {
1928       // No CodeItem. Native or abstract method.
1929       return true;
1930     }
1931 
1932     uint32_t method_idx = it.GetMemberIndex();
1933     CompiledMethod* compiled_method =
1934         writer_->compiler_driver_->GetCompiledMethod(MethodReference(dex_file_, method_idx));
1935 
1936     uint32_t length = 0;
1937     const uint8_t* data = nullptr;
1938     // VMap only contains quickening info if this method is not compiled.
1939     if (compiled_method != nullptr && compiled_method->GetQuickCode().empty()) {
1940       ArrayRef<const uint8_t> map = compiled_method->GetVmapTable();
1941       data = map.data();
1942       length = map.size() * sizeof(map.front());
1943     }
1944 
1945     if (!out_->WriteFully(&length, sizeof(length)) ||
1946         !out_->WriteFully(data, length)) {
1947       PLOG(ERROR) << "Failed to write quickening info for "
1948           << dex_file_->PrettyMethod(it.GetMemberIndex()) << " to " << out_->GetLocation();
1949       return false;
1950     }
1951     offset_ += sizeof(length) + length;
1952     written_bytes_ += sizeof(length) + length;
1953     return true;
1954   }
1955 
GetNumberOfWrittenBytes() const1956   size_t GetNumberOfWrittenBytes() const {
1957     return written_bytes_;
1958   }
1959 
1960  private:
1961   OutputStream* const out_;
1962   size_t written_bytes_;
1963 };
1964 
WriteQuickeningInfo(OutputStream * vdex_out)1965 bool OatWriter::WriteQuickeningInfo(OutputStream* vdex_out) {
1966   if (!kIsVdexEnabled) {
1967     return true;
1968   }
1969 
1970   size_t initial_offset = vdex_size_;
1971   size_t start_offset = RoundUp(initial_offset, 4u);
1972 
1973   vdex_size_ = start_offset;
1974   vdex_quickening_info_offset_ = vdex_size_;
1975   size_quickening_info_alignment_ = start_offset - initial_offset;
1976 
1977   off_t actual_offset = vdex_out->Seek(start_offset, kSeekSet);
1978   if (actual_offset != static_cast<off_t>(start_offset)) {
1979     PLOG(ERROR) << "Failed to seek to quickening info section. Actual: " << actual_offset
1980                 << " Expected: " << start_offset
1981                 << " Output: " << vdex_out->GetLocation();
1982     return false;
1983   }
1984 
1985   if (compiler_driver_->GetCompilerOptions().IsAnyCompilationEnabled()) {
1986     WriteQuickeningInfoMethodVisitor visitor(this, vdex_out, start_offset);
1987     if (!VisitDexMethods(&visitor)) {
1988       PLOG(ERROR) << "Failed to write the vdex quickening info. File: " << vdex_out->GetLocation();
1989       return false;
1990     }
1991 
1992     if (!vdex_out->Flush()) {
1993       PLOG(ERROR) << "Failed to flush stream after writing quickening info."
1994                   << " File: " << vdex_out->GetLocation();
1995       return false;
1996     }
1997     size_quickening_info_ = visitor.GetNumberOfWrittenBytes();
1998   } else {
1999     // We know we did not quicken.
2000     size_quickening_info_ = 0;
2001   }
2002 
2003   vdex_size_ += size_quickening_info_;
2004   return true;
2005 }
2006 
WriteVerifierDeps(OutputStream * vdex_out,verifier::VerifierDeps * verifier_deps)2007 bool OatWriter::WriteVerifierDeps(OutputStream* vdex_out, verifier::VerifierDeps* verifier_deps) {
2008   if (!kIsVdexEnabled) {
2009     return true;
2010   }
2011 
2012   if (verifier_deps == nullptr) {
2013     // Nothing to write. Record the offset, but no need
2014     // for alignment.
2015     vdex_verifier_deps_offset_ = vdex_size_;
2016     return true;
2017   }
2018 
2019   size_t initial_offset = vdex_size_;
2020   size_t start_offset = RoundUp(initial_offset, 4u);
2021 
2022   vdex_size_ = start_offset;
2023   vdex_verifier_deps_offset_ = vdex_size_;
2024   size_verifier_deps_alignment_ = start_offset - initial_offset;
2025 
2026   off_t actual_offset = vdex_out->Seek(start_offset, kSeekSet);
2027   if (actual_offset != static_cast<off_t>(start_offset)) {
2028     PLOG(ERROR) << "Failed to seek to verifier deps section. Actual: " << actual_offset
2029                 << " Expected: " << start_offset
2030                 << " Output: " << vdex_out->GetLocation();
2031     return false;
2032   }
2033 
2034   std::vector<uint8_t> buffer;
2035   verifier_deps->Encode(*dex_files_, &buffer);
2036 
2037   if (!vdex_out->WriteFully(buffer.data(), buffer.size())) {
2038     PLOG(ERROR) << "Failed to write verifier deps."
2039                 << " File: " << vdex_out->GetLocation();
2040     return false;
2041   }
2042   if (!vdex_out->Flush()) {
2043     PLOG(ERROR) << "Failed to flush stream after writing verifier deps."
2044                 << " File: " << vdex_out->GetLocation();
2045     return false;
2046   }
2047 
2048   size_verifier_deps_ = buffer.size();
2049   vdex_size_ += size_verifier_deps_;
2050   return true;
2051 }
2052 
WriteCode(OutputStream * out)2053 bool OatWriter::WriteCode(OutputStream* out) {
2054   CHECK(write_state_ == WriteState::kWriteText);
2055 
2056   // Wrap out to update checksum with each write.
2057   ChecksumUpdatingOutputStream checksum_updating_out(out, oat_header_.get());
2058   out = &checksum_updating_out;
2059 
2060   SetMultiOatRelativePatcherAdjustment();
2061 
2062   const size_t file_offset = oat_data_offset_;
2063   size_t relative_offset = oat_header_->GetExecutableOffset();
2064   DCHECK_OFFSET();
2065 
2066   relative_offset = WriteCode(out, file_offset, relative_offset);
2067   if (relative_offset == 0) {
2068     LOG(ERROR) << "Failed to write oat code to " << out->GetLocation();
2069     return false;
2070   }
2071 
2072   relative_offset = WriteCodeDexFiles(out, file_offset, relative_offset);
2073   if (relative_offset == 0) {
2074     LOG(ERROR) << "Failed to write oat code for dex files to " << out->GetLocation();
2075     return false;
2076   }
2077 
2078   const off_t oat_end_file_offset = out->Seek(0, kSeekCurrent);
2079   if (oat_end_file_offset == static_cast<off_t>(-1)) {
2080     LOG(ERROR) << "Failed to get oat end file offset in " << out->GetLocation();
2081     return false;
2082   }
2083 
2084   if (kIsDebugBuild) {
2085     uint32_t size_total = 0;
2086     #define DO_STAT(x) \
2087       VLOG(compiler) << #x "=" << PrettySize(x) << " (" << (x) << "B)"; \
2088       size_total += (x);
2089 
2090     DO_STAT(size_vdex_header_);
2091     DO_STAT(size_vdex_checksums_);
2092     DO_STAT(size_dex_file_alignment_);
2093     DO_STAT(size_executable_offset_alignment_);
2094     DO_STAT(size_oat_header_);
2095     DO_STAT(size_oat_header_key_value_store_);
2096     DO_STAT(size_dex_file_);
2097     DO_STAT(size_verifier_deps_);
2098     DO_STAT(size_verifier_deps_alignment_);
2099     DO_STAT(size_quickening_info_);
2100     DO_STAT(size_quickening_info_alignment_);
2101     DO_STAT(size_interpreter_to_interpreter_bridge_);
2102     DO_STAT(size_interpreter_to_compiled_code_bridge_);
2103     DO_STAT(size_jni_dlsym_lookup_);
2104     DO_STAT(size_quick_generic_jni_trampoline_);
2105     DO_STAT(size_quick_imt_conflict_trampoline_);
2106     DO_STAT(size_quick_resolution_trampoline_);
2107     DO_STAT(size_quick_to_interpreter_bridge_);
2108     DO_STAT(size_trampoline_alignment_);
2109     DO_STAT(size_method_header_);
2110     DO_STAT(size_code_);
2111     DO_STAT(size_code_alignment_);
2112     DO_STAT(size_relative_call_thunks_);
2113     DO_STAT(size_misc_thunks_);
2114     DO_STAT(size_vmap_table_);
2115     DO_STAT(size_method_info_);
2116     DO_STAT(size_oat_dex_file_location_size_);
2117     DO_STAT(size_oat_dex_file_location_data_);
2118     DO_STAT(size_oat_dex_file_location_checksum_);
2119     DO_STAT(size_oat_dex_file_offset_);
2120     DO_STAT(size_oat_dex_file_class_offsets_offset_);
2121     DO_STAT(size_oat_dex_file_lookup_table_offset_);
2122     DO_STAT(size_oat_lookup_table_alignment_);
2123     DO_STAT(size_oat_lookup_table_);
2124     DO_STAT(size_oat_class_offsets_alignment_);
2125     DO_STAT(size_oat_class_offsets_);
2126     DO_STAT(size_oat_class_type_);
2127     DO_STAT(size_oat_class_status_);
2128     DO_STAT(size_oat_class_method_bitmaps_);
2129     DO_STAT(size_oat_class_method_offsets_);
2130     #undef DO_STAT
2131 
2132     VLOG(compiler) << "size_total=" << PrettySize(size_total) << " (" << size_total << "B)";
2133 
2134     CHECK_EQ(vdex_size_ + oat_size_, size_total);
2135     CHECK_EQ(file_offset + size_total - vdex_size_, static_cast<size_t>(oat_end_file_offset));
2136   }
2137 
2138   CHECK_EQ(file_offset + oat_size_, static_cast<size_t>(oat_end_file_offset));
2139   CHECK_EQ(oat_size_, relative_offset);
2140 
2141   write_state_ = WriteState::kWriteHeader;
2142   return true;
2143 }
2144 
WriteHeader(OutputStream * out,uint32_t image_file_location_oat_checksum,uintptr_t image_file_location_oat_begin,int32_t image_patch_delta)2145 bool OatWriter::WriteHeader(OutputStream* out,
2146                             uint32_t image_file_location_oat_checksum,
2147                             uintptr_t image_file_location_oat_begin,
2148                             int32_t image_patch_delta) {
2149   CHECK(write_state_ == WriteState::kWriteHeader);
2150 
2151   oat_header_->SetImageFileLocationOatChecksum(image_file_location_oat_checksum);
2152   oat_header_->SetImageFileLocationOatDataBegin(image_file_location_oat_begin);
2153   if (compiler_driver_->GetCompilerOptions().IsBootImage()) {
2154     CHECK_EQ(image_patch_delta, 0);
2155     CHECK_EQ(oat_header_->GetImagePatchDelta(), 0);
2156   } else {
2157     CHECK_ALIGNED(image_patch_delta, kPageSize);
2158     oat_header_->SetImagePatchDelta(image_patch_delta);
2159   }
2160   oat_header_->UpdateChecksumWithHeaderData();
2161 
2162   const size_t file_offset = oat_data_offset_;
2163 
2164   off_t current_offset = out->Seek(0, kSeekCurrent);
2165   if (current_offset == static_cast<off_t>(-1)) {
2166     PLOG(ERROR) << "Failed to get current offset from " << out->GetLocation();
2167     return false;
2168   }
2169   if (out->Seek(file_offset, kSeekSet) == static_cast<off_t>(-1)) {
2170     PLOG(ERROR) << "Failed to seek to oat header position in " << out->GetLocation();
2171     return false;
2172   }
2173   DCHECK_EQ(file_offset, static_cast<size_t>(out->Seek(0, kSeekCurrent)));
2174 
2175   // Flush all other data before writing the header.
2176   if (!out->Flush()) {
2177     PLOG(ERROR) << "Failed to flush before writing oat header to " << out->GetLocation();
2178     return false;
2179   }
2180   // Write the header.
2181   size_t header_size = oat_header_->GetHeaderSize();
2182   if (!out->WriteFully(oat_header_.get(), header_size)) {
2183     PLOG(ERROR) << "Failed to write oat header to " << out->GetLocation();
2184     return false;
2185   }
2186   // Flush the header data.
2187   if (!out->Flush()) {
2188     PLOG(ERROR) << "Failed to flush after writing oat header to " << out->GetLocation();
2189     return false;
2190   }
2191 
2192   if (out->Seek(current_offset, kSeekSet) == static_cast<off_t>(-1)) {
2193     PLOG(ERROR) << "Failed to seek back after writing oat header to " << out->GetLocation();
2194     return false;
2195   }
2196   DCHECK_EQ(current_offset, out->Seek(0, kSeekCurrent));
2197 
2198   write_state_ = WriteState::kDone;
2199   return true;
2200 }
2201 
WriteClassOffsets(OutputStream * out)2202 bool OatWriter::WriteClassOffsets(OutputStream* out) {
2203   for (OatDexFile& oat_dex_file : oat_dex_files_) {
2204     if (oat_dex_file.class_offsets_offset_ != 0u) {
2205       uint32_t expected_offset = oat_data_offset_ + oat_dex_file.class_offsets_offset_;
2206       off_t actual_offset = out->Seek(expected_offset, kSeekSet);
2207       if (static_cast<uint32_t>(actual_offset) != expected_offset) {
2208         PLOG(ERROR) << "Failed to seek to oat class offsets section. Actual: " << actual_offset
2209                     << " Expected: " << expected_offset << " File: " << oat_dex_file.GetLocation();
2210         return false;
2211       }
2212       if (!oat_dex_file.WriteClassOffsets(this, out)) {
2213         return false;
2214       }
2215     }
2216   }
2217   return true;
2218 }
2219 
WriteClasses(OutputStream * out)2220 bool OatWriter::WriteClasses(OutputStream* out) {
2221   for (OatClass& oat_class : oat_classes_) {
2222     if (!oat_class.Write(this, out, oat_data_offset_)) {
2223       PLOG(ERROR) << "Failed to write oat methods information to " << out->GetLocation();
2224       return false;
2225     }
2226   }
2227   return true;
2228 }
2229 
WriteMaps(OutputStream * out,const size_t file_offset,size_t relative_offset)2230 size_t OatWriter::WriteMaps(OutputStream* out, const size_t file_offset, size_t relative_offset) {
2231   {
2232     size_t vmap_tables_offset = relative_offset;
2233     WriteMapMethodVisitor visitor(this, out, file_offset, relative_offset);
2234     if (UNLIKELY(!VisitDexMethods(&visitor))) {
2235       return 0;
2236     }
2237     relative_offset = visitor.GetOffset();
2238     size_vmap_table_ = relative_offset - vmap_tables_offset;
2239   }
2240   {
2241     size_t method_infos_offset = relative_offset;
2242     WriteMethodInfoVisitor visitor(this, out, file_offset, relative_offset);
2243     if (UNLIKELY(!VisitDexMethods(&visitor))) {
2244       return 0;
2245     }
2246     relative_offset = visitor.GetOffset();
2247     size_method_info_ = relative_offset - method_infos_offset;
2248   }
2249 
2250   return relative_offset;
2251 }
2252 
WriteCode(OutputStream * out,const size_t file_offset,size_t relative_offset)2253 size_t OatWriter::WriteCode(OutputStream* out, const size_t file_offset, size_t relative_offset) {
2254   if (compiler_driver_->GetCompilerOptions().IsBootImage()) {
2255     InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
2256 
2257     #define DO_TRAMPOLINE(field) \
2258       do { \
2259         uint32_t aligned_offset = CompiledCode::AlignCode(relative_offset, instruction_set); \
2260         uint32_t alignment_padding = aligned_offset - relative_offset; \
2261         out->Seek(alignment_padding, kSeekCurrent); \
2262         size_trampoline_alignment_ += alignment_padding; \
2263         if (!out->WriteFully((field)->data(), (field)->size())) { \
2264           PLOG(ERROR) << "Failed to write " # field " to " << out->GetLocation(); \
2265           return false; \
2266         } \
2267         size_ ## field += (field)->size(); \
2268         relative_offset += alignment_padding + (field)->size(); \
2269         DCHECK_OFFSET(); \
2270       } while (false)
2271 
2272     DO_TRAMPOLINE(jni_dlsym_lookup_);
2273     DO_TRAMPOLINE(quick_generic_jni_trampoline_);
2274     DO_TRAMPOLINE(quick_imt_conflict_trampoline_);
2275     DO_TRAMPOLINE(quick_resolution_trampoline_);
2276     DO_TRAMPOLINE(quick_to_interpreter_bridge_);
2277     #undef DO_TRAMPOLINE
2278   }
2279   return relative_offset;
2280 }
2281 
WriteCodeDexFiles(OutputStream * out,const size_t file_offset,size_t relative_offset)2282 size_t OatWriter::WriteCodeDexFiles(OutputStream* out,
2283                                     const size_t file_offset,
2284                                     size_t relative_offset) {
2285   #define VISIT(VisitorType)                                              \
2286     do {                                                                  \
2287       VisitorType visitor(this, out, file_offset, relative_offset);       \
2288       if (UNLIKELY(!VisitDexMethods(&visitor))) {                         \
2289         return 0;                                                         \
2290       }                                                                   \
2291       relative_offset = visitor.GetOffset();                              \
2292     } while (false)
2293 
2294   VISIT(WriteCodeMethodVisitor);
2295 
2296   #undef VISIT
2297 
2298   size_code_alignment_ += relative_patcher_->CodeAlignmentSize();
2299   size_relative_call_thunks_ += relative_patcher_->RelativeCallThunksSize();
2300   size_misc_thunks_ += relative_patcher_->MiscThunksSize();
2301 
2302   return relative_offset;
2303 }
2304 
RecordOatDataOffset(OutputStream * out)2305 bool OatWriter::RecordOatDataOffset(OutputStream* out) {
2306   // Get the elf file offset of the oat file.
2307   const off_t raw_file_offset = out->Seek(0, kSeekCurrent);
2308   if (raw_file_offset == static_cast<off_t>(-1)) {
2309     LOG(ERROR) << "Failed to get file offset in " << out->GetLocation();
2310     return false;
2311   }
2312   oat_data_offset_ = static_cast<size_t>(raw_file_offset);
2313   return true;
2314 }
2315 
ReadDexFileHeader(File * file,OatDexFile * oat_dex_file)2316 bool OatWriter::ReadDexFileHeader(File* file, OatDexFile* oat_dex_file) {
2317   // Read the dex file header and perform minimal verification.
2318   uint8_t raw_header[sizeof(DexFile::Header)];
2319   if (!file->ReadFully(&raw_header, sizeof(DexFile::Header))) {
2320     PLOG(ERROR) << "Failed to read dex file header. Actual: "
2321                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2322     return false;
2323   }
2324   if (!ValidateDexFileHeader(raw_header, oat_dex_file->GetLocation())) {
2325     return false;
2326   }
2327 
2328   const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_header);
2329   oat_dex_file->dex_file_size_ = header->file_size_;
2330   oat_dex_file->dex_file_location_checksum_ = header->checksum_;
2331   oat_dex_file->class_offsets_.resize(header->class_defs_size_);
2332   return true;
2333 }
2334 
ValidateDexFileHeader(const uint8_t * raw_header,const char * location)2335 bool OatWriter::ValidateDexFileHeader(const uint8_t* raw_header, const char* location) {
2336   if (!DexFile::IsMagicValid(raw_header)) {
2337     LOG(ERROR) << "Invalid magic number in dex file header. " << " File: " << location;
2338     return false;
2339   }
2340   if (!DexFile::IsVersionValid(raw_header)) {
2341     LOG(ERROR) << "Invalid version number in dex file header. " << " File: " << location;
2342     return false;
2343   }
2344   const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_header);
2345   if (header->file_size_ < sizeof(DexFile::Header)) {
2346     LOG(ERROR) << "Dex file header specifies file size insufficient to contain the header."
2347                << " File: " << location;
2348     return false;
2349   }
2350   return true;
2351 }
2352 
WriteDexFiles(OutputStream * out,File * file,bool update_input_vdex)2353 bool OatWriter::WriteDexFiles(OutputStream* out, File* file, bool update_input_vdex) {
2354   TimingLogger::ScopedTiming split("Write Dex files", timings_);
2355 
2356   vdex_dex_files_offset_ = vdex_size_;
2357 
2358   // Write dex files.
2359   for (OatDexFile& oat_dex_file : oat_dex_files_) {
2360     if (!WriteDexFile(out, file, &oat_dex_file, update_input_vdex)) {
2361       return false;
2362     }
2363   }
2364 
2365   CloseSources();
2366   return true;
2367 }
2368 
CloseSources()2369 void OatWriter::CloseSources() {
2370   for (OatDexFile& oat_dex_file : oat_dex_files_) {
2371     oat_dex_file.source_.Clear();  // Get rid of the reference, it's about to be invalidated.
2372   }
2373   zipped_dex_files_.clear();
2374   zip_archives_.clear();
2375   raw_dex_files_.clear();
2376 }
2377 
WriteDexFile(OutputStream * out,File * file,OatDexFile * oat_dex_file,bool update_input_vdex)2378 bool OatWriter::WriteDexFile(OutputStream* out,
2379                              File* file,
2380                              OatDexFile* oat_dex_file,
2381                              bool update_input_vdex) {
2382   if (!SeekToDexFile(out, file, oat_dex_file)) {
2383     return false;
2384   }
2385   if (profile_compilation_info_ != nullptr) {
2386     DCHECK(!update_input_vdex);
2387     if (!LayoutAndWriteDexFile(out, oat_dex_file)) {
2388       return false;
2389     }
2390   } else if (oat_dex_file->source_.IsZipEntry()) {
2391     DCHECK(!update_input_vdex);
2392     if (!WriteDexFile(out, file, oat_dex_file, oat_dex_file->source_.GetZipEntry())) {
2393       return false;
2394     }
2395   } else if (oat_dex_file->source_.IsRawFile()) {
2396     DCHECK(!update_input_vdex);
2397     if (!WriteDexFile(out, file, oat_dex_file, oat_dex_file->source_.GetRawFile())) {
2398       return false;
2399     }
2400   } else {
2401     DCHECK(oat_dex_file->source_.IsRawData());
2402     if (!WriteDexFile(out, oat_dex_file, oat_dex_file->source_.GetRawData(), update_input_vdex)) {
2403       return false;
2404     }
2405   }
2406 
2407   // Update current size and account for the written data.
2408   if (kIsVdexEnabled) {
2409     DCHECK_EQ(vdex_size_, oat_dex_file->dex_file_offset_);
2410     vdex_size_ += oat_dex_file->dex_file_size_;
2411   } else {
2412     DCHECK(!update_input_vdex);
2413     DCHECK_EQ(oat_size_, oat_dex_file->dex_file_offset_);
2414     oat_size_ += oat_dex_file->dex_file_size_;
2415   }
2416   size_dex_file_ += oat_dex_file->dex_file_size_;
2417   return true;
2418 }
2419 
SeekToDexFile(OutputStream * out,File * file,OatDexFile * oat_dex_file)2420 bool OatWriter::SeekToDexFile(OutputStream* out, File* file, OatDexFile* oat_dex_file) {
2421   // Dex files are required to be 4 byte aligned.
2422   size_t initial_offset = kIsVdexEnabled ? vdex_size_ : oat_size_;
2423   size_t start_offset = RoundUp(initial_offset, 4);
2424   size_t file_offset = kIsVdexEnabled ? start_offset : (oat_data_offset_ + start_offset);
2425   size_dex_file_alignment_ += start_offset - initial_offset;
2426 
2427   // Seek to the start of the dex file and flush any pending operations in the stream.
2428   // Verify that, after flushing the stream, the file is at the same offset as the stream.
2429   off_t actual_offset = out->Seek(file_offset, kSeekSet);
2430   if (actual_offset != static_cast<off_t>(file_offset)) {
2431     PLOG(ERROR) << "Failed to seek to dex file section. Actual: " << actual_offset
2432                 << " Expected: " << file_offset
2433                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2434     return false;
2435   }
2436   if (!out->Flush()) {
2437     PLOG(ERROR) << "Failed to flush before writing dex file."
2438                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2439     return false;
2440   }
2441   actual_offset = lseek(file->Fd(), 0, SEEK_CUR);
2442   if (actual_offset != static_cast<off_t>(file_offset)) {
2443     PLOG(ERROR) << "Stream/file position mismatch! Actual: " << actual_offset
2444                 << " Expected: " << file_offset
2445                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2446     return false;
2447   }
2448 
2449   if (kIsVdexEnabled) {
2450     vdex_size_ = start_offset;
2451   } else {
2452     oat_size_ = start_offset;
2453   }
2454   oat_dex_file->dex_file_offset_ = start_offset;
2455   return true;
2456 }
2457 
LayoutAndWriteDexFile(OutputStream * out,OatDexFile * oat_dex_file)2458 bool OatWriter::LayoutAndWriteDexFile(OutputStream* out, OatDexFile* oat_dex_file) {
2459   TimingLogger::ScopedTiming split("Dex Layout", timings_);
2460   std::string error_msg;
2461   std::string location(oat_dex_file->GetLocation());
2462   std::unique_ptr<const DexFile> dex_file;
2463   if (oat_dex_file->source_.IsZipEntry()) {
2464     ZipEntry* zip_entry = oat_dex_file->source_.GetZipEntry();
2465     std::unique_ptr<MemMap> mem_map(
2466         zip_entry->ExtractToMemMap(location.c_str(), "classes.dex", &error_msg));
2467     if (mem_map == nullptr) {
2468       LOG(ERROR) << "Failed to extract dex file to mem map for layout: " << error_msg;
2469       return false;
2470     }
2471     dex_file = DexFile::Open(location,
2472                              zip_entry->GetCrc32(),
2473                              std::move(mem_map),
2474                              /* verify */ true,
2475                              /* verify_checksum */ true,
2476                              &error_msg);
2477   } else if (oat_dex_file->source_.IsRawFile()) {
2478     File* raw_file = oat_dex_file->source_.GetRawFile();
2479     dex_file = DexFile::OpenDex(raw_file->Fd(), location, /* verify_checksum */ true, &error_msg);
2480   } else {
2481     // The source data is a vdex file.
2482     CHECK(oat_dex_file->source_.IsRawData())
2483         << static_cast<size_t>(oat_dex_file->source_.GetType());
2484     const uint8_t* raw_dex_file = oat_dex_file->source_.GetRawData();
2485     // Note: The raw data has already been checked to contain the header
2486     // and all the data that the header specifies as the file size.
2487     DCHECK(raw_dex_file != nullptr);
2488     DCHECK(ValidateDexFileHeader(raw_dex_file, oat_dex_file->GetLocation()));
2489     const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_dex_file);
2490     // Since the source may have had its layout changed, or may be quickened, don't verify it.
2491     dex_file = DexFile::Open(raw_dex_file,
2492                              header->file_size_,
2493                              location,
2494                              oat_dex_file->dex_file_location_checksum_,
2495                              nullptr,
2496                              /* verify */ false,
2497                              /* verify_checksum */ false,
2498                              &error_msg);
2499   }
2500   if (dex_file == nullptr) {
2501     LOG(ERROR) << "Failed to open dex file for layout: " << error_msg;
2502     return false;
2503   }
2504   Options options;
2505   options.output_to_memmap_ = true;
2506   DexLayout dex_layout(options, profile_compilation_info_, nullptr);
2507   dex_layout.ProcessDexFile(location.c_str(), dex_file.get(), 0);
2508   std::unique_ptr<MemMap> mem_map(dex_layout.GetAndReleaseMemMap());
2509   if (!WriteDexFile(out, oat_dex_file, mem_map->Begin(), /* update_input_vdex */ false)) {
2510     return false;
2511   }
2512   // Set the checksum of the new oat dex file to be the original file's checksum.
2513   oat_dex_file->dex_file_location_checksum_ = dex_file->GetLocationChecksum();
2514   return true;
2515 }
2516 
WriteDexFile(OutputStream * out,File * file,OatDexFile * oat_dex_file,ZipEntry * dex_file)2517 bool OatWriter::WriteDexFile(OutputStream* out,
2518                              File* file,
2519                              OatDexFile* oat_dex_file,
2520                              ZipEntry* dex_file) {
2521   size_t start_offset = kIsVdexEnabled ? vdex_size_ : oat_data_offset_ + oat_size_;
2522   DCHECK_EQ(static_cast<off_t>(start_offset), out->Seek(0, kSeekCurrent));
2523 
2524   // Extract the dex file and get the extracted size.
2525   std::string error_msg;
2526   if (!dex_file->ExtractToFile(*file, &error_msg)) {
2527     LOG(ERROR) << "Failed to extract dex file from ZIP entry: " << error_msg
2528                << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2529     return false;
2530   }
2531   if (file->Flush() != 0) {
2532     PLOG(ERROR) << "Failed to flush dex file from ZIP entry."
2533                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2534     return false;
2535   }
2536   off_t extracted_end = lseek(file->Fd(), 0, SEEK_CUR);
2537   if (extracted_end == static_cast<off_t>(-1)) {
2538     PLOG(ERROR) << "Failed get end offset after writing dex file from ZIP entry."
2539                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2540     return false;
2541   }
2542   if (extracted_end < static_cast<off_t>(start_offset)) {
2543     LOG(ERROR) << "Dex file end position is before start position! End: " << extracted_end
2544                << " Start: " << start_offset
2545                << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2546     return false;
2547   }
2548   uint64_t extracted_size = static_cast<uint64_t>(extracted_end - start_offset);
2549   if (extracted_size < sizeof(DexFile::Header)) {
2550     LOG(ERROR) << "Extracted dex file is shorter than dex file header. size: "
2551                << extracted_size << " File: " << oat_dex_file->GetLocation();
2552     return false;
2553   }
2554 
2555   // Read the dex file header and extract required data to OatDexFile.
2556   off_t actual_offset = lseek(file->Fd(), start_offset, SEEK_SET);
2557   if (actual_offset != static_cast<off_t>(start_offset)) {
2558     PLOG(ERROR) << "Failed to seek back to dex file header. Actual: " << actual_offset
2559                 << " Expected: " << start_offset
2560                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2561     return false;
2562   }
2563   if (!ReadDexFileHeader(file, oat_dex_file)) {
2564     return false;
2565   }
2566   if (extracted_size < oat_dex_file->dex_file_size_) {
2567     LOG(ERROR) << "Extracted truncated dex file. Extracted size: " << extracted_size
2568                << " file size from header: " << oat_dex_file->dex_file_size_
2569                << " File: " << oat_dex_file->GetLocation();
2570     return false;
2571   }
2572 
2573   // Override the checksum from header with the CRC from ZIP entry.
2574   oat_dex_file->dex_file_location_checksum_ = dex_file->GetCrc32();
2575 
2576   // Seek both file and stream to the end offset.
2577   size_t end_offset = start_offset + oat_dex_file->dex_file_size_;
2578   actual_offset = lseek(file->Fd(), end_offset, SEEK_SET);
2579   if (actual_offset != static_cast<off_t>(end_offset)) {
2580     PLOG(ERROR) << "Failed to seek to end of dex file. Actual: " << actual_offset
2581                 << " Expected: " << end_offset
2582                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2583     return false;
2584   }
2585   actual_offset = out->Seek(end_offset, kSeekSet);
2586   if (actual_offset != static_cast<off_t>(end_offset)) {
2587     PLOG(ERROR) << "Failed to seek stream to end of dex file. Actual: " << actual_offset
2588                 << " Expected: " << end_offset << " File: " << oat_dex_file->GetLocation();
2589     return false;
2590   }
2591   if (!out->Flush()) {
2592     PLOG(ERROR) << "Failed to flush stream after seeking over dex file."
2593                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2594     return false;
2595   }
2596 
2597   // If we extracted more than the size specified in the header, truncate the file.
2598   if (extracted_size > oat_dex_file->dex_file_size_) {
2599     if (file->SetLength(end_offset) != 0) {
2600       PLOG(ERROR) << "Failed to truncate excessive dex file length."
2601                   << " File: " << oat_dex_file->GetLocation()
2602                   << " Output: " << file->GetPath();
2603       return false;
2604     }
2605   }
2606 
2607   return true;
2608 }
2609 
WriteDexFile(OutputStream * out,File * file,OatDexFile * oat_dex_file,File * dex_file)2610 bool OatWriter::WriteDexFile(OutputStream* out,
2611                              File* file,
2612                              OatDexFile* oat_dex_file,
2613                              File* dex_file) {
2614   size_t start_offset = kIsVdexEnabled ? vdex_size_ : oat_data_offset_ + oat_size_;
2615   DCHECK_EQ(static_cast<off_t>(start_offset), out->Seek(0, kSeekCurrent));
2616 
2617   off_t input_offset = lseek(dex_file->Fd(), 0, SEEK_SET);
2618   if (input_offset != static_cast<off_t>(0)) {
2619     PLOG(ERROR) << "Failed to seek to dex file header. Actual: " << input_offset
2620                 << " Expected: 0"
2621                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2622     return false;
2623   }
2624   if (!ReadDexFileHeader(dex_file, oat_dex_file)) {
2625     return false;
2626   }
2627 
2628   // Copy the input dex file using sendfile().
2629   if (!file->Copy(dex_file, 0, oat_dex_file->dex_file_size_)) {
2630     PLOG(ERROR) << "Failed to copy dex file to oat file."
2631                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2632     return false;
2633   }
2634   if (file->Flush() != 0) {
2635     PLOG(ERROR) << "Failed to flush dex file."
2636                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2637     return false;
2638   }
2639 
2640   // Check file position and seek the stream to the end offset.
2641   size_t end_offset = start_offset + oat_dex_file->dex_file_size_;
2642   off_t actual_offset = lseek(file->Fd(), 0, SEEK_CUR);
2643   if (actual_offset != static_cast<off_t>(end_offset)) {
2644     PLOG(ERROR) << "Unexpected file position after copying dex file. Actual: " << actual_offset
2645                 << " Expected: " << end_offset
2646                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2647     return false;
2648   }
2649   actual_offset = out->Seek(end_offset, kSeekSet);
2650   if (actual_offset != static_cast<off_t>(end_offset)) {
2651     PLOG(ERROR) << "Failed to seek stream to end of dex file. Actual: " << actual_offset
2652                 << " Expected: " << end_offset << " File: " << oat_dex_file->GetLocation();
2653     return false;
2654   }
2655   if (!out->Flush()) {
2656     PLOG(ERROR) << "Failed to flush stream after seeking over dex file."
2657                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2658     return false;
2659   }
2660 
2661   return true;
2662 }
2663 
WriteDexFile(OutputStream * out,OatDexFile * oat_dex_file,const uint8_t * dex_file,bool update_input_vdex)2664 bool OatWriter::WriteDexFile(OutputStream* out,
2665                              OatDexFile* oat_dex_file,
2666                              const uint8_t* dex_file,
2667                              bool update_input_vdex) {
2668   // Note: The raw data has already been checked to contain the header
2669   // and all the data that the header specifies as the file size.
2670   DCHECK(dex_file != nullptr);
2671   DCHECK(ValidateDexFileHeader(dex_file, oat_dex_file->GetLocation()));
2672   const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(dex_file);
2673 
2674   if (update_input_vdex) {
2675     // The vdex already contains the dex code, no need to write it again.
2676   } else {
2677     if (!out->WriteFully(dex_file, header->file_size_)) {
2678       PLOG(ERROR) << "Failed to write dex file " << oat_dex_file->GetLocation()
2679                   << " to " << out->GetLocation();
2680       return false;
2681     }
2682     if (!out->Flush()) {
2683       PLOG(ERROR) << "Failed to flush stream after writing dex file."
2684                   << " File: " << oat_dex_file->GetLocation();
2685       return false;
2686     }
2687   }
2688 
2689   // Update dex file size and resize class offsets in the OatDexFile.
2690   // Note: For raw data, the checksum is passed directly to AddRawDexFileSource().
2691   // Note: For vdex, the checksum is copied from the existing vdex file.
2692   oat_dex_file->dex_file_size_ = header->file_size_;
2693   oat_dex_file->class_offsets_.resize(header->class_defs_size_);
2694   return true;
2695 }
2696 
WriteOatDexFiles(OutputStream * rodata)2697 bool OatWriter::WriteOatDexFiles(OutputStream* rodata) {
2698   TimingLogger::ScopedTiming split("WriteOatDexFiles", timings_);
2699 
2700   off_t initial_offset = rodata->Seek(0, kSeekCurrent);
2701   if (initial_offset == static_cast<off_t>(-1)) {
2702     LOG(ERROR) << "Failed to get current position in " << rodata->GetLocation();
2703     return false;
2704   }
2705 
2706   // Seek to the start of OatDexFiles, i.e. to the end of the OatHeader.  If there are
2707   // no OatDexFiles, no data is actually written to .rodata before WriteHeader() and
2708   // this Seek() ensures that we reserve the space for OatHeader in .rodata.
2709   DCHECK(oat_dex_files_.empty() || oat_dex_files_[0u].offset_ == oat_header_->GetHeaderSize());
2710   uint32_t expected_offset = oat_data_offset_ + oat_header_->GetHeaderSize();
2711   off_t actual_offset = rodata->Seek(expected_offset, kSeekSet);
2712   if (static_cast<uint32_t>(actual_offset) != expected_offset) {
2713     PLOG(ERROR) << "Failed to seek to OatDexFile table section. Actual: " << actual_offset
2714                 << " Expected: " << expected_offset << " File: " << rodata->GetLocation();
2715     return false;
2716   }
2717 
2718   for (size_t i = 0, size = oat_dex_files_.size(); i != size; ++i) {
2719     OatDexFile* oat_dex_file = &oat_dex_files_[i];
2720 
2721     DCHECK_EQ(oat_data_offset_ + oat_dex_file->offset_,
2722               static_cast<size_t>(rodata->Seek(0, kSeekCurrent)));
2723 
2724     // Write OatDexFile.
2725     if (!oat_dex_file->Write(this, rodata)) {
2726       PLOG(ERROR) << "Failed to write oat dex information to " << rodata->GetLocation();
2727       return false;
2728     }
2729   }
2730 
2731   // Seek back to the initial position.
2732   if (rodata->Seek(initial_offset, kSeekSet) != initial_offset) {
2733     PLOG(ERROR) << "Failed to seek to initial position. Actual: " << actual_offset
2734                 << " Expected: " << initial_offset << " File: " << rodata->GetLocation();
2735     return false;
2736   }
2737 
2738   return true;
2739 }
2740 
OpenDexFiles(File * file,bool verify,std::unique_ptr<MemMap> * opened_dex_files_map,std::vector<std::unique_ptr<const DexFile>> * opened_dex_files)2741 bool OatWriter::OpenDexFiles(
2742     File* file,
2743     bool verify,
2744     /*out*/ std::unique_ptr<MemMap>* opened_dex_files_map,
2745     /*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files) {
2746   TimingLogger::ScopedTiming split("OpenDexFiles", timings_);
2747 
2748   if (oat_dex_files_.empty()) {
2749     // Nothing to do.
2750     return true;
2751   }
2752 
2753   size_t map_offset = oat_dex_files_[0].dex_file_offset_;
2754   size_t length = kIsVdexEnabled ? (vdex_size_ - map_offset) : (oat_size_ - map_offset);
2755 
2756   std::string error_msg;
2757   std::unique_ptr<MemMap> dex_files_map(MemMap::MapFile(
2758       length,
2759       PROT_READ | PROT_WRITE,
2760       MAP_SHARED,
2761       file->Fd(),
2762       kIsVdexEnabled ? map_offset : (oat_data_offset_ + map_offset),
2763       /* low_4gb */ false,
2764       file->GetPath().c_str(),
2765       &error_msg));
2766   if (dex_files_map == nullptr) {
2767     LOG(ERROR) << "Failed to mmap() dex files from oat file. File: " << file->GetPath()
2768                << " error: " << error_msg;
2769     return false;
2770   }
2771   std::vector<std::unique_ptr<const DexFile>> dex_files;
2772   for (OatDexFile& oat_dex_file : oat_dex_files_) {
2773     // Make sure no one messed with input files while we were copying data.
2774     // At the very least we need consistent file size and number of class definitions.
2775     const uint8_t* raw_dex_file =
2776         dex_files_map->Begin() + oat_dex_file.dex_file_offset_ - map_offset;
2777     if (!ValidateDexFileHeader(raw_dex_file, oat_dex_file.GetLocation())) {
2778       // Note: ValidateDexFileHeader() already logged an error message.
2779       LOG(ERROR) << "Failed to verify written dex file header!"
2780           << " Output: " << file->GetPath() << " ~ " << std::hex << map_offset
2781           << " ~ " << static_cast<const void*>(raw_dex_file);
2782       return false;
2783     }
2784     const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_dex_file);
2785     if (header->file_size_ != oat_dex_file.dex_file_size_) {
2786       LOG(ERROR) << "File size mismatch in written dex file header! Expected: "
2787           << oat_dex_file.dex_file_size_ << " Actual: " << header->file_size_
2788           << " Output: " << file->GetPath();
2789       return false;
2790     }
2791     if (header->class_defs_size_ != oat_dex_file.class_offsets_.size()) {
2792       LOG(ERROR) << "Class defs size mismatch in written dex file header! Expected: "
2793           << oat_dex_file.class_offsets_.size() << " Actual: " << header->class_defs_size_
2794           << " Output: " << file->GetPath();
2795       return false;
2796     }
2797 
2798     // Now, open the dex file.
2799     dex_files.emplace_back(DexFile::Open(raw_dex_file,
2800                                          oat_dex_file.dex_file_size_,
2801                                          oat_dex_file.GetLocation(),
2802                                          oat_dex_file.dex_file_location_checksum_,
2803                                          /* oat_dex_file */ nullptr,
2804                                          verify,
2805                                          verify,
2806                                          &error_msg));
2807     if (dex_files.back() == nullptr) {
2808       LOG(ERROR) << "Failed to open dex file from oat file. File: " << oat_dex_file.GetLocation()
2809                  << " Error: " << error_msg;
2810       return false;
2811     }
2812   }
2813 
2814   *opened_dex_files_map = std::move(dex_files_map);
2815   *opened_dex_files = std::move(dex_files);
2816   return true;
2817 }
2818 
WriteTypeLookupTables(OutputStream * oat_rodata,const std::vector<std::unique_ptr<const DexFile>> & opened_dex_files)2819 bool OatWriter::WriteTypeLookupTables(
2820     OutputStream* oat_rodata,
2821     const std::vector<std::unique_ptr<const DexFile>>& opened_dex_files) {
2822   TimingLogger::ScopedTiming split("WriteTypeLookupTables", timings_);
2823 
2824   uint32_t expected_offset = oat_data_offset_ + oat_size_;
2825   off_t actual_offset = oat_rodata->Seek(expected_offset, kSeekSet);
2826   if (static_cast<uint32_t>(actual_offset) != expected_offset) {
2827     PLOG(ERROR) << "Failed to seek to TypeLookupTable section. Actual: " << actual_offset
2828                 << " Expected: " << expected_offset << " File: " << oat_rodata->GetLocation();
2829     return false;
2830   }
2831 
2832   DCHECK_EQ(opened_dex_files.size(), oat_dex_files_.size());
2833   for (size_t i = 0, size = opened_dex_files.size(); i != size; ++i) {
2834     OatDexFile* oat_dex_file = &oat_dex_files_[i];
2835     DCHECK_EQ(oat_dex_file->lookup_table_offset_, 0u);
2836 
2837     if (oat_dex_file->create_type_lookup_table_ != CreateTypeLookupTable::kCreate ||
2838         oat_dex_file->class_offsets_.empty()) {
2839       continue;
2840     }
2841 
2842     size_t table_size = TypeLookupTable::RawDataLength(oat_dex_file->class_offsets_.size());
2843     if (table_size == 0u) {
2844       continue;
2845     }
2846 
2847     // Create the lookup table. When `nullptr` is given as the storage buffer,
2848     // TypeLookupTable allocates its own and OatDexFile takes ownership.
2849     const DexFile& dex_file = *opened_dex_files[i];
2850     {
2851       std::unique_ptr<TypeLookupTable> type_lookup_table =
2852           TypeLookupTable::Create(dex_file, /* storage */ nullptr);
2853       type_lookup_table_oat_dex_files_.push_back(
2854           std::make_unique<art::OatDexFile>(std::move(type_lookup_table)));
2855       dex_file.SetOatDexFile(type_lookup_table_oat_dex_files_.back().get());
2856     }
2857     TypeLookupTable* const table = type_lookup_table_oat_dex_files_.back()->GetTypeLookupTable();
2858 
2859     // Type tables are required to be 4 byte aligned.
2860     size_t initial_offset = oat_size_;
2861     size_t rodata_offset = RoundUp(initial_offset, 4);
2862     size_t padding_size = rodata_offset - initial_offset;
2863 
2864     if (padding_size != 0u) {
2865       std::vector<uint8_t> buffer(padding_size, 0u);
2866       if (!oat_rodata->WriteFully(buffer.data(), padding_size)) {
2867         PLOG(ERROR) << "Failed to write lookup table alignment padding."
2868                     << " File: " << oat_dex_file->GetLocation()
2869                     << " Output: " << oat_rodata->GetLocation();
2870         return false;
2871       }
2872     }
2873 
2874     DCHECK_EQ(oat_data_offset_ + rodata_offset,
2875               static_cast<size_t>(oat_rodata->Seek(0u, kSeekCurrent)));
2876     DCHECK_EQ(table_size, table->RawDataLength());
2877 
2878     if (!oat_rodata->WriteFully(table->RawData(), table_size)) {
2879       PLOG(ERROR) << "Failed to write lookup table."
2880                   << " File: " << oat_dex_file->GetLocation()
2881                   << " Output: " << oat_rodata->GetLocation();
2882       return false;
2883     }
2884 
2885     oat_dex_file->lookup_table_offset_ = rodata_offset;
2886 
2887     oat_size_ += padding_size + table_size;
2888     size_oat_lookup_table_ += table_size;
2889     size_oat_lookup_table_alignment_ += padding_size;
2890   }
2891 
2892   if (!oat_rodata->Flush()) {
2893     PLOG(ERROR) << "Failed to flush stream after writing type lookup tables."
2894                 << " File: " << oat_rodata->GetLocation();
2895     return false;
2896   }
2897 
2898   return true;
2899 }
2900 
WriteChecksumsAndVdexHeader(OutputStream * vdex_out)2901 bool OatWriter::WriteChecksumsAndVdexHeader(OutputStream* vdex_out) {
2902   if (!kIsVdexEnabled) {
2903     return true;
2904   }
2905   // Write checksums
2906   off_t actual_offset = vdex_out->Seek(sizeof(VdexFile::Header), kSeekSet);
2907   if (actual_offset != sizeof(VdexFile::Header)) {
2908     PLOG(ERROR) << "Failed to seek to the checksum location of vdex file. Actual: " << actual_offset
2909                 << " File: " << vdex_out->GetLocation();
2910     return false;
2911   }
2912 
2913   for (size_t i = 0, size = oat_dex_files_.size(); i != size; ++i) {
2914     OatDexFile* oat_dex_file = &oat_dex_files_[i];
2915     if (!vdex_out->WriteFully(
2916             &oat_dex_file->dex_file_location_checksum_, sizeof(VdexFile::VdexChecksum))) {
2917       PLOG(ERROR) << "Failed to write dex file location checksum. File: "
2918                   << vdex_out->GetLocation();
2919       return false;
2920     }
2921     size_vdex_checksums_ += sizeof(VdexFile::VdexChecksum);
2922   }
2923 
2924   // Write header.
2925   actual_offset = vdex_out->Seek(0, kSeekSet);
2926   if (actual_offset != 0) {
2927     PLOG(ERROR) << "Failed to seek to the beginning of vdex file. Actual: " << actual_offset
2928                 << " File: " << vdex_out->GetLocation();
2929     return false;
2930   }
2931 
2932   DCHECK_NE(vdex_dex_files_offset_, 0u);
2933   DCHECK_NE(vdex_verifier_deps_offset_, 0u);
2934 
2935   size_t dex_section_size = vdex_verifier_deps_offset_ - vdex_dex_files_offset_;
2936   size_t verifier_deps_section_size = vdex_quickening_info_offset_ - vdex_verifier_deps_offset_;
2937   size_t quickening_info_section_size = vdex_size_ - vdex_quickening_info_offset_;
2938 
2939   VdexFile::Header vdex_header(oat_dex_files_.size(),
2940                                dex_section_size,
2941                                verifier_deps_section_size,
2942                                quickening_info_section_size);
2943   if (!vdex_out->WriteFully(&vdex_header, sizeof(VdexFile::Header))) {
2944     PLOG(ERROR) << "Failed to write vdex header. File: " << vdex_out->GetLocation();
2945     return false;
2946   }
2947   size_vdex_header_ = sizeof(VdexFile::Header);
2948 
2949   if (!vdex_out->Flush()) {
2950     PLOG(ERROR) << "Failed to flush stream after writing to vdex file."
2951                 << " File: " << vdex_out->GetLocation();
2952     return false;
2953   }
2954 
2955   return true;
2956 }
2957 
WriteCodeAlignment(OutputStream * out,uint32_t aligned_code_delta)2958 bool OatWriter::WriteCodeAlignment(OutputStream* out, uint32_t aligned_code_delta) {
2959   static const uint8_t kPadding[] = {
2960       0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u
2961   };
2962   DCHECK_LE(aligned_code_delta, sizeof(kPadding));
2963   if (UNLIKELY(!out->WriteFully(kPadding, aligned_code_delta))) {
2964     return false;
2965   }
2966   size_code_alignment_ += aligned_code_delta;
2967   return true;
2968 }
2969 
SetMultiOatRelativePatcherAdjustment()2970 void OatWriter::SetMultiOatRelativePatcherAdjustment() {
2971   DCHECK(dex_files_ != nullptr);
2972   DCHECK(relative_patcher_ != nullptr);
2973   DCHECK_NE(oat_data_offset_, 0u);
2974   if (image_writer_ != nullptr && !dex_files_->empty()) {
2975     // The oat data begin may not be initialized yet but the oat file offset is ready.
2976     size_t oat_index = image_writer_->GetOatIndexForDexFile(dex_files_->front());
2977     size_t elf_file_offset = image_writer_->GetOatFileOffset(oat_index);
2978     relative_patcher_->StartOatFile(elf_file_offset + oat_data_offset_);
2979   }
2980 }
2981 
OatDexFile(const char * dex_file_location,DexFileSource source,CreateTypeLookupTable create_type_lookup_table)2982 OatWriter::OatDexFile::OatDexFile(const char* dex_file_location,
2983                                   DexFileSource source,
2984                                   CreateTypeLookupTable create_type_lookup_table)
2985     : source_(source),
2986       create_type_lookup_table_(create_type_lookup_table),
2987       dex_file_size_(0),
2988       offset_(0),
2989       dex_file_location_size_(strlen(dex_file_location)),
2990       dex_file_location_data_(dex_file_location),
2991       dex_file_location_checksum_(0u),
2992       dex_file_offset_(0u),
2993       class_offsets_offset_(0u),
2994       lookup_table_offset_(0u),
2995       class_offsets_() {
2996 }
2997 
SizeOf() const2998 size_t OatWriter::OatDexFile::SizeOf() const {
2999   return sizeof(dex_file_location_size_)
3000           + dex_file_location_size_
3001           + sizeof(dex_file_location_checksum_)
3002           + sizeof(dex_file_offset_)
3003           + sizeof(class_offsets_offset_)
3004           + sizeof(lookup_table_offset_);
3005 }
3006 
ReserveClassOffsets(OatWriter * oat_writer)3007 void OatWriter::OatDexFile::ReserveClassOffsets(OatWriter* oat_writer) {
3008   DCHECK_EQ(class_offsets_offset_, 0u);
3009   if (!class_offsets_.empty()) {
3010     // Class offsets are required to be 4 byte aligned.
3011     size_t initial_offset = oat_writer->oat_size_;
3012     size_t offset = RoundUp(initial_offset, 4);
3013     oat_writer->size_oat_class_offsets_alignment_ += offset - initial_offset;
3014     class_offsets_offset_ = offset;
3015     oat_writer->oat_size_ = offset + GetClassOffsetsRawSize();
3016   }
3017 }
3018 
Write(OatWriter * oat_writer,OutputStream * out) const3019 bool OatWriter::OatDexFile::Write(OatWriter* oat_writer, OutputStream* out) const {
3020   const size_t file_offset = oat_writer->oat_data_offset_;
3021   DCHECK_OFFSET_();
3022 
3023   if (!out->WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) {
3024     PLOG(ERROR) << "Failed to write dex file location length to " << out->GetLocation();
3025     return false;
3026   }
3027   oat_writer->size_oat_dex_file_location_size_ += sizeof(dex_file_location_size_);
3028 
3029   if (!out->WriteFully(dex_file_location_data_, dex_file_location_size_)) {
3030     PLOG(ERROR) << "Failed to write dex file location data to " << out->GetLocation();
3031     return false;
3032   }
3033   oat_writer->size_oat_dex_file_location_data_ += dex_file_location_size_;
3034 
3035   if (!out->WriteFully(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_))) {
3036     PLOG(ERROR) << "Failed to write dex file location checksum to " << out->GetLocation();
3037     return false;
3038   }
3039   oat_writer->size_oat_dex_file_location_checksum_ += sizeof(dex_file_location_checksum_);
3040 
3041   if (!out->WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) {
3042     PLOG(ERROR) << "Failed to write dex file offset to " << out->GetLocation();
3043     return false;
3044   }
3045   oat_writer->size_oat_dex_file_offset_ += sizeof(dex_file_offset_);
3046 
3047   if (!out->WriteFully(&class_offsets_offset_, sizeof(class_offsets_offset_))) {
3048     PLOG(ERROR) << "Failed to write class offsets offset to " << out->GetLocation();
3049     return false;
3050   }
3051   oat_writer->size_oat_dex_file_class_offsets_offset_ += sizeof(class_offsets_offset_);
3052 
3053   if (!out->WriteFully(&lookup_table_offset_, sizeof(lookup_table_offset_))) {
3054     PLOG(ERROR) << "Failed to write lookup table offset to " << out->GetLocation();
3055     return false;
3056   }
3057   oat_writer->size_oat_dex_file_lookup_table_offset_ += sizeof(lookup_table_offset_);
3058 
3059   return true;
3060 }
3061 
WriteClassOffsets(OatWriter * oat_writer,OutputStream * out)3062 bool OatWriter::OatDexFile::WriteClassOffsets(OatWriter* oat_writer, OutputStream* out) {
3063   if (!out->WriteFully(class_offsets_.data(), GetClassOffsetsRawSize())) {
3064     PLOG(ERROR) << "Failed to write oat class offsets for " << GetLocation()
3065                 << " to " << out->GetLocation();
3066     return false;
3067   }
3068   oat_writer->size_oat_class_offsets_ += GetClassOffsetsRawSize();
3069   return true;
3070 }
3071 
OatClass(size_t offset,const dchecked_vector<CompiledMethod * > & compiled_methods,uint32_t num_non_null_compiled_methods,mirror::Class::Status status)3072 OatWriter::OatClass::OatClass(size_t offset,
3073                               const dchecked_vector<CompiledMethod*>& compiled_methods,
3074                               uint32_t num_non_null_compiled_methods,
3075                               mirror::Class::Status status)
3076     : compiled_methods_(compiled_methods) {
3077   uint32_t num_methods = compiled_methods.size();
3078   CHECK_LE(num_non_null_compiled_methods, num_methods);
3079 
3080   offset_ = offset;
3081   oat_method_offsets_offsets_from_oat_class_.resize(num_methods);
3082 
3083   // Since both kOatClassNoneCompiled and kOatClassAllCompiled could
3084   // apply when there are 0 methods, we just arbitrarily say that 0
3085   // methods means kOatClassNoneCompiled and that we won't use
3086   // kOatClassAllCompiled unless there is at least one compiled
3087   // method. This means in an interpretter only system, we can assert
3088   // that all classes are kOatClassNoneCompiled.
3089   if (num_non_null_compiled_methods == 0) {
3090     type_ = kOatClassNoneCompiled;
3091   } else if (num_non_null_compiled_methods == num_methods) {
3092     type_ = kOatClassAllCompiled;
3093   } else {
3094     type_ = kOatClassSomeCompiled;
3095   }
3096 
3097   status_ = status;
3098   method_offsets_.resize(num_non_null_compiled_methods);
3099   method_headers_.resize(num_non_null_compiled_methods);
3100 
3101   uint32_t oat_method_offsets_offset_from_oat_class = sizeof(type_) + sizeof(status_);
3102   if (type_ == kOatClassSomeCompiled) {
3103     method_bitmap_.reset(new BitVector(num_methods, false, Allocator::GetMallocAllocator()));
3104     method_bitmap_size_ = method_bitmap_->GetSizeOf();
3105     oat_method_offsets_offset_from_oat_class += sizeof(method_bitmap_size_);
3106     oat_method_offsets_offset_from_oat_class += method_bitmap_size_;
3107   } else {
3108     method_bitmap_ = nullptr;
3109     method_bitmap_size_ = 0;
3110   }
3111 
3112   for (size_t i = 0; i < num_methods; i++) {
3113     CompiledMethod* compiled_method = compiled_methods_[i];
3114     if (compiled_method == nullptr) {
3115       oat_method_offsets_offsets_from_oat_class_[i] = 0;
3116     } else {
3117       oat_method_offsets_offsets_from_oat_class_[i] = oat_method_offsets_offset_from_oat_class;
3118       oat_method_offsets_offset_from_oat_class += sizeof(OatMethodOffsets);
3119       if (type_ == kOatClassSomeCompiled) {
3120         method_bitmap_->SetBit(i);
3121       }
3122     }
3123   }
3124 }
3125 
GetOatMethodOffsetsOffsetFromOatHeader(size_t class_def_method_index_) const3126 size_t OatWriter::OatClass::GetOatMethodOffsetsOffsetFromOatHeader(
3127     size_t class_def_method_index_) const {
3128   uint32_t method_offset = GetOatMethodOffsetsOffsetFromOatClass(class_def_method_index_);
3129   if (method_offset == 0) {
3130     return 0;
3131   }
3132   return offset_ + method_offset;
3133 }
3134 
GetOatMethodOffsetsOffsetFromOatClass(size_t class_def_method_index_) const3135 size_t OatWriter::OatClass::GetOatMethodOffsetsOffsetFromOatClass(
3136     size_t class_def_method_index_) const {
3137   return oat_method_offsets_offsets_from_oat_class_[class_def_method_index_];
3138 }
3139 
SizeOf() const3140 size_t OatWriter::OatClass::SizeOf() const {
3141   return sizeof(status_)
3142           + sizeof(type_)
3143           + ((method_bitmap_size_ == 0) ? 0 : sizeof(method_bitmap_size_))
3144           + method_bitmap_size_
3145           + (sizeof(method_offsets_[0]) * method_offsets_.size());
3146 }
3147 
Write(OatWriter * oat_writer,OutputStream * out,const size_t file_offset) const3148 bool OatWriter::OatClass::Write(OatWriter* oat_writer,
3149                                 OutputStream* out,
3150                                 const size_t file_offset) const {
3151   DCHECK_OFFSET_();
3152   if (!out->WriteFully(&status_, sizeof(status_))) {
3153     PLOG(ERROR) << "Failed to write class status to " << out->GetLocation();
3154     return false;
3155   }
3156   oat_writer->size_oat_class_status_ += sizeof(status_);
3157 
3158   if (!out->WriteFully(&type_, sizeof(type_))) {
3159     PLOG(ERROR) << "Failed to write oat class type to " << out->GetLocation();
3160     return false;
3161   }
3162   oat_writer->size_oat_class_type_ += sizeof(type_);
3163 
3164   if (method_bitmap_size_ != 0) {
3165     CHECK_EQ(kOatClassSomeCompiled, type_);
3166     if (!out->WriteFully(&method_bitmap_size_, sizeof(method_bitmap_size_))) {
3167       PLOG(ERROR) << "Failed to write method bitmap size to " << out->GetLocation();
3168       return false;
3169     }
3170     oat_writer->size_oat_class_method_bitmaps_ += sizeof(method_bitmap_size_);
3171 
3172     if (!out->WriteFully(method_bitmap_->GetRawStorage(), method_bitmap_size_)) {
3173       PLOG(ERROR) << "Failed to write method bitmap to " << out->GetLocation();
3174       return false;
3175     }
3176     oat_writer->size_oat_class_method_bitmaps_ += method_bitmap_size_;
3177   }
3178 
3179   if (!out->WriteFully(method_offsets_.data(), GetMethodOffsetsRawSize())) {
3180     PLOG(ERROR) << "Failed to write method offsets to " << out->GetLocation();
3181     return false;
3182   }
3183   oat_writer->size_oat_class_method_offsets_ += GetMethodOffsetsRawSize();
3184   return true;
3185 }
3186 
3187 }  // namespace art
3188