You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1010 lines
38 KiB
1010 lines
38 KiB
/*
|
|
* Copyright (C) 2016 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "dex_writer.h"
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <vector>
|
|
|
|
#include "compact_dex_writer.h"
|
|
#include "dex/compact_dex_file.h"
|
|
#include "dex/dex_file_layout.h"
|
|
#include "dex/dex_file_types.h"
|
|
#include "dex/standard_dex_file.h"
|
|
#include "dex/utf.h"
|
|
#include "dexlayout.h"
|
|
|
|
namespace art {
|
|
|
|
constexpr uint32_t DexWriter::kDataSectionAlignment;
|
|
|
|
static size_t EncodeIntValue(int32_t value, uint8_t* buffer) {
|
|
size_t length = 0;
|
|
if (value >= 0) {
|
|
while (value > 0x7f) {
|
|
buffer[length++] = static_cast<uint8_t>(value);
|
|
value >>= 8;
|
|
}
|
|
} else {
|
|
while (value < -0x80) {
|
|
buffer[length++] = static_cast<uint8_t>(value);
|
|
value >>= 8;
|
|
}
|
|
}
|
|
buffer[length++] = static_cast<uint8_t>(value);
|
|
return length;
|
|
}
|
|
|
|
static size_t EncodeUIntValue(uint32_t value, uint8_t* buffer) {
|
|
size_t length = 0;
|
|
do {
|
|
buffer[length++] = static_cast<uint8_t>(value);
|
|
value >>= 8;
|
|
} while (value != 0);
|
|
return length;
|
|
}
|
|
|
|
static size_t EncodeLongValue(int64_t value, uint8_t* buffer) {
|
|
size_t length = 0;
|
|
if (value >= 0) {
|
|
while (value > 0x7f) {
|
|
buffer[length++] = static_cast<uint8_t>(value);
|
|
value >>= 8;
|
|
}
|
|
} else {
|
|
while (value < -0x80) {
|
|
buffer[length++] = static_cast<uint8_t>(value);
|
|
value >>= 8;
|
|
}
|
|
}
|
|
buffer[length++] = static_cast<uint8_t>(value);
|
|
return length;
|
|
}
|
|
|
|
union FloatUnion {
|
|
float f_;
|
|
uint32_t i_;
|
|
};
|
|
|
|
static size_t EncodeFloatValue(float value, uint8_t* buffer) {
|
|
FloatUnion float_union;
|
|
float_union.f_ = value;
|
|
uint32_t int_value = float_union.i_;
|
|
size_t index = 3;
|
|
do {
|
|
buffer[index--] = int_value >> 24;
|
|
int_value <<= 8;
|
|
} while (int_value != 0);
|
|
return 3 - index;
|
|
}
|
|
|
|
union DoubleUnion {
|
|
double d_;
|
|
uint64_t l_;
|
|
};
|
|
|
|
static size_t EncodeDoubleValue(double value, uint8_t* buffer) {
|
|
DoubleUnion double_union;
|
|
double_union.d_ = value;
|
|
uint64_t long_value = double_union.l_;
|
|
size_t index = 7;
|
|
do {
|
|
buffer[index--] = long_value >> 56;
|
|
long_value <<= 8;
|
|
} while (long_value != 0);
|
|
return 7 - index;
|
|
}
|
|
|
|
DexWriter::DexWriter(DexLayout* dex_layout, bool compute_offsets)
|
|
: header_(dex_layout->GetHeader()),
|
|
dex_layout_(dex_layout),
|
|
compute_offsets_(compute_offsets) {}
|
|
|
|
void DexWriter::WriteEncodedValue(Stream* stream, dex_ir::EncodedValue* encoded_value) {
|
|
size_t start = 0;
|
|
size_t length;
|
|
uint8_t buffer[8];
|
|
int8_t type = encoded_value->Type();
|
|
switch (type) {
|
|
case DexFile::kDexAnnotationByte:
|
|
length = EncodeIntValue(encoded_value->GetByte(), buffer);
|
|
break;
|
|
case DexFile::kDexAnnotationShort:
|
|
length = EncodeIntValue(encoded_value->GetShort(), buffer);
|
|
break;
|
|
case DexFile::kDexAnnotationChar:
|
|
length = EncodeUIntValue(encoded_value->GetChar(), buffer);
|
|
break;
|
|
case DexFile::kDexAnnotationInt:
|
|
length = EncodeIntValue(encoded_value->GetInt(), buffer);
|
|
break;
|
|
case DexFile::kDexAnnotationLong:
|
|
length = EncodeLongValue(encoded_value->GetLong(), buffer);
|
|
break;
|
|
case DexFile::kDexAnnotationFloat:
|
|
length = EncodeFloatValue(encoded_value->GetFloat(), buffer);
|
|
start = 4 - length;
|
|
break;
|
|
case DexFile::kDexAnnotationDouble:
|
|
length = EncodeDoubleValue(encoded_value->GetDouble(), buffer);
|
|
start = 8 - length;
|
|
break;
|
|
case DexFile::kDexAnnotationMethodType:
|
|
length = EncodeUIntValue(encoded_value->GetProtoId()->GetIndex(), buffer);
|
|
break;
|
|
case DexFile::kDexAnnotationMethodHandle:
|
|
length = EncodeUIntValue(encoded_value->GetMethodHandle()->GetIndex(), buffer);
|
|
break;
|
|
case DexFile::kDexAnnotationString:
|
|
length = EncodeUIntValue(encoded_value->GetStringId()->GetIndex(), buffer);
|
|
break;
|
|
case DexFile::kDexAnnotationType:
|
|
length = EncodeUIntValue(encoded_value->GetTypeId()->GetIndex(), buffer);
|
|
break;
|
|
case DexFile::kDexAnnotationField:
|
|
case DexFile::kDexAnnotationEnum:
|
|
length = EncodeUIntValue(encoded_value->GetFieldId()->GetIndex(), buffer);
|
|
break;
|
|
case DexFile::kDexAnnotationMethod:
|
|
length = EncodeUIntValue(encoded_value->GetMethodId()->GetIndex(), buffer);
|
|
break;
|
|
case DexFile::kDexAnnotationArray:
|
|
WriteEncodedValueHeader(stream, type, 0);
|
|
WriteEncodedArray(stream, encoded_value->GetEncodedArray()->GetEncodedValues());
|
|
return;
|
|
case DexFile::kDexAnnotationAnnotation:
|
|
WriteEncodedValueHeader(stream, type, 0);
|
|
WriteEncodedAnnotation(stream, encoded_value->GetEncodedAnnotation());
|
|
return;
|
|
case DexFile::kDexAnnotationNull:
|
|
WriteEncodedValueHeader(stream, type, 0);
|
|
return;
|
|
case DexFile::kDexAnnotationBoolean:
|
|
WriteEncodedValueHeader(stream, type, encoded_value->GetBoolean() ? 1 : 0);
|
|
return;
|
|
default:
|
|
return;
|
|
}
|
|
WriteEncodedValueHeader(stream, type, length - 1);
|
|
stream->Write(buffer + start, length);
|
|
}
|
|
|
|
void DexWriter::WriteEncodedValueHeader(Stream* stream, int8_t value_type, size_t value_arg) {
|
|
uint8_t buffer[1] = { static_cast<uint8_t>((value_arg << 5) | value_type) };
|
|
stream->Write(buffer, sizeof(uint8_t));
|
|
}
|
|
|
|
void DexWriter::WriteEncodedArray(Stream* stream, dex_ir::EncodedValueVector* values) {
|
|
stream->WriteUleb128(values->size());
|
|
for (std::unique_ptr<dex_ir::EncodedValue>& value : *values) {
|
|
WriteEncodedValue(stream, value.get());
|
|
}
|
|
}
|
|
|
|
void DexWriter::WriteEncodedAnnotation(Stream* stream, dex_ir::EncodedAnnotation* annotation) {
|
|
stream->WriteUleb128(annotation->GetType()->GetIndex());
|
|
stream->WriteUleb128(annotation->GetAnnotationElements()->size());
|
|
for (std::unique_ptr<dex_ir::AnnotationElement>& annotation_element :
|
|
*annotation->GetAnnotationElements()) {
|
|
stream->WriteUleb128(annotation_element->GetName()->GetIndex());
|
|
WriteEncodedValue(stream, annotation_element->GetValue());
|
|
}
|
|
}
|
|
|
|
void DexWriter::WriteEncodedFields(Stream* stream, dex_ir::FieldItemVector* fields) {
|
|
uint32_t prev_index = 0;
|
|
for (auto& field : *fields) {
|
|
uint32_t index = field.GetFieldId()->GetIndex();
|
|
stream->WriteUleb128(index - prev_index);
|
|
stream->WriteUleb128(field.GetAccessFlags());
|
|
prev_index = index;
|
|
}
|
|
}
|
|
|
|
void DexWriter::WriteEncodedMethods(Stream* stream, dex_ir::MethodItemVector* methods) {
|
|
uint32_t prev_index = 0;
|
|
for (auto& method : *methods) {
|
|
uint32_t index = method.GetMethodId()->GetIndex();
|
|
uint32_t code_off = method.GetCodeItem() == nullptr ? 0 : method.GetCodeItem()->GetOffset();
|
|
stream->WriteUleb128(index - prev_index);
|
|
stream->WriteUleb128(method.GetAccessFlags());
|
|
stream->WriteUleb128(code_off);
|
|
prev_index = index;
|
|
}
|
|
}
|
|
|
|
// TODO: Refactor this to remove duplicated boiler plate. One way to do this is adding
|
|
// function that takes a CollectionVector<T> and uses overloading.
|
|
void DexWriter::WriteStringIds(Stream* stream, bool reserve_only) {
|
|
const uint32_t start = stream->Tell();
|
|
for (auto& string_id : header_->StringIds()) {
|
|
stream->AlignTo(SectionAlignment(DexFile::kDexTypeStringIdItem));
|
|
if (reserve_only) {
|
|
stream->Skip(string_id->GetSize());
|
|
} else {
|
|
uint32_t string_data_off = string_id->DataItem()->GetOffset();
|
|
stream->Write(&string_data_off, string_id->GetSize());
|
|
}
|
|
}
|
|
if (compute_offsets_ && start != stream->Tell()) {
|
|
header_->StringIds().SetOffset(start);
|
|
}
|
|
}
|
|
|
|
void DexWriter::WriteStringData(Stream* stream, dex_ir::StringData* string_data) {
|
|
ProcessOffset(stream, string_data);
|
|
stream->AlignTo(SectionAlignment(DexFile::kDexTypeStringDataItem));
|
|
stream->WriteUleb128(CountModifiedUtf8Chars(string_data->Data()));
|
|
stream->Write(string_data->Data(), strlen(string_data->Data()));
|
|
// Skip null terminator (already zeroed out, no need to write).
|
|
stream->Skip(1);
|
|
}
|
|
|
|
void DexWriter::WriteStringDatas(Stream* stream) {
|
|
const uint32_t start = stream->Tell();
|
|
for (auto& string_data : header_->StringDatas()) {
|
|
WriteStringData(stream, string_data.get());
|
|
}
|
|
if (compute_offsets_ && start != stream->Tell()) {
|
|
header_->StringDatas().SetOffset(start);
|
|
}
|
|
}
|
|
|
|
void DexWriter::WriteTypeIds(Stream* stream) {
|
|
uint32_t descriptor_idx[1];
|
|
const uint32_t start = stream->Tell();
|
|
for (auto& type_id : header_->TypeIds()) {
|
|
stream->AlignTo(SectionAlignment(DexFile::kDexTypeTypeIdItem));
|
|
ProcessOffset(stream, type_id.get());
|
|
descriptor_idx[0] = type_id->GetStringId()->GetIndex();
|
|
stream->Write(descriptor_idx, type_id->GetSize());
|
|
}
|
|
if (compute_offsets_ && start != stream->Tell()) {
|
|
header_->TypeIds().SetOffset(start);
|
|
}
|
|
}
|
|
|
|
void DexWriter::WriteTypeLists(Stream* stream) {
|
|
uint32_t size[1];
|
|
uint16_t list[1];
|
|
const uint32_t start = stream->Tell();
|
|
for (auto& type_list : header_->TypeLists()) {
|
|
stream->AlignTo(SectionAlignment(DexFile::kDexTypeTypeList));
|
|
size[0] = type_list->GetTypeList()->size();
|
|
ProcessOffset(stream, type_list.get());
|
|
stream->Write(size, sizeof(uint32_t));
|
|
for (const dex_ir::TypeId* type_id : *type_list->GetTypeList()) {
|
|
list[0] = type_id->GetIndex();
|
|
stream->Write(list, sizeof(uint16_t));
|
|
}
|
|
}
|
|
if (compute_offsets_ && start != stream->Tell()) {
|
|
header_->TypeLists().SetOffset(start);
|
|
}
|
|
}
|
|
|
|
void DexWriter::WriteProtoIds(Stream* stream, bool reserve_only) {
|
|
uint32_t buffer[3];
|
|
const uint32_t start = stream->Tell();
|
|
for (auto& proto_id : header_->ProtoIds()) {
|
|
stream->AlignTo(SectionAlignment(DexFile::kDexTypeProtoIdItem));
|
|
ProcessOffset(stream, proto_id.get());
|
|
if (reserve_only) {
|
|
stream->Skip(proto_id->GetSize());
|
|
} else {
|
|
buffer[0] = proto_id->Shorty()->GetIndex();
|
|
buffer[1] = proto_id->ReturnType()->GetIndex();
|
|
buffer[2] = proto_id->Parameters() == nullptr ? 0 : proto_id->Parameters()->GetOffset();
|
|
stream->Write(buffer, proto_id->GetSize());
|
|
}
|
|
}
|
|
if (compute_offsets_ && start != stream->Tell()) {
|
|
header_->ProtoIds().SetOffset(start);
|
|
}
|
|
}
|
|
|
|
void DexWriter::WriteFieldIds(Stream* stream) {
|
|
uint16_t buffer[4];
|
|
const uint32_t start = stream->Tell();
|
|
for (auto& field_id : header_->FieldIds()) {
|
|
stream->AlignTo(SectionAlignment(DexFile::kDexTypeFieldIdItem));
|
|
ProcessOffset(stream, field_id.get());
|
|
buffer[0] = field_id->Class()->GetIndex();
|
|
buffer[1] = field_id->Type()->GetIndex();
|
|
buffer[2] = field_id->Name()->GetIndex();
|
|
buffer[3] = field_id->Name()->GetIndex() >> 16;
|
|
stream->Write(buffer, field_id->GetSize());
|
|
}
|
|
if (compute_offsets_ && start != stream->Tell()) {
|
|
header_->FieldIds().SetOffset(start);
|
|
}
|
|
}
|
|
|
|
void DexWriter::WriteMethodIds(Stream* stream) {
|
|
uint16_t buffer[4];
|
|
const uint32_t start = stream->Tell();
|
|
for (auto& method_id : header_->MethodIds()) {
|
|
stream->AlignTo(SectionAlignment(DexFile::kDexTypeMethodIdItem));
|
|
ProcessOffset(stream, method_id.get());
|
|
buffer[0] = method_id->Class()->GetIndex();
|
|
buffer[1] = method_id->Proto()->GetIndex();
|
|
buffer[2] = method_id->Name()->GetIndex();
|
|
buffer[3] = method_id->Name()->GetIndex() >> 16;
|
|
stream->Write(buffer, method_id->GetSize());
|
|
}
|
|
if (compute_offsets_ && start != stream->Tell()) {
|
|
header_->MethodIds().SetOffset(start);
|
|
}
|
|
}
|
|
|
|
void DexWriter::WriteEncodedArrays(Stream* stream) {
|
|
const uint32_t start = stream->Tell();
|
|
for (auto& encoded_array : header_->EncodedArrayItems()) {
|
|
stream->AlignTo(SectionAlignment(DexFile::kDexTypeEncodedArrayItem));
|
|
ProcessOffset(stream, encoded_array.get());
|
|
WriteEncodedArray(stream, encoded_array->GetEncodedValues());
|
|
}
|
|
if (compute_offsets_ && start != stream->Tell()) {
|
|
header_->EncodedArrayItems().SetOffset(start);
|
|
}
|
|
}
|
|
|
|
void DexWriter::WriteAnnotations(Stream* stream) {
|
|
uint8_t visibility[1];
|
|
const uint32_t start = stream->Tell();
|
|
for (auto& annotation : header_->AnnotationItems()) {
|
|
stream->AlignTo(SectionAlignment(DexFile::kDexTypeAnnotationItem));
|
|
visibility[0] = annotation->GetVisibility();
|
|
ProcessOffset(stream, annotation.get());
|
|
stream->Write(visibility, sizeof(uint8_t));
|
|
WriteEncodedAnnotation(stream, annotation->GetAnnotation());
|
|
}
|
|
if (compute_offsets_ && start != stream->Tell()) {
|
|
header_->AnnotationItems().SetOffset(start);
|
|
}
|
|
}
|
|
|
|
void DexWriter::WriteAnnotationSets(Stream* stream) {
|
|
uint32_t size[1];
|
|
uint32_t annotation_off[1];
|
|
const uint32_t start = stream->Tell();
|
|
for (auto& annotation_set : header_->AnnotationSetItems()) {
|
|
stream->AlignTo(SectionAlignment(DexFile::kDexTypeAnnotationSetItem));
|
|
size[0] = annotation_set->GetItems()->size();
|
|
ProcessOffset(stream, annotation_set.get());
|
|
stream->Write(size, sizeof(uint32_t));
|
|
for (dex_ir::AnnotationItem* annotation : *annotation_set->GetItems()) {
|
|
annotation_off[0] = annotation->GetOffset();
|
|
stream->Write(annotation_off, sizeof(uint32_t));
|
|
}
|
|
}
|
|
if (compute_offsets_ && start != stream->Tell()) {
|
|
header_->AnnotationSetItems().SetOffset(start);
|
|
}
|
|
}
|
|
|
|
void DexWriter::WriteAnnotationSetRefs(Stream* stream) {
|
|
uint32_t size[1];
|
|
uint32_t annotations_off[1];
|
|
const uint32_t start = stream->Tell();
|
|
for (auto& annotation_set_ref : header_->AnnotationSetRefLists()) {
|
|
stream->AlignTo(SectionAlignment(DexFile::kDexTypeAnnotationSetRefList));
|
|
size[0] = annotation_set_ref->GetItems()->size();
|
|
ProcessOffset(stream, annotation_set_ref.get());
|
|
stream->Write(size, sizeof(uint32_t));
|
|
for (dex_ir::AnnotationSetItem* annotation_set : *annotation_set_ref->GetItems()) {
|
|
annotations_off[0] = annotation_set == nullptr ? 0 : annotation_set->GetOffset();
|
|
stream->Write(annotations_off, sizeof(uint32_t));
|
|
}
|
|
}
|
|
if (compute_offsets_ && start != stream->Tell()) {
|
|
header_->AnnotationSetRefLists().SetOffset(start);
|
|
}
|
|
}
|
|
|
|
void DexWriter::WriteAnnotationsDirectories(Stream* stream) {
|
|
uint32_t directory_buffer[4];
|
|
uint32_t annotation_buffer[2];
|
|
const uint32_t start = stream->Tell();
|
|
for (auto& annotations_directory : header_->AnnotationsDirectoryItems()) {
|
|
stream->AlignTo(SectionAlignment(DexFile::kDexTypeAnnotationsDirectoryItem));
|
|
ProcessOffset(stream, annotations_directory.get());
|
|
directory_buffer[0] = annotations_directory->GetClassAnnotation() == nullptr ? 0 :
|
|
annotations_directory->GetClassAnnotation()->GetOffset();
|
|
directory_buffer[1] = annotations_directory->GetFieldAnnotations() == nullptr ? 0 :
|
|
annotations_directory->GetFieldAnnotations()->size();
|
|
directory_buffer[2] = annotations_directory->GetMethodAnnotations() == nullptr ? 0 :
|
|
annotations_directory->GetMethodAnnotations()->size();
|
|
directory_buffer[3] = annotations_directory->GetParameterAnnotations() == nullptr ? 0 :
|
|
annotations_directory->GetParameterAnnotations()->size();
|
|
stream->Write(directory_buffer, 4 * sizeof(uint32_t));
|
|
if (annotations_directory->GetFieldAnnotations() != nullptr) {
|
|
for (std::unique_ptr<dex_ir::FieldAnnotation>& field :
|
|
*annotations_directory->GetFieldAnnotations()) {
|
|
annotation_buffer[0] = field->GetFieldId()->GetIndex();
|
|
annotation_buffer[1] = field->GetAnnotationSetItem()->GetOffset();
|
|
stream->Write(annotation_buffer, 2 * sizeof(uint32_t));
|
|
}
|
|
}
|
|
if (annotations_directory->GetMethodAnnotations() != nullptr) {
|
|
for (std::unique_ptr<dex_ir::MethodAnnotation>& method :
|
|
*annotations_directory->GetMethodAnnotations()) {
|
|
annotation_buffer[0] = method->GetMethodId()->GetIndex();
|
|
annotation_buffer[1] = method->GetAnnotationSetItem()->GetOffset();
|
|
stream->Write(annotation_buffer, 2 * sizeof(uint32_t));
|
|
}
|
|
}
|
|
if (annotations_directory->GetParameterAnnotations() != nullptr) {
|
|
for (std::unique_ptr<dex_ir::ParameterAnnotation>& parameter :
|
|
*annotations_directory->GetParameterAnnotations()) {
|
|
annotation_buffer[0] = parameter->GetMethodId()->GetIndex();
|
|
annotation_buffer[1] = parameter->GetAnnotations()->GetOffset();
|
|
stream->Write(annotation_buffer, 2 * sizeof(uint32_t));
|
|
}
|
|
}
|
|
}
|
|
if (compute_offsets_ && start != stream->Tell()) {
|
|
header_->AnnotationsDirectoryItems().SetOffset(start);
|
|
}
|
|
}
|
|
|
|
void DexWriter::WriteHiddenapiClassData(Stream* stream) {
|
|
if (header_->HiddenapiClassDatas().Empty()) {
|
|
return;
|
|
}
|
|
DCHECK_EQ(header_->HiddenapiClassDatas().Size(), header_->ClassDefs().Size());
|
|
|
|
stream->AlignTo(SectionAlignment(DexFile::kDexTypeHiddenapiClassData));
|
|
ProcessOffset(stream, &header_->HiddenapiClassDatas());
|
|
const uint32_t start = stream->Tell();
|
|
|
|
// Compute offsets for each class def and write the header.
|
|
// data_header[0]: total size of the section
|
|
// data_header[i + 1]: offset of class def[i] from the beginning of the section,
|
|
// or zero if no data
|
|
std::vector<uint32_t> data_header(header_->ClassDefs().Size() + 1, 0);
|
|
data_header[0] = sizeof(uint32_t) * (header_->ClassDefs().Size() + 1);
|
|
for (uint32_t i = 0; i < header_->ClassDefs().Size(); ++i) {
|
|
uint32_t item_size = header_->HiddenapiClassDatas()[i]->ItemSize();
|
|
data_header[i + 1] = item_size == 0u ? 0 : data_header[0];
|
|
data_header[0] += item_size;
|
|
}
|
|
stream->Write(data_header.data(), sizeof(uint32_t) * data_header.size());
|
|
|
|
// Write class data streams.
|
|
for (uint32_t i = 0; i < header_->ClassDefs().Size(); ++i) {
|
|
dex_ir::ClassDef* class_def = header_->ClassDefs()[i];
|
|
const auto& item = header_->HiddenapiClassDatas()[i];
|
|
DCHECK(item->GetClassDef() == class_def);
|
|
|
|
if (data_header[i + 1] != 0u) {
|
|
dex_ir::ClassData* class_data = class_def->GetClassData();
|
|
DCHECK(class_data != nullptr);
|
|
DCHECK_EQ(data_header[i + 1], stream->Tell() - start);
|
|
for (const dex_ir::FieldItem& field : *class_data->StaticFields()) {
|
|
stream->WriteUleb128(item->GetFlags(&field));
|
|
}
|
|
for (const dex_ir::FieldItem& field : *class_data->InstanceFields()) {
|
|
stream->WriteUleb128(item->GetFlags(&field));
|
|
}
|
|
for (const dex_ir::MethodItem& method : *class_data->DirectMethods()) {
|
|
stream->WriteUleb128(item->GetFlags(&method));
|
|
}
|
|
for (const dex_ir::MethodItem& method : *class_data->VirtualMethods()) {
|
|
stream->WriteUleb128(item->GetFlags(&method));
|
|
}
|
|
}
|
|
}
|
|
DCHECK_EQ(stream->Tell() - start, data_header[0]);
|
|
|
|
if (compute_offsets_ && start != stream->Tell()) {
|
|
header_->HiddenapiClassDatas().SetOffset(start);
|
|
}
|
|
}
|
|
|
|
void DexWriter::WriteDebugInfoItem(Stream* stream, dex_ir::DebugInfoItem* debug_info) {
|
|
stream->AlignTo(SectionAlignment(DexFile::kDexTypeDebugInfoItem));
|
|
ProcessOffset(stream, debug_info);
|
|
stream->Write(debug_info->GetDebugInfo(), debug_info->GetDebugInfoSize());
|
|
}
|
|
|
|
void DexWriter::WriteDebugInfoItems(Stream* stream) {
|
|
const uint32_t start = stream->Tell();
|
|
for (auto& debug_info : header_->DebugInfoItems()) {
|
|
WriteDebugInfoItem(stream, debug_info.get());
|
|
}
|
|
if (compute_offsets_ && start != stream->Tell()) {
|
|
header_->DebugInfoItems().SetOffset(start);
|
|
}
|
|
}
|
|
|
|
void DexWriter::WriteCodeItemPostInstructionData(Stream* stream,
|
|
dex_ir::CodeItem* code_item,
|
|
bool reserve_only) {
|
|
if (code_item->TriesSize() != 0) {
|
|
stream->AlignTo(dex::TryItem::kAlignment);
|
|
// Write try items.
|
|
for (std::unique_ptr<const dex_ir::TryItem>& try_item : *code_item->Tries()) {
|
|
dex::TryItem disk_try_item;
|
|
if (!reserve_only) {
|
|
disk_try_item.start_addr_ = try_item->StartAddr();
|
|
disk_try_item.insn_count_ = try_item->InsnCount();
|
|
disk_try_item.handler_off_ = try_item->GetHandlers()->GetListOffset();
|
|
}
|
|
stream->Write(&disk_try_item, sizeof(disk_try_item));
|
|
}
|
|
// Leave offset pointing to the end of the try items.
|
|
const size_t offset = stream->Tell();
|
|
size_t max_offset = offset + stream->WriteUleb128(code_item->Handlers()->size());
|
|
for (std::unique_ptr<const dex_ir::CatchHandler>& handlers : *code_item->Handlers()) {
|
|
stream->Seek(offset + handlers->GetListOffset());
|
|
uint32_t size = handlers->HasCatchAll() ? (handlers->GetHandlers()->size() - 1) * -1 :
|
|
handlers->GetHandlers()->size();
|
|
stream->WriteSleb128(size);
|
|
for (std::unique_ptr<const dex_ir::TypeAddrPair>& handler : *handlers->GetHandlers()) {
|
|
if (handler->GetTypeId() != nullptr) {
|
|
stream->WriteUleb128(handler->GetTypeId()->GetIndex());
|
|
}
|
|
stream->WriteUleb128(handler->GetAddress());
|
|
}
|
|
// TODO: Clean this up to write the handlers in address order.
|
|
max_offset = std::max(max_offset, stream->Tell());
|
|
}
|
|
stream->Seek(max_offset);
|
|
}
|
|
}
|
|
|
|
void DexWriter::WriteCodeItem(Stream* stream,
|
|
dex_ir::CodeItem* code_item,
|
|
bool reserve_only) {
|
|
DCHECK(code_item != nullptr);
|
|
const uint32_t start_offset = stream->Tell();
|
|
stream->AlignTo(SectionAlignment(DexFile::kDexTypeCodeItem));
|
|
ProcessOffset(stream, code_item);
|
|
|
|
StandardDexFile::CodeItem disk_code_item;
|
|
if (!reserve_only) {
|
|
disk_code_item.registers_size_ = code_item->RegistersSize();
|
|
disk_code_item.ins_size_ = code_item->InsSize();
|
|
disk_code_item.outs_size_ = code_item->OutsSize();
|
|
disk_code_item.tries_size_ = code_item->TriesSize();
|
|
disk_code_item.debug_info_off_ = code_item->DebugInfo() == nullptr
|
|
? 0
|
|
: code_item->DebugInfo()->GetOffset();
|
|
disk_code_item.insns_size_in_code_units_ = code_item->InsnsSize();
|
|
}
|
|
// Avoid using sizeof so that we don't write the fake instruction array at the end of the code
|
|
// item.
|
|
stream->Write(&disk_code_item, OFFSETOF_MEMBER(StandardDexFile::CodeItem, insns_));
|
|
// Write the instructions.
|
|
stream->Write(code_item->Insns(), code_item->InsnsSize() * sizeof(uint16_t));
|
|
// Write the post instruction data.
|
|
WriteCodeItemPostInstructionData(stream, code_item, reserve_only);
|
|
if (reserve_only) {
|
|
stream->Clear(start_offset, stream->Tell() - start_offset);
|
|
}
|
|
}
|
|
|
|
void DexWriter::WriteCodeItems(Stream* stream, bool reserve_only) {
|
|
DexLayoutSection* code_section = nullptr;
|
|
if (!reserve_only && dex_layout_ != nullptr) {
|
|
code_section = &dex_layout_->GetSections().sections_[static_cast<size_t>(
|
|
DexLayoutSections::SectionType::kSectionTypeCode)];
|
|
}
|
|
const uint32_t start = stream->Tell();
|
|
for (auto& code_item : header_->CodeItems()) {
|
|
uint32_t start_offset = stream->Tell();
|
|
WriteCodeItem(stream, code_item.get(), reserve_only);
|
|
// Only add the section hotness info once.
|
|
if (!reserve_only && code_section != nullptr) {
|
|
auto it = dex_layout_->LayoutHotnessInfo().code_item_layout_.find(code_item.get());
|
|
if (it != dex_layout_->LayoutHotnessInfo().code_item_layout_.end()) {
|
|
code_section->parts_[static_cast<size_t>(it->second)].CombineSection(
|
|
start_offset,
|
|
stream->Tell());
|
|
}
|
|
}
|
|
}
|
|
|
|
if (compute_offsets_ && start != stream->Tell()) {
|
|
header_->CodeItems().SetOffset(start);
|
|
}
|
|
}
|
|
|
|
void DexWriter::WriteClassDefs(Stream* stream, bool reserve_only) {
|
|
const uint32_t start = stream->Tell();
|
|
uint32_t class_def_buffer[8];
|
|
for (auto& class_def : header_->ClassDefs()) {
|
|
stream->AlignTo(SectionAlignment(DexFile::kDexTypeClassDefItem));
|
|
if (reserve_only) {
|
|
stream->Skip(class_def->GetSize());
|
|
} else {
|
|
class_def_buffer[0] = class_def->ClassType()->GetIndex();
|
|
class_def_buffer[1] = class_def->GetAccessFlags();
|
|
class_def_buffer[2] = class_def->Superclass() == nullptr ? dex::kDexNoIndex :
|
|
class_def->Superclass()->GetIndex();
|
|
class_def_buffer[3] = class_def->InterfacesOffset();
|
|
class_def_buffer[4] = class_def->SourceFile() == nullptr ? dex::kDexNoIndex :
|
|
class_def->SourceFile()->GetIndex();
|
|
class_def_buffer[5] = class_def->Annotations() == nullptr ? 0 :
|
|
class_def->Annotations()->GetOffset();
|
|
class_def_buffer[6] = class_def->GetClassData() == nullptr ? 0 :
|
|
class_def->GetClassData()->GetOffset();
|
|
class_def_buffer[7] = class_def->StaticValues() == nullptr ? 0 :
|
|
class_def->StaticValues()->GetOffset();
|
|
stream->Write(class_def_buffer, class_def->GetSize());
|
|
}
|
|
}
|
|
if (compute_offsets_ && start != stream->Tell()) {
|
|
header_->ClassDefs().SetOffset(start);
|
|
}
|
|
}
|
|
|
|
void DexWriter::WriteClassDatas(Stream* stream) {
|
|
const uint32_t start = stream->Tell();
|
|
for (const std::unique_ptr<dex_ir::ClassData>& class_data :
|
|
header_->ClassDatas()) {
|
|
stream->AlignTo(SectionAlignment(DexFile::kDexTypeClassDataItem));
|
|
ProcessOffset(stream, class_data.get());
|
|
stream->WriteUleb128(class_data->StaticFields()->size());
|
|
stream->WriteUleb128(class_data->InstanceFields()->size());
|
|
stream->WriteUleb128(class_data->DirectMethods()->size());
|
|
stream->WriteUleb128(class_data->VirtualMethods()->size());
|
|
WriteEncodedFields(stream, class_data->StaticFields());
|
|
WriteEncodedFields(stream, class_data->InstanceFields());
|
|
WriteEncodedMethods(stream, class_data->DirectMethods());
|
|
WriteEncodedMethods(stream, class_data->VirtualMethods());
|
|
}
|
|
if (compute_offsets_ && start != stream->Tell()) {
|
|
header_->ClassDatas().SetOffset(start);
|
|
}
|
|
}
|
|
|
|
void DexWriter::WriteCallSiteIds(Stream* stream, bool reserve_only) {
|
|
const uint32_t start = stream->Tell();
|
|
uint32_t call_site_off[1];
|
|
for (auto& call_site_id : header_->CallSiteIds()) {
|
|
stream->AlignTo(SectionAlignment(DexFile::kDexTypeCallSiteIdItem));
|
|
if (reserve_only) {
|
|
stream->Skip(call_site_id->GetSize());
|
|
} else {
|
|
call_site_off[0] = call_site_id->CallSiteItem()->GetOffset();
|
|
stream->Write(call_site_off, call_site_id->GetSize());
|
|
}
|
|
}
|
|
if (compute_offsets_ && start != stream->Tell()) {
|
|
header_->CallSiteIds().SetOffset(start);
|
|
}
|
|
}
|
|
|
|
void DexWriter::WriteMethodHandles(Stream* stream) {
|
|
const uint32_t start = stream->Tell();
|
|
uint16_t method_handle_buff[4];
|
|
for (auto& method_handle : header_->MethodHandleItems()) {
|
|
stream->AlignTo(SectionAlignment(DexFile::kDexTypeMethodHandleItem));
|
|
method_handle_buff[0] = static_cast<uint16_t>(method_handle->GetMethodHandleType());
|
|
method_handle_buff[1] = 0; // unused.
|
|
method_handle_buff[2] = method_handle->GetFieldOrMethodId()->GetIndex();
|
|
method_handle_buff[3] = 0; // unused.
|
|
stream->Write(method_handle_buff, method_handle->GetSize());
|
|
}
|
|
if (compute_offsets_ && start != stream->Tell()) {
|
|
header_->MethodHandleItems().SetOffset(start);
|
|
}
|
|
}
|
|
|
|
void DexWriter::WriteMapItems(Stream* stream, MapItemQueue* queue) {
|
|
// All the sections should already have been added.
|
|
const uint32_t map_list_size = queue->size();
|
|
stream->Write(&map_list_size, sizeof(map_list_size));
|
|
while (!queue->empty()) {
|
|
const MapItem& item = queue->top();
|
|
dex::MapItem map_item;
|
|
map_item.type_ = item.type_;
|
|
map_item.size_ = item.size_;
|
|
map_item.offset_ = item.offset_;
|
|
map_item.unused_ = 0u;
|
|
stream->Write(&map_item, sizeof(map_item));
|
|
queue->pop();
|
|
}
|
|
}
|
|
|
|
void DexWriter::GenerateAndWriteMapItems(Stream* stream) {
|
|
MapItemQueue queue;
|
|
|
|
// Header and index section.
|
|
queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeHeaderItem, 1, 0));
|
|
queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeStringIdItem,
|
|
header_->StringIds().Size(),
|
|
header_->StringIds().GetOffset()));
|
|
queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeTypeIdItem,
|
|
header_->TypeIds().Size(),
|
|
header_->TypeIds().GetOffset()));
|
|
queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeProtoIdItem,
|
|
header_->ProtoIds().Size(),
|
|
header_->ProtoIds().GetOffset()));
|
|
queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeFieldIdItem,
|
|
header_->FieldIds().Size(),
|
|
header_->FieldIds().GetOffset()));
|
|
queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeMethodIdItem,
|
|
header_->MethodIds().Size(),
|
|
header_->MethodIds().GetOffset()));
|
|
queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeClassDefItem,
|
|
header_->ClassDefs().Size(),
|
|
header_->ClassDefs().GetOffset()));
|
|
queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeCallSiteIdItem,
|
|
header_->CallSiteIds().Size(),
|
|
header_->CallSiteIds().GetOffset()));
|
|
queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeMethodHandleItem,
|
|
header_->MethodHandleItems().Size(),
|
|
header_->MethodHandleItems().GetOffset()));
|
|
// Data section.
|
|
queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeMapList, 1, header_->MapListOffset()));
|
|
queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeTypeList,
|
|
header_->TypeLists().Size(),
|
|
header_->TypeLists().GetOffset()));
|
|
queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeAnnotationSetRefList,
|
|
header_->AnnotationSetRefLists().Size(),
|
|
header_->AnnotationSetRefLists().GetOffset()));
|
|
queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeAnnotationSetItem,
|
|
header_->AnnotationSetItems().Size(),
|
|
header_->AnnotationSetItems().GetOffset()));
|
|
queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeClassDataItem,
|
|
header_->ClassDatas().Size(),
|
|
header_->ClassDatas().GetOffset()));
|
|
queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeCodeItem,
|
|
header_->CodeItems().Size(),
|
|
header_->CodeItems().GetOffset()));
|
|
queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeStringDataItem,
|
|
header_->StringDatas().Size(),
|
|
header_->StringDatas().GetOffset()));
|
|
queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeDebugInfoItem,
|
|
header_->DebugInfoItems().Size(),
|
|
header_->DebugInfoItems().GetOffset()));
|
|
queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeAnnotationItem,
|
|
header_->AnnotationItems().Size(),
|
|
header_->AnnotationItems().GetOffset()));
|
|
queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeEncodedArrayItem,
|
|
header_->EncodedArrayItems().Size(),
|
|
header_->EncodedArrayItems().GetOffset()));
|
|
queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeAnnotationsDirectoryItem,
|
|
header_->AnnotationsDirectoryItems().Size(),
|
|
header_->AnnotationsDirectoryItems().GetOffset()));
|
|
queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeHiddenapiClassData,
|
|
header_->HiddenapiClassDatas().Empty() ? 0u : 1u,
|
|
header_->HiddenapiClassDatas().GetOffset()));
|
|
WriteMapItems(stream, &queue);
|
|
}
|
|
|
|
void DexWriter::WriteHeader(Stream* stream) {
|
|
StandardDexFile::Header header;
|
|
if (CompactDexFile::IsMagicValid(header_->Magic())) {
|
|
StandardDexFile::WriteMagic(header.magic_);
|
|
if (header_->SupportDefaultMethods()) {
|
|
StandardDexFile::WriteCurrentVersion(header.magic_);
|
|
} else {
|
|
StandardDexFile::WriteVersionBeforeDefaultMethods(header.magic_);
|
|
}
|
|
} else {
|
|
// Standard dex -> standard dex, just reuse the same header.
|
|
static constexpr size_t kMagicAndVersionLen =
|
|
StandardDexFile::kDexMagicSize + StandardDexFile::kDexVersionLen;
|
|
std::copy_n(header_->Magic(), kMagicAndVersionLen, header.magic_);
|
|
}
|
|
header.checksum_ = header_->Checksum();
|
|
std::copy_n(header_->Signature(), DexFile::kSha1DigestSize, header.signature_);
|
|
header.file_size_ = header_->FileSize();
|
|
header.header_size_ = GetHeaderSize();
|
|
header.endian_tag_ = header_->EndianTag();
|
|
header.link_size_ = header_->LinkSize();
|
|
header.link_off_ = header_->LinkOffset();
|
|
header.map_off_ = header_->MapListOffset();
|
|
header.string_ids_size_ = header_->StringIds().Size();
|
|
header.string_ids_off_ = header_->StringIds().GetOffset();
|
|
header.type_ids_size_ = header_->TypeIds().Size();
|
|
header.type_ids_off_ = header_->TypeIds().GetOffset();
|
|
header.proto_ids_size_ = header_->ProtoIds().Size();
|
|
header.proto_ids_off_ = header_->ProtoIds().GetOffset();
|
|
header.field_ids_size_ = header_->FieldIds().Size();
|
|
header.field_ids_off_ = header_->FieldIds().GetOffset();
|
|
header.method_ids_size_ = header_->MethodIds().Size();
|
|
header.method_ids_off_ = header_->MethodIds().GetOffset();
|
|
header.class_defs_size_ = header_->ClassDefs().Size();
|
|
header.class_defs_off_ = header_->ClassDefs().GetOffset();
|
|
header.data_size_ = header_->DataSize();
|
|
header.data_off_ = header_->DataOffset();
|
|
|
|
CHECK_EQ(sizeof(header), GetHeaderSize());
|
|
static_assert(sizeof(header) == 0x70, "Size doesn't match dex spec");
|
|
stream->Seek(0);
|
|
stream->Overwrite(reinterpret_cast<uint8_t*>(&header), sizeof(header));
|
|
}
|
|
|
|
size_t DexWriter::GetHeaderSize() const {
|
|
return sizeof(StandardDexFile::Header);
|
|
}
|
|
|
|
bool DexWriter::Write(DexContainer* output, std::string* error_msg) {
|
|
DCHECK(error_msg != nullptr);
|
|
|
|
Stream stream_storage(output->GetMainSection());
|
|
Stream* stream = &stream_storage;
|
|
|
|
// Starting offset is right after the header.
|
|
stream->Seek(GetHeaderSize());
|
|
|
|
// Based on: https://source.android.com/devices/tech/dalvik/dex-format
|
|
// Since the offsets may not be calculated already, the writing must be done in the correct order.
|
|
const uint32_t string_ids_offset = stream->Tell();
|
|
WriteStringIds(stream, /*reserve_only=*/ true);
|
|
WriteTypeIds(stream);
|
|
const uint32_t proto_ids_offset = stream->Tell();
|
|
WriteProtoIds(stream, /*reserve_only=*/ true);
|
|
WriteFieldIds(stream);
|
|
WriteMethodIds(stream);
|
|
const uint32_t class_defs_offset = stream->Tell();
|
|
WriteClassDefs(stream, /*reserve_only=*/ true);
|
|
const uint32_t call_site_ids_offset = stream->Tell();
|
|
WriteCallSiteIds(stream, /*reserve_only=*/ true);
|
|
WriteMethodHandles(stream);
|
|
|
|
uint32_t data_offset_ = 0u;
|
|
if (compute_offsets_) {
|
|
// Data section.
|
|
stream->AlignTo(kDataSectionAlignment);
|
|
data_offset_ = stream->Tell();
|
|
}
|
|
|
|
// Write code item first to minimize the space required for encoded methods.
|
|
// Reserve code item space since we need the debug offsets to actually write them.
|
|
const uint32_t code_items_offset = stream->Tell();
|
|
WriteCodeItems(stream, /*reserve_only=*/ true);
|
|
// Write debug info section.
|
|
WriteDebugInfoItems(stream);
|
|
{
|
|
// Actually write code items since debug info offsets are calculated now.
|
|
Stream::ScopedSeek seek(stream, code_items_offset);
|
|
WriteCodeItems(stream, /*reserve_only=*/ false);
|
|
}
|
|
|
|
WriteEncodedArrays(stream);
|
|
WriteAnnotations(stream);
|
|
WriteAnnotationSets(stream);
|
|
WriteAnnotationSetRefs(stream);
|
|
WriteAnnotationsDirectories(stream);
|
|
WriteTypeLists(stream);
|
|
WriteClassDatas(stream);
|
|
WriteStringDatas(stream);
|
|
WriteHiddenapiClassData(stream);
|
|
|
|
// Write delayed id sections that depend on data sections.
|
|
{
|
|
Stream::ScopedSeek seek(stream, string_ids_offset);
|
|
WriteStringIds(stream, /*reserve_only=*/ false);
|
|
}
|
|
{
|
|
Stream::ScopedSeek seek(stream, proto_ids_offset);
|
|
WriteProtoIds(stream, /*reserve_only=*/ false);
|
|
}
|
|
{
|
|
Stream::ScopedSeek seek(stream, class_defs_offset);
|
|
WriteClassDefs(stream, /*reserve_only=*/ false);
|
|
}
|
|
{
|
|
Stream::ScopedSeek seek(stream, call_site_ids_offset);
|
|
WriteCallSiteIds(stream, /*reserve_only=*/ false);
|
|
}
|
|
|
|
// Write the map list.
|
|
if (compute_offsets_) {
|
|
stream->AlignTo(SectionAlignment(DexFile::kDexTypeMapList));
|
|
header_->SetMapListOffset(stream->Tell());
|
|
} else {
|
|
stream->Seek(header_->MapListOffset());
|
|
}
|
|
GenerateAndWriteMapItems(stream);
|
|
stream->AlignTo(kDataSectionAlignment);
|
|
|
|
// Map items are included in the data section.
|
|
if (compute_offsets_) {
|
|
header_->SetDataSize(stream->Tell() - data_offset_);
|
|
if (header_->DataSize() != 0) {
|
|
// Offset must be zero when the size is zero.
|
|
header_->SetDataOffset(data_offset_);
|
|
} else {
|
|
header_->SetDataOffset(0u);
|
|
}
|
|
}
|
|
|
|
// Write link data if it exists.
|
|
const std::vector<uint8_t>& link_data = header_->LinkData();
|
|
if (link_data.size() > 0) {
|
|
CHECK_EQ(header_->LinkSize(), static_cast<uint32_t>(link_data.size()));
|
|
if (compute_offsets_) {
|
|
header_->SetLinkOffset(stream->Tell());
|
|
} else {
|
|
stream->Seek(header_->LinkOffset());
|
|
}
|
|
stream->Write(&link_data[0], link_data.size());
|
|
}
|
|
|
|
// Write header last.
|
|
if (compute_offsets_) {
|
|
header_->SetFileSize(stream->Tell());
|
|
}
|
|
WriteHeader(stream);
|
|
|
|
if (dex_layout_->GetOptions().update_checksum_) {
|
|
header_->SetChecksum(DexFile::CalculateChecksum(stream->Begin(), header_->FileSize()));
|
|
// Rewrite the header with the calculated checksum.
|
|
WriteHeader(stream);
|
|
}
|
|
|
|
// Trim the map to make it sized as large as the dex file.
|
|
output->GetMainSection()->Resize(header_->FileSize());
|
|
return true;
|
|
}
|
|
|
|
bool DexWriter::Output(DexLayout* dex_layout,
|
|
std::unique_ptr<DexContainer>* container,
|
|
bool compute_offsets,
|
|
std::string* error_msg) {
|
|
CHECK(dex_layout != nullptr);
|
|
std::unique_ptr<DexWriter> writer;
|
|
if (dex_layout->GetOptions().compact_dex_level_ != CompactDexLevel::kCompactDexLevelNone) {
|
|
CHECK(compute_offsets) << "Compact dex requires computing offsets";
|
|
writer.reset(new CompactDexWriter(dex_layout));
|
|
} else {
|
|
writer.reset(new DexWriter(dex_layout, compute_offsets));
|
|
}
|
|
DCHECK(container != nullptr);
|
|
if (*container == nullptr) {
|
|
*container = writer->CreateDexContainer();
|
|
}
|
|
return writer->Write(container->get(), error_msg);
|
|
}
|
|
|
|
void MapItemQueue::AddIfNotEmpty(const MapItem& item) {
|
|
if (item.size_ != 0) {
|
|
push(item);
|
|
}
|
|
}
|
|
|
|
void DexWriter::ProcessOffset(Stream* stream, dex_ir::Item* item) {
|
|
if (compute_offsets_) {
|
|
item->SetOffset(stream->Tell());
|
|
} else {
|
|
// Not computing offsets, just use the one in the item.
|
|
stream->Seek(item->GetOffset());
|
|
}
|
|
}
|
|
|
|
void DexWriter::ProcessOffset(Stream* stream, dex_ir::CollectionBase* item) {
|
|
if (compute_offsets_) {
|
|
item->SetOffset(stream->Tell());
|
|
} else {
|
|
// Not computing offsets, just use the one in the item.
|
|
stream->Seek(item->GetOffset());
|
|
}
|
|
}
|
|
|
|
std::unique_ptr<DexContainer> DexWriter::CreateDexContainer() const {
|
|
return std::unique_ptr<DexContainer>(new DexWriter::Container);
|
|
}
|
|
|
|
} // namespace art
|