Home | History | Annotate | Download | only in dexlayout
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "dex_writer.h"
     18 
     19 #include <stdint.h>
     20 
     21 #include <vector>
     22 
     23 #include "compact_dex_writer.h"
     24 #include "dex/compact_dex_file.h"
     25 #include "dex/dex_file_layout.h"
     26 #include "dex/dex_file_types.h"
     27 #include "dex/standard_dex_file.h"
     28 #include "dex/utf.h"
     29 #include "dexlayout.h"
     30 
     31 namespace art {
     32 
     33 constexpr uint32_t DexWriter::kDataSectionAlignment;
     34 
     35 static size_t EncodeIntValue(int32_t value, uint8_t* buffer) {
     36   size_t length = 0;
     37   if (value >= 0) {
     38     while (value > 0x7f) {
     39       buffer[length++] = static_cast<uint8_t>(value);
     40       value >>= 8;
     41     }
     42   } else {
     43     while (value < -0x80) {
     44       buffer[length++] = static_cast<uint8_t>(value);
     45       value >>= 8;
     46     }
     47   }
     48   buffer[length++] = static_cast<uint8_t>(value);
     49   return length;
     50 }
     51 
     52 static size_t EncodeUIntValue(uint32_t value, uint8_t* buffer) {
     53   size_t length = 0;
     54   do {
     55     buffer[length++] = static_cast<uint8_t>(value);
     56     value >>= 8;
     57   } while (value != 0);
     58   return length;
     59 }
     60 
     61 static size_t EncodeLongValue(int64_t value, uint8_t* buffer) {
     62   size_t length = 0;
     63   if (value >= 0) {
     64     while (value > 0x7f) {
     65       buffer[length++] = static_cast<uint8_t>(value);
     66       value >>= 8;
     67     }
     68   } else {
     69     while (value < -0x80) {
     70       buffer[length++] = static_cast<uint8_t>(value);
     71       value >>= 8;
     72     }
     73   }
     74   buffer[length++] = static_cast<uint8_t>(value);
     75   return length;
     76 }
     77 
     78 union FloatUnion {
     79   float f_;
     80   uint32_t i_;
     81 };
     82 
     83 static size_t EncodeFloatValue(float value, uint8_t* buffer) {
     84   FloatUnion float_union;
     85   float_union.f_ = value;
     86   uint32_t int_value = float_union.i_;
     87   size_t index = 3;
     88   do {
     89     buffer[index--] = int_value >> 24;
     90     int_value <<= 8;
     91   } while (int_value != 0);
     92   return 3 - index;
     93 }
     94 
     95 union DoubleUnion {
     96   double d_;
     97   uint64_t l_;
     98 };
     99 
    100 static size_t EncodeDoubleValue(double value, uint8_t* buffer) {
    101   DoubleUnion double_union;
    102   double_union.d_ = value;
    103   uint64_t long_value = double_union.l_;
    104   size_t index = 7;
    105   do {
    106     buffer[index--] = long_value >> 56;
    107     long_value <<= 8;
    108   } while (long_value != 0);
    109   return 7 - index;
    110 }
    111 
    112 DexWriter::DexWriter(DexLayout* dex_layout, bool compute_offsets)
    113     : header_(dex_layout->GetHeader()),
    114       dex_layout_(dex_layout),
    115       compute_offsets_(compute_offsets) {}
    116 
    117 void DexWriter::WriteEncodedValue(Stream* stream, dex_ir::EncodedValue* encoded_value) {
    118   size_t start = 0;
    119   size_t length;
    120   uint8_t buffer[8];
    121   int8_t type = encoded_value->Type();
    122   switch (type) {
    123     case DexFile::kDexAnnotationByte:
    124       length = EncodeIntValue(encoded_value->GetByte(), buffer);
    125       break;
    126     case DexFile::kDexAnnotationShort:
    127       length = EncodeIntValue(encoded_value->GetShort(), buffer);
    128       break;
    129     case DexFile::kDexAnnotationChar:
    130       length = EncodeUIntValue(encoded_value->GetChar(), buffer);
    131       break;
    132     case DexFile::kDexAnnotationInt:
    133       length = EncodeIntValue(encoded_value->GetInt(), buffer);
    134       break;
    135     case DexFile::kDexAnnotationLong:
    136       length = EncodeLongValue(encoded_value->GetLong(), buffer);
    137       break;
    138     case DexFile::kDexAnnotationFloat:
    139       length = EncodeFloatValue(encoded_value->GetFloat(), buffer);
    140       start = 4 - length;
    141       break;
    142     case DexFile::kDexAnnotationDouble:
    143       length = EncodeDoubleValue(encoded_value->GetDouble(), buffer);
    144       start = 8 - length;
    145       break;
    146     case DexFile::kDexAnnotationMethodType:
    147       length = EncodeUIntValue(encoded_value->GetProtoId()->GetIndex(), buffer);
    148       break;
    149     case DexFile::kDexAnnotationMethodHandle:
    150       length = EncodeUIntValue(encoded_value->GetMethodHandle()->GetIndex(), buffer);
    151       break;
    152     case DexFile::kDexAnnotationString:
    153       length = EncodeUIntValue(encoded_value->GetStringId()->GetIndex(), buffer);
    154       break;
    155     case DexFile::kDexAnnotationType:
    156       length = EncodeUIntValue(encoded_value->GetTypeId()->GetIndex(), buffer);
    157       break;
    158     case DexFile::kDexAnnotationField:
    159     case DexFile::kDexAnnotationEnum:
    160       length = EncodeUIntValue(encoded_value->GetFieldId()->GetIndex(), buffer);
    161       break;
    162     case DexFile::kDexAnnotationMethod:
    163       length = EncodeUIntValue(encoded_value->GetMethodId()->GetIndex(), buffer);
    164       break;
    165     case DexFile::kDexAnnotationArray:
    166       WriteEncodedValueHeader(stream, type, 0);
    167       WriteEncodedArray(stream, encoded_value->GetEncodedArray()->GetEncodedValues());
    168       return;
    169     case DexFile::kDexAnnotationAnnotation:
    170       WriteEncodedValueHeader(stream, type, 0);
    171       WriteEncodedAnnotation(stream, encoded_value->GetEncodedAnnotation());
    172       return;
    173     case DexFile::kDexAnnotationNull:
    174       WriteEncodedValueHeader(stream, type, 0);
    175       return;
    176     case DexFile::kDexAnnotationBoolean:
    177       WriteEncodedValueHeader(stream, type, encoded_value->GetBoolean() ? 1 : 0);
    178       return;
    179     default:
    180       return;
    181   }
    182   WriteEncodedValueHeader(stream, type, length - 1);
    183   stream->Write(buffer + start, length);
    184 }
    185 
    186 void DexWriter::WriteEncodedValueHeader(Stream* stream, int8_t value_type, size_t value_arg) {
    187   uint8_t buffer[1] = { static_cast<uint8_t>((value_arg << 5) | value_type) };
    188   stream->Write(buffer, sizeof(uint8_t));
    189 }
    190 
    191 void DexWriter::WriteEncodedArray(Stream* stream, dex_ir::EncodedValueVector* values) {
    192   stream->WriteUleb128(values->size());
    193   for (std::unique_ptr<dex_ir::EncodedValue>& value : *values) {
    194     WriteEncodedValue(stream, value.get());
    195   }
    196 }
    197 
    198 void DexWriter::WriteEncodedAnnotation(Stream* stream, dex_ir::EncodedAnnotation* annotation) {
    199   stream->WriteUleb128(annotation->GetType()->GetIndex());
    200   stream->WriteUleb128(annotation->GetAnnotationElements()->size());
    201   for (std::unique_ptr<dex_ir::AnnotationElement>& annotation_element :
    202       *annotation->GetAnnotationElements()) {
    203     stream->WriteUleb128(annotation_element->GetName()->GetIndex());
    204     WriteEncodedValue(stream, annotation_element->GetValue());
    205   }
    206 }
    207 
    208 void DexWriter::WriteEncodedFields(Stream* stream, dex_ir::FieldItemVector* fields) {
    209   uint32_t prev_index = 0;
    210   for (auto& field : *fields) {
    211     uint32_t index = field.GetFieldId()->GetIndex();
    212     stream->WriteUleb128(index - prev_index);
    213     stream->WriteUleb128(field.GetAccessFlags());
    214     prev_index = index;
    215   }
    216 }
    217 
    218 void DexWriter::WriteEncodedMethods(Stream* stream, dex_ir::MethodItemVector* methods) {
    219   uint32_t prev_index = 0;
    220   for (auto& method : *methods) {
    221     uint32_t index = method.GetMethodId()->GetIndex();
    222     uint32_t code_off = method.GetCodeItem() == nullptr ? 0 : method.GetCodeItem()->GetOffset();
    223     stream->WriteUleb128(index - prev_index);
    224     stream->WriteUleb128(method.GetAccessFlags());
    225     stream->WriteUleb128(code_off);
    226     prev_index = index;
    227   }
    228 }
    229 
    230 // TODO: Refactor this to remove duplicated boiler plate. One way to do this is adding
    231 // function that takes a CollectionVector<T> and uses overloading.
    232 void DexWriter::WriteStringIds(Stream* stream, bool reserve_only) {
    233   const uint32_t start = stream->Tell();
    234   for (auto& string_id : header_->StringIds()) {
    235     stream->AlignTo(SectionAlignment(DexFile::kDexTypeStringIdItem));
    236     if (reserve_only) {
    237       stream->Skip(string_id->GetSize());
    238     } else {
    239       uint32_t string_data_off = string_id->DataItem()->GetOffset();
    240       stream->Write(&string_data_off, string_id->GetSize());
    241     }
    242   }
    243   if (compute_offsets_ && start != stream->Tell()) {
    244     header_->StringIds().SetOffset(start);
    245   }
    246 }
    247 
    248 void DexWriter::WriteStringData(Stream* stream, dex_ir::StringData* string_data) {
    249   ProcessOffset(stream, string_data);
    250   stream->AlignTo(SectionAlignment(DexFile::kDexTypeStringDataItem));
    251   stream->WriteUleb128(CountModifiedUtf8Chars(string_data->Data()));
    252   stream->Write(string_data->Data(), strlen(string_data->Data()));
    253   // Skip null terminator (already zeroed out, no need to write).
    254   stream->Skip(1);
    255 }
    256 
    257 void DexWriter::WriteStringDatas(Stream* stream) {
    258   const uint32_t start = stream->Tell();
    259   for (auto& string_data : header_->StringDatas()) {
    260     WriteStringData(stream, string_data.get());
    261   }
    262   if (compute_offsets_ && start != stream->Tell()) {
    263     header_->StringDatas().SetOffset(start);
    264   }
    265 }
    266 
    267 void DexWriter::WriteTypeIds(Stream* stream) {
    268   uint32_t descriptor_idx[1];
    269   const uint32_t start = stream->Tell();
    270   for (auto& type_id : header_->TypeIds()) {
    271     stream->AlignTo(SectionAlignment(DexFile::kDexTypeTypeIdItem));
    272     ProcessOffset(stream, type_id.get());
    273     descriptor_idx[0] = type_id->GetStringId()->GetIndex();
    274     stream->Write(descriptor_idx, type_id->GetSize());
    275   }
    276   if (compute_offsets_ && start != stream->Tell()) {
    277     header_->TypeIds().SetOffset(start);
    278   }
    279 }
    280 
    281 void DexWriter::WriteTypeLists(Stream* stream) {
    282   uint32_t size[1];
    283   uint16_t list[1];
    284   const uint32_t start = stream->Tell();
    285   for (auto& type_list : header_->TypeLists()) {
    286     stream->AlignTo(SectionAlignment(DexFile::kDexTypeTypeList));
    287     size[0] = type_list->GetTypeList()->size();
    288     ProcessOffset(stream, type_list.get());
    289     stream->Write(size, sizeof(uint32_t));
    290     for (const dex_ir::TypeId* type_id : *type_list->GetTypeList()) {
    291       list[0] = type_id->GetIndex();
    292       stream->Write(list, sizeof(uint16_t));
    293     }
    294   }
    295   if (compute_offsets_ && start != stream->Tell()) {
    296     header_->TypeLists().SetOffset(start);
    297   }
    298 }
    299 
    300 void DexWriter::WriteProtoIds(Stream* stream, bool reserve_only) {
    301   uint32_t buffer[3];
    302   const uint32_t start = stream->Tell();
    303   for (auto& proto_id : header_->ProtoIds()) {
    304     stream->AlignTo(SectionAlignment(DexFile::kDexTypeProtoIdItem));
    305     ProcessOffset(stream, proto_id.get());
    306     if (reserve_only) {
    307       stream->Skip(proto_id->GetSize());
    308     } else {
    309       buffer[0] = proto_id->Shorty()->GetIndex();
    310       buffer[1] = proto_id->ReturnType()->GetIndex();
    311       buffer[2] = proto_id->Parameters() == nullptr ? 0 : proto_id->Parameters()->GetOffset();
    312       stream->Write(buffer, proto_id->GetSize());
    313     }
    314   }
    315   if (compute_offsets_ && start != stream->Tell()) {
    316     header_->ProtoIds().SetOffset(start);
    317   }
    318 }
    319 
    320 void DexWriter::WriteFieldIds(Stream* stream) {
    321   uint16_t buffer[4];
    322   const uint32_t start = stream->Tell();
    323   for (auto& field_id : header_->FieldIds()) {
    324     stream->AlignTo(SectionAlignment(DexFile::kDexTypeFieldIdItem));
    325     ProcessOffset(stream, field_id.get());
    326     buffer[0] = field_id->Class()->GetIndex();
    327     buffer[1] = field_id->Type()->GetIndex();
    328     buffer[2] = field_id->Name()->GetIndex();
    329     buffer[3] = field_id->Name()->GetIndex() >> 16;
    330     stream->Write(buffer, field_id->GetSize());
    331   }
    332   if (compute_offsets_ && start != stream->Tell()) {
    333     header_->FieldIds().SetOffset(start);
    334   }
    335 }
    336 
    337 void DexWriter::WriteMethodIds(Stream* stream) {
    338   uint16_t buffer[4];
    339   const uint32_t start = stream->Tell();
    340   for (auto& method_id : header_->MethodIds()) {
    341     stream->AlignTo(SectionAlignment(DexFile::kDexTypeMethodIdItem));
    342     ProcessOffset(stream, method_id.get());
    343     buffer[0] = method_id->Class()->GetIndex();
    344     buffer[1] = method_id->Proto()->GetIndex();
    345     buffer[2] = method_id->Name()->GetIndex();
    346     buffer[3] = method_id->Name()->GetIndex() >> 16;
    347     stream->Write(buffer, method_id->GetSize());
    348   }
    349   if (compute_offsets_ && start != stream->Tell()) {
    350     header_->MethodIds().SetOffset(start);
    351   }
    352 }
    353 
    354 void DexWriter::WriteEncodedArrays(Stream* stream) {
    355   const uint32_t start = stream->Tell();
    356   for (auto& encoded_array : header_->EncodedArrayItems()) {
    357     stream->AlignTo(SectionAlignment(DexFile::kDexTypeEncodedArrayItem));
    358     ProcessOffset(stream, encoded_array.get());
    359     WriteEncodedArray(stream, encoded_array->GetEncodedValues());
    360   }
    361   if (compute_offsets_ && start != stream->Tell()) {
    362     header_->EncodedArrayItems().SetOffset(start);
    363   }
    364 }
    365 
    366 void DexWriter::WriteAnnotations(Stream* stream) {
    367   uint8_t visibility[1];
    368   const uint32_t start = stream->Tell();
    369   for (auto& annotation : header_->AnnotationItems()) {
    370     stream->AlignTo(SectionAlignment(DexFile::kDexTypeAnnotationItem));
    371     visibility[0] = annotation->GetVisibility();
    372     ProcessOffset(stream, annotation.get());
    373     stream->Write(visibility, sizeof(uint8_t));
    374     WriteEncodedAnnotation(stream, annotation->GetAnnotation());
    375   }
    376   if (compute_offsets_ && start != stream->Tell()) {
    377     header_->AnnotationItems().SetOffset(start);
    378   }
    379 }
    380 
    381 void DexWriter::WriteAnnotationSets(Stream* stream) {
    382   uint32_t size[1];
    383   uint32_t annotation_off[1];
    384   const uint32_t start = stream->Tell();
    385   for (auto& annotation_set : header_->AnnotationSetItems()) {
    386     stream->AlignTo(SectionAlignment(DexFile::kDexTypeAnnotationSetItem));
    387     size[0] = annotation_set->GetItems()->size();
    388     ProcessOffset(stream, annotation_set.get());
    389     stream->Write(size, sizeof(uint32_t));
    390     for (dex_ir::AnnotationItem* annotation : *annotation_set->GetItems()) {
    391       annotation_off[0] = annotation->GetOffset();
    392       stream->Write(annotation_off, sizeof(uint32_t));
    393     }
    394   }
    395   if (compute_offsets_ && start != stream->Tell()) {
    396     header_->AnnotationSetItems().SetOffset(start);
    397   }
    398 }
    399 
    400 void DexWriter::WriteAnnotationSetRefs(Stream* stream) {
    401   uint32_t size[1];
    402   uint32_t annotations_off[1];
    403   const uint32_t start = stream->Tell();
    404   for (auto& annotation_set_ref : header_->AnnotationSetRefLists()) {
    405     stream->AlignTo(SectionAlignment(DexFile::kDexTypeAnnotationSetRefList));
    406     size[0] = annotation_set_ref->GetItems()->size();
    407     ProcessOffset(stream, annotation_set_ref.get());
    408     stream->Write(size, sizeof(uint32_t));
    409     for (dex_ir::AnnotationSetItem* annotation_set : *annotation_set_ref->GetItems()) {
    410       annotations_off[0] = annotation_set == nullptr ? 0 : annotation_set->GetOffset();
    411       stream->Write(annotations_off, sizeof(uint32_t));
    412     }
    413   }
    414   if (compute_offsets_ && start != stream->Tell()) {
    415     header_->AnnotationSetRefLists().SetOffset(start);
    416   }
    417 }
    418 
    419 void DexWriter::WriteAnnotationsDirectories(Stream* stream) {
    420   uint32_t directory_buffer[4];
    421   uint32_t annotation_buffer[2];
    422   const uint32_t start = stream->Tell();
    423   for (auto& annotations_directory : header_->AnnotationsDirectoryItems()) {
    424     stream->AlignTo(SectionAlignment(DexFile::kDexTypeAnnotationsDirectoryItem));
    425     ProcessOffset(stream, annotations_directory.get());
    426     directory_buffer[0] = annotations_directory->GetClassAnnotation() == nullptr ? 0 :
    427         annotations_directory->GetClassAnnotation()->GetOffset();
    428     directory_buffer[1] = annotations_directory->GetFieldAnnotations() == nullptr ? 0 :
    429         annotations_directory->GetFieldAnnotations()->size();
    430     directory_buffer[2] = annotations_directory->GetMethodAnnotations() == nullptr ? 0 :
    431         annotations_directory->GetMethodAnnotations()->size();
    432     directory_buffer[3] = annotations_directory->GetParameterAnnotations() == nullptr ? 0 :
    433         annotations_directory->GetParameterAnnotations()->size();
    434     stream->Write(directory_buffer, 4 * sizeof(uint32_t));
    435     if (annotations_directory->GetFieldAnnotations() != nullptr) {
    436       for (std::unique_ptr<dex_ir::FieldAnnotation>& field :
    437           *annotations_directory->GetFieldAnnotations()) {
    438         annotation_buffer[0] = field->GetFieldId()->GetIndex();
    439         annotation_buffer[1] = field->GetAnnotationSetItem()->GetOffset();
    440         stream->Write(annotation_buffer, 2 * sizeof(uint32_t));
    441       }
    442     }
    443     if (annotations_directory->GetMethodAnnotations() != nullptr) {
    444       for (std::unique_ptr<dex_ir::MethodAnnotation>& method :
    445           *annotations_directory->GetMethodAnnotations()) {
    446         annotation_buffer[0] = method->GetMethodId()->GetIndex();
    447         annotation_buffer[1] = method->GetAnnotationSetItem()->GetOffset();
    448         stream->Write(annotation_buffer, 2 * sizeof(uint32_t));
    449       }
    450     }
    451     if (annotations_directory->GetParameterAnnotations() != nullptr) {
    452       for (std::unique_ptr<dex_ir::ParameterAnnotation>& parameter :
    453           *annotations_directory->GetParameterAnnotations()) {
    454         annotation_buffer[0] = parameter->GetMethodId()->GetIndex();
    455         annotation_buffer[1] = parameter->GetAnnotations()->GetOffset();
    456         stream->Write(annotation_buffer, 2 * sizeof(uint32_t));
    457       }
    458     }
    459   }
    460   if (compute_offsets_ && start != stream->Tell()) {
    461     header_->AnnotationsDirectoryItems().SetOffset(start);
    462   }
    463 }
    464 
    465 void DexWriter::WriteHiddenapiClassData(Stream* stream) {
    466   if (header_->HiddenapiClassDatas().Empty()) {
    467     return;
    468   }
    469   DCHECK_EQ(header_->HiddenapiClassDatas().Size(), header_->ClassDefs().Size());
    470 
    471   stream->AlignTo(SectionAlignment(DexFile::kDexTypeHiddenapiClassData));
    472   ProcessOffset(stream, &header_->HiddenapiClassDatas());
    473   const uint32_t start = stream->Tell();
    474 
    475   // Compute offsets for each class def and write the header.
    476   // data_header[0]: total size of the section
    477   // data_header[i + 1]: offset of class def[i] from the beginning of the section,
    478   //                     or zero if no data
    479   std::vector<uint32_t> data_header(header_->ClassDefs().Size() + 1, 0);
    480   data_header[0] = sizeof(uint32_t) * (header_->ClassDefs().Size() + 1);
    481   for (uint32_t i = 0; i < header_->ClassDefs().Size(); ++i) {
    482     uint32_t item_size = header_->HiddenapiClassDatas()[i]->ItemSize();
    483     data_header[i + 1] = item_size == 0u ? 0 : data_header[0];
    484     data_header[0] += item_size;
    485   }
    486   stream->Write(data_header.data(), sizeof(uint32_t) * data_header.size());
    487 
    488   // Write class data streams.
    489   for (uint32_t i = 0; i < header_->ClassDefs().Size(); ++i) {
    490     dex_ir::ClassDef* class_def = header_->ClassDefs()[i];
    491     const auto& item = header_->HiddenapiClassDatas()[i];
    492     DCHECK(item->GetClassDef() == class_def);
    493 
    494     if (data_header[i + 1] != 0u) {
    495       dex_ir::ClassData* class_data = class_def->GetClassData();
    496       DCHECK(class_data != nullptr);
    497       DCHECK_EQ(data_header[i + 1], stream->Tell() - start);
    498       for (const dex_ir::FieldItem& field : *class_data->StaticFields()) {
    499         stream->WriteUleb128(item->GetFlags(&field));
    500       }
    501       for (const dex_ir::FieldItem& field : *class_data->InstanceFields()) {
    502         stream->WriteUleb128(item->GetFlags(&field));
    503       }
    504       for (const dex_ir::MethodItem& method : *class_data->DirectMethods()) {
    505         stream->WriteUleb128(item->GetFlags(&method));
    506       }
    507       for (const dex_ir::MethodItem& method : *class_data->VirtualMethods()) {
    508         stream->WriteUleb128(item->GetFlags(&method));
    509       }
    510     }
    511   }
    512   DCHECK_EQ(stream->Tell() - start, data_header[0]);
    513 
    514   if (compute_offsets_ && start != stream->Tell()) {
    515     header_->HiddenapiClassDatas().SetOffset(start);
    516   }
    517 }
    518 
    519 void DexWriter::WriteDebugInfoItem(Stream* stream, dex_ir::DebugInfoItem* debug_info) {
    520   stream->AlignTo(SectionAlignment(DexFile::kDexTypeDebugInfoItem));
    521   ProcessOffset(stream, debug_info);
    522   stream->Write(debug_info->GetDebugInfo(), debug_info->GetDebugInfoSize());
    523 }
    524 
    525 void DexWriter::WriteDebugInfoItems(Stream* stream) {
    526   const uint32_t start = stream->Tell();
    527   for (auto& debug_info : header_->DebugInfoItems()) {
    528     WriteDebugInfoItem(stream, debug_info.get());
    529   }
    530   if (compute_offsets_ && start != stream->Tell()) {
    531     header_->DebugInfoItems().SetOffset(start);
    532   }
    533 }
    534 
    535 void DexWriter::WriteCodeItemPostInstructionData(Stream* stream,
    536                                                  dex_ir::CodeItem* code_item,
    537                                                  bool reserve_only) {
    538   if (code_item->TriesSize() != 0) {
    539     stream->AlignTo(dex::TryItem::kAlignment);
    540     // Write try items.
    541     for (std::unique_ptr<const dex_ir::TryItem>& try_item : *code_item->Tries()) {
    542       dex::TryItem disk_try_item;
    543       if (!reserve_only) {
    544         disk_try_item.start_addr_ = try_item->StartAddr();
    545         disk_try_item.insn_count_ = try_item->InsnCount();
    546         disk_try_item.handler_off_ = try_item->GetHandlers()->GetListOffset();
    547       }
    548       stream->Write(&disk_try_item, sizeof(disk_try_item));
    549     }
    550     // Leave offset pointing to the end of the try items.
    551     const size_t offset = stream->Tell();
    552     size_t max_offset = offset + stream->WriteUleb128(code_item->Handlers()->size());
    553     for (std::unique_ptr<const dex_ir::CatchHandler>& handlers : *code_item->Handlers()) {
    554       stream->Seek(offset + handlers->GetListOffset());
    555       uint32_t size = handlers->HasCatchAll() ? (handlers->GetHandlers()->size() - 1) * -1 :
    556           handlers->GetHandlers()->size();
    557       stream->WriteSleb128(size);
    558       for (std::unique_ptr<const dex_ir::TypeAddrPair>& handler : *handlers->GetHandlers()) {
    559         if (handler->GetTypeId() != nullptr) {
    560           stream->WriteUleb128(handler->GetTypeId()->GetIndex());
    561         }
    562         stream->WriteUleb128(handler->GetAddress());
    563       }
    564       // TODO: Clean this up to write the handlers in address order.
    565       max_offset = std::max(max_offset, stream->Tell());
    566     }
    567     stream->Seek(max_offset);
    568   }
    569 }
    570 
    571 void DexWriter::WriteCodeItem(Stream* stream,
    572                               dex_ir::CodeItem* code_item,
    573                               bool reserve_only) {
    574   DCHECK(code_item != nullptr);
    575   const uint32_t start_offset = stream->Tell();
    576   stream->AlignTo(SectionAlignment(DexFile::kDexTypeCodeItem));
    577   ProcessOffset(stream, code_item);
    578 
    579   StandardDexFile::CodeItem disk_code_item;
    580   if (!reserve_only) {
    581     disk_code_item.registers_size_ = code_item->RegistersSize();
    582     disk_code_item.ins_size_ = code_item->InsSize();
    583     disk_code_item.outs_size_ = code_item->OutsSize();
    584     disk_code_item.tries_size_ = code_item->TriesSize();
    585     disk_code_item.debug_info_off_ = code_item->DebugInfo() == nullptr
    586         ? 0
    587         : code_item->DebugInfo()->GetOffset();
    588     disk_code_item.insns_size_in_code_units_ = code_item->InsnsSize();
    589   }
    590   // Avoid using sizeof so that we don't write the fake instruction array at the end of the code
    591   // item.
    592   stream->Write(&disk_code_item, OFFSETOF_MEMBER(StandardDexFile::CodeItem, insns_));
    593   // Write the instructions.
    594   stream->Write(code_item->Insns(), code_item->InsnsSize() * sizeof(uint16_t));
    595   // Write the post instruction data.
    596   WriteCodeItemPostInstructionData(stream, code_item, reserve_only);
    597   if (reserve_only) {
    598     stream->Clear(start_offset, stream->Tell() - start_offset);
    599   }
    600 }
    601 
    602 void DexWriter::WriteCodeItems(Stream* stream, bool reserve_only) {
    603   DexLayoutSection* code_section = nullptr;
    604   if (!reserve_only && dex_layout_ != nullptr) {
    605     code_section = &dex_layout_->GetSections().sections_[static_cast<size_t>(
    606         DexLayoutSections::SectionType::kSectionTypeCode)];
    607   }
    608   const uint32_t start = stream->Tell();
    609   for (auto& code_item : header_->CodeItems()) {
    610     uint32_t start_offset = stream->Tell();
    611     WriteCodeItem(stream, code_item.get(), reserve_only);
    612     // Only add the section hotness info once.
    613     if (!reserve_only && code_section != nullptr) {
    614       auto it = dex_layout_->LayoutHotnessInfo().code_item_layout_.find(code_item.get());
    615       if (it != dex_layout_->LayoutHotnessInfo().code_item_layout_.end()) {
    616         code_section->parts_[static_cast<size_t>(it->second)].CombineSection(
    617             start_offset,
    618             stream->Tell());
    619       }
    620     }
    621   }
    622 
    623   if (compute_offsets_ && start != stream->Tell()) {
    624     header_->CodeItems().SetOffset(start);
    625   }
    626 }
    627 
    628 void DexWriter::WriteClassDefs(Stream* stream, bool reserve_only) {
    629   const uint32_t start = stream->Tell();
    630   uint32_t class_def_buffer[8];
    631   for (auto& class_def : header_->ClassDefs()) {
    632     stream->AlignTo(SectionAlignment(DexFile::kDexTypeClassDefItem));
    633     if (reserve_only) {
    634       stream->Skip(class_def->GetSize());
    635     } else {
    636       class_def_buffer[0] = class_def->ClassType()->GetIndex();
    637       class_def_buffer[1] = class_def->GetAccessFlags();
    638       class_def_buffer[2] = class_def->Superclass() == nullptr ? dex::kDexNoIndex :
    639           class_def->Superclass()->GetIndex();
    640       class_def_buffer[3] = class_def->InterfacesOffset();
    641       class_def_buffer[4] = class_def->SourceFile() == nullptr ? dex::kDexNoIndex :
    642           class_def->SourceFile()->GetIndex();
    643       class_def_buffer[5] = class_def->Annotations() == nullptr ? 0 :
    644           class_def->Annotations()->GetOffset();
    645       class_def_buffer[6] = class_def->GetClassData() == nullptr ? 0 :
    646           class_def->GetClassData()->GetOffset();
    647       class_def_buffer[7] = class_def->StaticValues() == nullptr ? 0 :
    648           class_def->StaticValues()->GetOffset();
    649       stream->Write(class_def_buffer, class_def->GetSize());
    650     }
    651   }
    652   if (compute_offsets_ && start != stream->Tell()) {
    653     header_->ClassDefs().SetOffset(start);
    654   }
    655 }
    656 
    657 void DexWriter::WriteClassDatas(Stream* stream) {
    658   const uint32_t start = stream->Tell();
    659   for (const std::unique_ptr<dex_ir::ClassData>& class_data :
    660       header_->ClassDatas()) {
    661     stream->AlignTo(SectionAlignment(DexFile::kDexTypeClassDataItem));
    662     ProcessOffset(stream, class_data.get());
    663     stream->WriteUleb128(class_data->StaticFields()->size());
    664     stream->WriteUleb128(class_data->InstanceFields()->size());
    665     stream->WriteUleb128(class_data->DirectMethods()->size());
    666     stream->WriteUleb128(class_data->VirtualMethods()->size());
    667     WriteEncodedFields(stream, class_data->StaticFields());
    668     WriteEncodedFields(stream, class_data->InstanceFields());
    669     WriteEncodedMethods(stream, class_data->DirectMethods());
    670     WriteEncodedMethods(stream, class_data->VirtualMethods());
    671   }
    672   if (compute_offsets_ && start != stream->Tell()) {
    673     header_->ClassDatas().SetOffset(start);
    674   }
    675 }
    676 
    677 void DexWriter::WriteCallSiteIds(Stream* stream, bool reserve_only) {
    678   const uint32_t start = stream->Tell();
    679   uint32_t call_site_off[1];
    680   for (auto& call_site_id : header_->CallSiteIds()) {
    681     stream->AlignTo(SectionAlignment(DexFile::kDexTypeCallSiteIdItem));
    682     if (reserve_only) {
    683       stream->Skip(call_site_id->GetSize());
    684     } else {
    685       call_site_off[0] = call_site_id->CallSiteItem()->GetOffset();
    686       stream->Write(call_site_off, call_site_id->GetSize());
    687     }
    688   }
    689   if (compute_offsets_ && start != stream->Tell()) {
    690     header_->CallSiteIds().SetOffset(start);
    691   }
    692 }
    693 
    694 void DexWriter::WriteMethodHandles(Stream* stream) {
    695   const uint32_t start = stream->Tell();
    696   uint16_t method_handle_buff[4];
    697   for (auto& method_handle : header_->MethodHandleItems()) {
    698     stream->AlignTo(SectionAlignment(DexFile::kDexTypeMethodHandleItem));
    699     method_handle_buff[0] = static_cast<uint16_t>(method_handle->GetMethodHandleType());
    700     method_handle_buff[1] = 0;  // unused.
    701     method_handle_buff[2] = method_handle->GetFieldOrMethodId()->GetIndex();
    702     method_handle_buff[3] = 0;  // unused.
    703     stream->Write(method_handle_buff, method_handle->GetSize());
    704   }
    705   if (compute_offsets_ && start != stream->Tell()) {
    706     header_->MethodHandleItems().SetOffset(start);
    707   }
    708 }
    709 
    710 void DexWriter::WriteMapItems(Stream* stream, MapItemQueue* queue) {
    711   // All the sections should already have been added.
    712   const uint32_t map_list_size = queue->size();
    713   stream->Write(&map_list_size, sizeof(map_list_size));
    714   while (!queue->empty()) {
    715     const MapItem& item = queue->top();
    716     dex::MapItem map_item;
    717     map_item.type_ = item.type_;
    718     map_item.size_ = item.size_;
    719     map_item.offset_ = item.offset_;
    720     map_item.unused_ = 0u;
    721     stream->Write(&map_item, sizeof(map_item));
    722     queue->pop();
    723   }
    724 }
    725 
    726 void DexWriter::GenerateAndWriteMapItems(Stream* stream) {
    727   MapItemQueue queue;
    728 
    729   // Header and index section.
    730   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeHeaderItem, 1, 0));
    731   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeStringIdItem,
    732                               header_->StringIds().Size(),
    733                               header_->StringIds().GetOffset()));
    734   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeTypeIdItem,
    735                               header_->TypeIds().Size(),
    736                               header_->TypeIds().GetOffset()));
    737   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeProtoIdItem,
    738                               header_->ProtoIds().Size(),
    739                               header_->ProtoIds().GetOffset()));
    740   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeFieldIdItem,
    741                               header_->FieldIds().Size(),
    742                               header_->FieldIds().GetOffset()));
    743   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeMethodIdItem,
    744                               header_->MethodIds().Size(),
    745                               header_->MethodIds().GetOffset()));
    746   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeClassDefItem,
    747                               header_->ClassDefs().Size(),
    748                               header_->ClassDefs().GetOffset()));
    749   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeCallSiteIdItem,
    750                               header_->CallSiteIds().Size(),
    751                               header_->CallSiteIds().GetOffset()));
    752   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeMethodHandleItem,
    753                               header_->MethodHandleItems().Size(),
    754                               header_->MethodHandleItems().GetOffset()));
    755   // Data section.
    756   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeMapList, 1, header_->MapListOffset()));
    757   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeTypeList,
    758                               header_->TypeLists().Size(),
    759                               header_->TypeLists().GetOffset()));
    760   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeAnnotationSetRefList,
    761                               header_->AnnotationSetRefLists().Size(),
    762                               header_->AnnotationSetRefLists().GetOffset()));
    763   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeAnnotationSetItem,
    764                               header_->AnnotationSetItems().Size(),
    765                               header_->AnnotationSetItems().GetOffset()));
    766   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeClassDataItem,
    767                               header_->ClassDatas().Size(),
    768                               header_->ClassDatas().GetOffset()));
    769   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeCodeItem,
    770                               header_->CodeItems().Size(),
    771                               header_->CodeItems().GetOffset()));
    772   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeStringDataItem,
    773                               header_->StringDatas().Size(),
    774                               header_->StringDatas().GetOffset()));
    775   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeDebugInfoItem,
    776                               header_->DebugInfoItems().Size(),
    777                               header_->DebugInfoItems().GetOffset()));
    778   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeAnnotationItem,
    779                               header_->AnnotationItems().Size(),
    780                               header_->AnnotationItems().GetOffset()));
    781   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeEncodedArrayItem,
    782                               header_->EncodedArrayItems().Size(),
    783                               header_->EncodedArrayItems().GetOffset()));
    784   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeAnnotationsDirectoryItem,
    785                               header_->AnnotationsDirectoryItems().Size(),
    786                               header_->AnnotationsDirectoryItems().GetOffset()));
    787   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeHiddenapiClassData,
    788                               header_->HiddenapiClassDatas().Empty() ? 0u : 1u,
    789                               header_->HiddenapiClassDatas().GetOffset()));
    790   WriteMapItems(stream, &queue);
    791 }
    792 
    793 void DexWriter::WriteHeader(Stream* stream) {
    794   StandardDexFile::Header header;
    795   if (CompactDexFile::IsMagicValid(header_->Magic())) {
    796     StandardDexFile::WriteMagic(header.magic_);
    797     // TODO: Should we write older versions based on the feature flags?
    798     StandardDexFile::WriteCurrentVersion(header.magic_);
    799   } else {
    800     // Standard dex -> standard dex, just reuse the same header.
    801     static constexpr size_t kMagicAndVersionLen =
    802         StandardDexFile::kDexMagicSize + StandardDexFile::kDexVersionLen;
    803     std::copy_n(header_->Magic(), kMagicAndVersionLen, header.magic_);
    804   }
    805   header.checksum_ = header_->Checksum();
    806   std::copy_n(header_->Signature(), DexFile::kSha1DigestSize, header.signature_);
    807   header.file_size_ = header_->FileSize();
    808   header.header_size_ = GetHeaderSize();
    809   header.endian_tag_ = header_->EndianTag();
    810   header.link_size_ = header_->LinkSize();
    811   header.link_off_ = header_->LinkOffset();
    812   header.map_off_ = header_->MapListOffset();
    813   header.string_ids_size_ = header_->StringIds().Size();
    814   header.string_ids_off_ = header_->StringIds().GetOffset();
    815   header.type_ids_size_ = header_->TypeIds().Size();
    816   header.type_ids_off_ = header_->TypeIds().GetOffset();
    817   header.proto_ids_size_ = header_->ProtoIds().Size();
    818   header.proto_ids_off_ = header_->ProtoIds().GetOffset();
    819   header.field_ids_size_ = header_->FieldIds().Size();
    820   header.field_ids_off_ = header_->FieldIds().GetOffset();
    821   header.method_ids_size_ = header_->MethodIds().Size();
    822   header.method_ids_off_ = header_->MethodIds().GetOffset();
    823   header.class_defs_size_ = header_->ClassDefs().Size();
    824   header.class_defs_off_ = header_->ClassDefs().GetOffset();
    825   header.data_size_ = header_->DataSize();
    826   header.data_off_ = header_->DataOffset();
    827 
    828   CHECK_EQ(sizeof(header), GetHeaderSize());
    829   static_assert(sizeof(header) == 0x70, "Size doesn't match dex spec");
    830   stream->Seek(0);
    831   stream->Overwrite(reinterpret_cast<uint8_t*>(&header), sizeof(header));
    832 }
    833 
    834 size_t DexWriter::GetHeaderSize() const {
    835   return sizeof(StandardDexFile::Header);
    836 }
    837 
    838 bool DexWriter::Write(DexContainer* output, std::string* error_msg) {
    839   DCHECK(error_msg != nullptr);
    840 
    841   Stream stream_storage(output->GetMainSection());
    842   Stream* stream = &stream_storage;
    843 
    844   // Starting offset is right after the header.
    845   stream->Seek(GetHeaderSize());
    846 
    847   // Based on: https://source.android.com/devices/tech/dalvik/dex-format
    848   // Since the offsets may not be calculated already, the writing must be done in the correct order.
    849   const uint32_t string_ids_offset = stream->Tell();
    850   WriteStringIds(stream, /*reserve_only=*/ true);
    851   WriteTypeIds(stream);
    852   const uint32_t proto_ids_offset = stream->Tell();
    853   WriteProtoIds(stream, /*reserve_only=*/ true);
    854   WriteFieldIds(stream);
    855   WriteMethodIds(stream);
    856   const uint32_t class_defs_offset = stream->Tell();
    857   WriteClassDefs(stream, /*reserve_only=*/ true);
    858   const uint32_t call_site_ids_offset = stream->Tell();
    859   WriteCallSiteIds(stream, /*reserve_only=*/ true);
    860   WriteMethodHandles(stream);
    861 
    862   uint32_t data_offset_ = 0u;
    863   if (compute_offsets_) {
    864     // Data section.
    865     stream->AlignTo(kDataSectionAlignment);
    866     data_offset_ = stream->Tell();
    867   }
    868 
    869   // Write code item first to minimize the space required for encoded methods.
    870   // Reserve code item space since we need the debug offsets to actually write them.
    871   const uint32_t code_items_offset = stream->Tell();
    872   WriteCodeItems(stream, /*reserve_only=*/ true);
    873   // Write debug info section.
    874   WriteDebugInfoItems(stream);
    875   {
    876     // Actually write code items since debug info offsets are calculated now.
    877     Stream::ScopedSeek seek(stream, code_items_offset);
    878     WriteCodeItems(stream, /*reserve_only=*/ false);
    879   }
    880 
    881   WriteEncodedArrays(stream);
    882   WriteAnnotations(stream);
    883   WriteAnnotationSets(stream);
    884   WriteAnnotationSetRefs(stream);
    885   WriteAnnotationsDirectories(stream);
    886   WriteTypeLists(stream);
    887   WriteClassDatas(stream);
    888   WriteStringDatas(stream);
    889   WriteHiddenapiClassData(stream);
    890 
    891   // Write delayed id sections that depend on data sections.
    892   {
    893     Stream::ScopedSeek seek(stream, string_ids_offset);
    894     WriteStringIds(stream, /*reserve_only=*/ false);
    895   }
    896   {
    897     Stream::ScopedSeek seek(stream, proto_ids_offset);
    898     WriteProtoIds(stream, /*reserve_only=*/ false);
    899   }
    900   {
    901     Stream::ScopedSeek seek(stream, class_defs_offset);
    902     WriteClassDefs(stream, /*reserve_only=*/ false);
    903   }
    904   {
    905     Stream::ScopedSeek seek(stream, call_site_ids_offset);
    906     WriteCallSiteIds(stream, /*reserve_only=*/ false);
    907   }
    908 
    909   // Write the map list.
    910   if (compute_offsets_) {
    911     stream->AlignTo(SectionAlignment(DexFile::kDexTypeMapList));
    912     header_->SetMapListOffset(stream->Tell());
    913   } else {
    914     stream->Seek(header_->MapListOffset());
    915   }
    916   GenerateAndWriteMapItems(stream);
    917   stream->AlignTo(kDataSectionAlignment);
    918 
    919   // Map items are included in the data section.
    920   if (compute_offsets_) {
    921     header_->SetDataSize(stream->Tell() - data_offset_);
    922     if (header_->DataSize() != 0) {
    923       // Offset must be zero when the size is zero.
    924       header_->SetDataOffset(data_offset_);
    925     } else {
    926       header_->SetDataOffset(0u);
    927     }
    928   }
    929 
    930   // Write link data if it exists.
    931   const std::vector<uint8_t>& link_data = header_->LinkData();
    932   if (link_data.size() > 0) {
    933     CHECK_EQ(header_->LinkSize(), static_cast<uint32_t>(link_data.size()));
    934     if (compute_offsets_) {
    935       header_->SetLinkOffset(stream->Tell());
    936     } else {
    937       stream->Seek(header_->LinkOffset());
    938     }
    939     stream->Write(&link_data[0], link_data.size());
    940   }
    941 
    942   // Write header last.
    943   if (compute_offsets_) {
    944     header_->SetFileSize(stream->Tell());
    945   }
    946   WriteHeader(stream);
    947 
    948   if (dex_layout_->GetOptions().update_checksum_) {
    949     header_->SetChecksum(DexFile::CalculateChecksum(stream->Begin(), header_->FileSize()));
    950     // Rewrite the header with the calculated checksum.
    951     WriteHeader(stream);
    952   }
    953 
    954   // Trim the map to make it sized as large as the dex file.
    955   output->GetMainSection()->Resize(header_->FileSize());
    956   return true;
    957 }
    958 
    959 bool DexWriter::Output(DexLayout* dex_layout,
    960                        std::unique_ptr<DexContainer>* container,
    961                        bool compute_offsets,
    962                        std::string* error_msg) {
    963   CHECK(dex_layout != nullptr);
    964   std::unique_ptr<DexWriter> writer;
    965   if (dex_layout->GetOptions().compact_dex_level_ != CompactDexLevel::kCompactDexLevelNone) {
    966     CHECK(compute_offsets) << "Compact dex requires computing offsets";
    967     writer.reset(new CompactDexWriter(dex_layout));
    968   } else {
    969     writer.reset(new DexWriter(dex_layout, compute_offsets));
    970   }
    971   DCHECK(container != nullptr);
    972   if (*container == nullptr) {
    973     *container = writer->CreateDexContainer();
    974   }
    975   return writer->Write(container->get(), error_msg);
    976 }
    977 
    978 void MapItemQueue::AddIfNotEmpty(const MapItem& item) {
    979   if (item.size_ != 0) {
    980     push(item);
    981   }
    982 }
    983 
    984 void DexWriter::ProcessOffset(Stream* stream, dex_ir::Item* item) {
    985   if (compute_offsets_) {
    986     item->SetOffset(stream->Tell());
    987   } else {
    988     // Not computing offsets, just use the one in the item.
    989     stream->Seek(item->GetOffset());
    990   }
    991 }
    992 
    993 void DexWriter::ProcessOffset(Stream* stream, dex_ir::CollectionBase* item) {
    994   if (compute_offsets_) {
    995     item->SetOffset(stream->Tell());
    996   } else {
    997     // Not computing offsets, just use the one in the item.
    998     stream->Seek(item->GetOffset());
    999   }
   1000 }
   1001 
   1002 std::unique_ptr<DexContainer> DexWriter::CreateDexContainer() const {
   1003   return std::unique_ptr<DexContainer>(new DexWriter::Container);
   1004 }
   1005 
   1006 }  // namespace art
   1007