diff options
author | 2018-10-26 16:53:25 +0000 | |
---|---|---|
committer | 2018-10-26 16:53:25 +0000 | |
commit | d33d318685ec4a1c9e7995c914c104ab6487513b (patch) | |
tree | 3bb8a93f499ac537d445e90533598571f3d2d120 | |
parent | fe3a979f6214e2ea94a9aed4c573c6a6f64c7096 (diff) |
Revert "Revert^2: Add dex item for hiddenapi flags"
This reverts commit fe3a979f6214e2ea94a9aed4c573c6a6f64c7096.
Reason for revert: Caught by droidcop https://b.corp.google.com/issues/118481351
Change-Id: I17cc3586c9ae3b49839633d9543edce2937c388d
-rw-r--r-- | dex2oat/linker/oat_writer.cc | 9 | ||||
-rw-r--r-- | dexdump/dexdump.cc | 4 | ||||
-rw-r--r-- | dexlayout/compact_dex_writer.cc | 1 | ||||
-rw-r--r-- | dexlayout/dex_ir.h | 55 | ||||
-rw-r--r-- | dexlayout/dex_ir_builder.cc | 49 | ||||
-rw-r--r-- | dexlayout/dex_writer.cc | 56 | ||||
-rw-r--r-- | dexlayout/dex_writer.h | 1 | ||||
-rw-r--r-- | dexlayout/dexlayout.cc | 44 | ||||
-rw-r--r-- | dexlayout/dexlayout.h | 14 | ||||
-rw-r--r-- | dexlist/dexlist.cc | 2 | ||||
-rw-r--r-- | libdexfile/dex/class_accessor-inl.h | 80 | ||||
-rw-r--r-- | libdexfile/dex/class_accessor.h | 60 | ||||
-rw-r--r-- | libdexfile/dex/dex_file.cc | 31 | ||||
-rw-r--r-- | libdexfile/dex/dex_file.h | 44 | ||||
-rw-r--r-- | libdexfile/dex/dex_file_verifier.cc | 118 | ||||
-rw-r--r-- | libdexfile/dex/dex_file_verifier.h | 1 | ||||
-rw-r--r-- | libdexfile/dex/hidden_api_access_flags.h | 93 | ||||
-rw-r--r-- | libdexfile/dex/modifiers.h | 5 | ||||
-rw-r--r-- | oatdump/oatdump.cc | 5 | ||||
-rw-r--r-- | openjdkjvmti/fixed_up_dex_file.cc | 1 | ||||
-rw-r--r-- | runtime/class_linker.cc | 13 | ||||
-rwxr-xr-x | test/etc/default-build | 3 | ||||
-rw-r--r-- | tools/hiddenapi/hiddenapi.cc | 403 | ||||
-rw-r--r-- | tools/hiddenapi/hiddenapi_test.cc | 24 |
24 files changed, 250 insertions, 866 deletions
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc index 01c24fc197..23c486d05b 100644 --- a/dex2oat/linker/oat_writer.cc +++ b/dex2oat/linker/oat_writer.cc @@ -3401,6 +3401,11 @@ bool OatWriter::SeekToDexFile(OutputStream* out, File* file, OatDexFile* oat_dex } bool OatWriter::LayoutAndWriteDexFile(OutputStream* out, OatDexFile* oat_dex_file) { + // Open dex files and write them into `out`. + // Note that we only verify dex files which do not belong to the boot class path. + // This is because those have been processed by `hiddenapi` and would not pass + // some of the checks. No guarantees are lost, however, as `hiddenapi` verifies + // the dex files prior to processing. TimingLogger::ScopedTiming split("Dex Layout", timings_); std::string error_msg; std::string location(oat_dex_file->GetLocation()); @@ -3421,7 +3426,7 @@ bool OatWriter::LayoutAndWriteDexFile(OutputStream* out, OatDexFile* oat_dex_fil dex_file = dex_file_loader.Open(location, zip_entry->GetCrc32(), std::move(mem_map), - /* verify */ true, + /* verify */ !GetCompilerOptions().IsBootImage(), /* verify_checksum */ true, &error_msg); } else if (oat_dex_file->source_.IsRawFile()) { @@ -3433,7 +3438,7 @@ bool OatWriter::LayoutAndWriteDexFile(OutputStream* out, OatDexFile* oat_dex_fil } TimingLogger::ScopedTiming extract("Open", timings_); dex_file = dex_file_loader.OpenDex(dup_fd, location, - /* verify */ true, + /* verify */ !GetCompilerOptions().IsBootImage(), /* verify_checksum */ true, /* mmap_shared */ false, &error_msg); diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc index 2b59342158..6b2a1b9a70 100644 --- a/dexdump/dexdump.cc +++ b/dexdump/dexdump.cc @@ -1208,7 +1208,7 @@ static void dumpCode(const DexFile* pDexFile, u4 idx, u4 flags, */ static void dumpMethod(const ClassAccessor::Method& method, int i) { // Bail for anything private if export only requested. - const uint32_t flags = method.GetAccessFlags(); + const uint32_t flags = method.GetRawAccessFlags(); if (gOptions.exportsOnly && (flags & (kAccPublic | kAccProtected)) == 0) { return; } @@ -1319,7 +1319,7 @@ static void dumpMethod(const ClassAccessor::Method& method, int i) { */ static void dumpField(const ClassAccessor::Field& field, int i, const u1** data = nullptr) { // Bail for anything private if export only requested. - const uint32_t flags = field.GetAccessFlags(); + const uint32_t flags = field.GetRawAccessFlags(); if (gOptions.exportsOnly && (flags & (kAccPublic | kAccProtected)) == 0) { return; } diff --git a/dexlayout/compact_dex_writer.cc b/dexlayout/compact_dex_writer.cc index a7dad0762d..a04cfb65f9 100644 --- a/dexlayout/compact_dex_writer.cc +++ b/dexlayout/compact_dex_writer.cc @@ -441,7 +441,6 @@ bool CompactDexWriter::Write(DexContainer* output, std::string* error_msg) { WriteTypeLists(data_stream); WriteClassDatas(data_stream); WriteStringDatas(data_stream); - WriteHiddenapiClassData(data_stream); // Write delayed id sections that depend on data sections. { diff --git a/dexlayout/dex_ir.h b/dexlayout/dex_ir.h index 20ebc1733c..598f7df778 100644 --- a/dexlayout/dex_ir.h +++ b/dexlayout/dex_ir.h @@ -21,11 +21,11 @@ #include <stdint.h> +#include <map> #include <vector> #include "base/iteration_range.h" #include "base/leb128.h" -#include "base/safe_map.h" #include "base/stl_util.h" #include "dex/dex_file-inl.h" #include "dex/dex_file_types.h" @@ -50,7 +50,6 @@ class EncodedValue; class FieldId; class FieldItem; class Header; -class HiddenapiClassData; class MapList; class MapItem; class MethodHandleItem; @@ -102,7 +101,6 @@ class AbstractDispatcher { virtual void Dispatch(AnnotationSetItem* annotation_set_item) = 0; virtual void Dispatch(AnnotationSetRefList* annotation_set_ref_list) = 0; virtual void Dispatch(AnnotationsDirectoryItem* annotations_directory_item) = 0; - virtual void Dispatch(HiddenapiClassData* hiddenapi_class_data) = 0; virtual void Dispatch(MapList* map_list) = 0; virtual void Dispatch(MapItem* map_item) = 0; @@ -218,7 +216,6 @@ class CollectionBase { uint32_t GetOffset() const { return offset_; } void SetOffset(uint32_t new_offset) { offset_ = new_offset; } virtual uint32_t Size() const = 0; - bool Empty() const { return Size() == 0u; } private: // Start out unassigned. @@ -479,12 +476,6 @@ class Header : public Item { const CollectionVector<AnnotationsDirectoryItem>& AnnotationsDirectoryItems() const { return annotations_directory_items_; } - IndexedCollectionVector<HiddenapiClassData>& HiddenapiClassDatas() { - return hiddenapi_class_datas_; - } - const IndexedCollectionVector<HiddenapiClassData>& HiddenapiClassDatas() const { - return hiddenapi_class_datas_; - } CollectionVector<DebugInfoItem>& DebugInfoItems() { return debug_info_items_; } const CollectionVector<DebugInfoItem>& DebugInfoItems() const { return debug_info_items_; } CollectionVector<CodeItem>& CodeItems() { return code_items_; } @@ -562,7 +553,6 @@ class Header : public Item { IndexedCollectionVector<AnnotationSetItem> annotation_set_items_; IndexedCollectionVector<AnnotationSetRefList> annotation_set_ref_lists_; IndexedCollectionVector<AnnotationsDirectoryItem> annotations_directory_items_; - IndexedCollectionVector<HiddenapiClassData> hiddenapi_class_datas_; // The order of the vectors controls the layout of the output file by index order, to change the // layout just sort the vector. Note that you may only change the order of the non indexed vectors // below. Indexed vectors are accessed by indices in other places, changing the sorting order will @@ -1274,49 +1264,6 @@ class MethodHandleItem : public IndexedItem { DISALLOW_COPY_AND_ASSIGN(MethodHandleItem); }; -using HiddenapiFlagsMap = SafeMap<const Item*, uint32_t>; - -class HiddenapiClassData : public IndexedItem { - public: - HiddenapiClassData(const ClassDef* class_def, std::unique_ptr<HiddenapiFlagsMap> flags) - : class_def_(class_def), flags_(std::move(flags)) { } - ~HiddenapiClassData() override { } - - const ClassDef* GetClassDef() const { return class_def_; } - - uint32_t GetFlags(const Item* field_or_method_item) const { - return (flags_ == nullptr) ? 0u : flags_->Get(field_or_method_item); - } - - static uint32_t GetFlags(Header* header, ClassDef* class_def, const Item* field_or_method_item) { - DCHECK(header != nullptr); - DCHECK(class_def != nullptr); - return (header->HiddenapiClassDatas().Empty()) - ? 0u - : header->HiddenapiClassDatas()[class_def->GetIndex()]->GetFlags(field_or_method_item); - } - - uint32_t ItemSize() const { - uint32_t size = 0u; - bool has_non_zero_entries = false; - if (flags_ != nullptr) { - for (const auto& entry : *flags_) { - size += UnsignedLeb128Size(entry.second); - has_non_zero_entries |= (entry.second != 0u); - } - } - return has_non_zero_entries ? size : 0u; - } - - void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); } - - private: - const ClassDef* class_def_; - std::unique_ptr<HiddenapiFlagsMap> flags_; - - DISALLOW_COPY_AND_ASSIGN(HiddenapiClassData); -}; - // TODO(sehr): implement MapList. class MapList : public Item { public: diff --git a/dexlayout/dex_ir_builder.cc b/dexlayout/dex_ir_builder.cc index c38e563f18..947d3d5297 100644 --- a/dexlayout/dex_ir_builder.cc +++ b/dexlayout/dex_ir_builder.cc @@ -170,7 +170,6 @@ class BuilderMaps { void AddAnnotationsFromMapListSection(const DexFile& dex_file, uint32_t start_offset, uint32_t count); - void AddHiddenapiClassDataFromMapListSection(const DexFile& dex_file, uint32_t offset); void CheckAndSetRemainingOffsets(const DexFile& dex_file, const Options& options); @@ -409,10 +408,6 @@ void BuilderMaps::CheckAndSetRemainingOffsets(const DexFile& dex_file, const Opt case DexFile::kDexTypeAnnotationsDirectoryItem: header_->AnnotationsDirectoryItems().SetOffset(item->offset_); break; - case DexFile::kDexTypeHiddenapiClassData: - header_->HiddenapiClassDatas().SetOffset(item->offset_); - AddHiddenapiClassDataFromMapListSection(dex_file, item->offset_); - break; default: LOG(ERROR) << "Unknown map list item type."; } @@ -629,44 +624,6 @@ void BuilderMaps::AddAnnotationsFromMapListSection(const DexFile& dex_file, } } -void BuilderMaps::AddHiddenapiClassDataFromMapListSection(const DexFile& dex_file, - uint32_t offset) { - const DexFile::HiddenapiClassData* hiddenapi_class_data = - dex_file.GetHiddenapiClassDataAtOffset(offset); - DCHECK(hiddenapi_class_data == dex_file.GetHiddenapiClassData()); - - for (size_t i = 0; i < dex_file.NumClassDefs(); ++i) { - ClassDef* class_def = header_->ClassDefs()[i]; - ClassData* class_data = class_def->GetClassData(); - const uint8_t* ptr = hiddenapi_class_data->GetFlagsPointer(i); - - std::unique_ptr<HiddenapiFlagsMap> flags = nullptr; - if (ptr != nullptr) { - DCHECK(class_data != nullptr); - flags = std::make_unique<HiddenapiFlagsMap>(); - for (const dex_ir::FieldItem& field : *class_data->StaticFields()) { - flags->emplace(&field, DecodeUnsignedLeb128(&ptr)); - } - for (const dex_ir::FieldItem& field : *class_data->InstanceFields()) { - flags->emplace(&field, DecodeUnsignedLeb128(&ptr)); - } - for (const dex_ir::MethodItem& method : *class_data->DirectMethods()) { - flags->emplace(&method, DecodeUnsignedLeb128(&ptr)); - } - for (const dex_ir::MethodItem& method : *class_data->VirtualMethods()) { - flags->emplace(&method, DecodeUnsignedLeb128(&ptr)); - } - } - - CreateAndAddIndexedItem(header_->HiddenapiClassDatas(), - header_->HiddenapiClassDatas().GetOffset() + - hiddenapi_class_data->flags_offset_[i], - i, - class_def, - std::move(flags)); - } -} - AnnotationItem* BuilderMaps::CreateAnnotationItem(const DexFile& dex_file, const DexFile::AnnotationItem* annotation) { const uint8_t* const start_data = reinterpret_cast<const uint8_t*>(annotation); @@ -951,13 +908,13 @@ ClassData* BuilderMaps::CreateClassData(const DexFile& dex_file, FieldItemVector* static_fields = new FieldItemVector(); for (const ClassAccessor::Field& field : accessor.GetStaticFields()) { FieldId* field_item = header_->FieldIds()[field.GetIndex()]; - uint32_t access_flags = field.GetAccessFlags(); + uint32_t access_flags = field.GetRawAccessFlags(); static_fields->emplace_back(access_flags, field_item); } FieldItemVector* instance_fields = new FieldItemVector(); for (const ClassAccessor::Field& field : accessor.GetInstanceFields()) { FieldId* field_item = header_->FieldIds()[field.GetIndex()]; - uint32_t access_flags = field.GetAccessFlags(); + uint32_t access_flags = field.GetRawAccessFlags(); instance_fields->emplace_back(access_flags, field_item); } // Direct methods. @@ -1223,7 +1180,7 @@ void BuilderMaps::ReadEncodedValue(const DexFile& dex_file, MethodItem BuilderMaps::GenerateMethodItem(const DexFile& dex_file, const ClassAccessor::Method& method) { MethodId* method_id = header_->MethodIds()[method.GetIndex()]; - uint32_t access_flags = method.GetAccessFlags(); + uint32_t access_flags = method.GetRawAccessFlags(); const DexFile::CodeItem* disk_code_item = method.GetCodeItem(); // Temporary hack to prevent incorrectly deduping code items if they have the same offset since // they may have different debug info streams. diff --git a/dexlayout/dex_writer.cc b/dexlayout/dex_writer.cc index 929ed405a6..365171b855 100644 --- a/dexlayout/dex_writer.cc +++ b/dexlayout/dex_writer.cc @@ -462,58 +462,6 @@ void DexWriter::WriteAnnotationsDirectories(Stream* stream) { } } -void DexWriter::WriteHiddenapiClassData(Stream* stream) { - if (header_->HiddenapiClassDatas().Empty()) { - return; - } - DCHECK_EQ(header_->HiddenapiClassDatas().Size(), header_->ClassDefs().Size()); - - 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); @@ -782,9 +730,6 @@ void DexWriter::GenerateAndWriteMapItems(Stream* stream) { 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); } @@ -884,7 +829,6 @@ bool DexWriter::Write(DexContainer* output, std::string* error_msg) { WriteTypeLists(stream); WriteClassDatas(stream); WriteStringDatas(stream); - WriteHiddenapiClassData(stream); // Write delayed id sections that depend on data sections. { diff --git a/dexlayout/dex_writer.h b/dexlayout/dex_writer.h index 98041d3314..dd2ebad26f 100644 --- a/dexlayout/dex_writer.h +++ b/dexlayout/dex_writer.h @@ -257,7 +257,6 @@ class DexWriter { void WriteStringDatas(Stream* stream); void WriteClassDatas(Stream* stream); void WriteMethodHandles(Stream* stream); - void WriteHiddenapiClassData(Stream* stream); void WriteMapItems(Stream* stream, MapItemQueue* queue); void GenerateAndWriteMapItems(Stream* stream); diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc index 09f0b20ca1..8905aa31c4 100644 --- a/dexlayout/dexlayout.cc +++ b/dexlayout/dexlayout.cc @@ -222,17 +222,6 @@ static char* CreateAccessFlagStr(uint32_t flags, AccessFor for_what) { return str; } -static const char* GetHiddenapiFlagStr(uint32_t hiddenapi_flags) { - static const char* const kValue[] = { - "WHITELIST", /* 0x0 */ - "LIGHT_GREYLIST", /* 0x1 */ - "DARK_GREYLIST", /* 0x2 */ - "BLACKLIST", /* 0x3 */ - }; - DCHECK_LT(hiddenapi_flags, arraysize(kValue)); - return kValue[hiddenapi_flags]; -} - static std::string GetSignatureForProtoId(const dex_ir::ProtoId* proto) { if (proto == nullptr) { return "<no signature>"; @@ -1158,11 +1147,7 @@ void DexLayout::DumpCode(uint32_t idx, /* * Dumps a method. */ -void DexLayout::DumpMethod(uint32_t idx, - uint32_t flags, - uint32_t hiddenapi_flags, - const dex_ir::CodeItem* code, - int i) { +void DexLayout::DumpMethod(uint32_t idx, uint32_t flags, const dex_ir::CodeItem* code, int i) { // Bail for anything private if export only requested. if (options_.exports_only_ && (flags & (kAccPublic | kAccProtected)) == 0) { return; @@ -1173,16 +1158,12 @@ void DexLayout::DumpMethod(uint32_t idx, char* type_descriptor = strdup(GetSignatureForProtoId(method_id->Proto()).c_str()); const char* back_descriptor = method_id->Class()->GetStringId()->Data(); char* access_str = CreateAccessFlagStr(flags, kAccessForMethod); - const char* hiddenapi_str = GetHiddenapiFlagStr(hiddenapi_flags); if (options_.output_format_ == kOutputPlain) { fprintf(out_file_, " #%d : (in %s)\n", i, back_descriptor); fprintf(out_file_, " name : '%s'\n", name); fprintf(out_file_, " type : '%s'\n", type_descriptor); fprintf(out_file_, " access : 0x%04x (%s)\n", flags, access_str); - if (hiddenapi_flags != 0u) { - fprintf(out_file_, " hiddenapi : 0x%04x (%s)\n", hiddenapi_flags, hiddenapi_str); - } if (code == nullptr) { fprintf(out_file_, " code : (none)\n"); } else { @@ -1276,11 +1257,7 @@ void DexLayout::DumpMethod(uint32_t idx, /* * Dumps a static (class) field. */ -void DexLayout::DumpSField(uint32_t idx, - uint32_t flags, - uint32_t hiddenapi_flags, - int i, - dex_ir::EncodedValue* init) { +void DexLayout::DumpSField(uint32_t idx, uint32_t flags, int i, dex_ir::EncodedValue* init) { // Bail for anything private if export only requested. if (options_.exports_only_ && (flags & (kAccPublic | kAccProtected)) == 0) { return; @@ -1291,16 +1268,12 @@ void DexLayout::DumpSField(uint32_t idx, const char* type_descriptor = field_id->Type()->GetStringId()->Data(); const char* back_descriptor = field_id->Class()->GetStringId()->Data(); char* access_str = CreateAccessFlagStr(flags, kAccessForField); - const char* hiddenapi_str = GetHiddenapiFlagStr(hiddenapi_flags); if (options_.output_format_ == kOutputPlain) { fprintf(out_file_, " #%d : (in %s)\n", i, back_descriptor); fprintf(out_file_, " name : '%s'\n", name); fprintf(out_file_, " type : '%s'\n", type_descriptor); fprintf(out_file_, " access : 0x%04x (%s)\n", flags, access_str); - if (hiddenapi_flags != 0u) { - fprintf(out_file_, " hiddenapi : 0x%04x (%s)\n", hiddenapi_flags, hiddenapi_str); - } if (init != nullptr) { fputs(" value : ", out_file_); DumpEncodedValue(init); @@ -1331,11 +1304,8 @@ void DexLayout::DumpSField(uint32_t idx, /* * Dumps an instance field. */ -void DexLayout::DumpIField(uint32_t idx, - uint32_t flags, - uint32_t hiddenapi_flags, - int i) { - DumpSField(idx, flags, hiddenapi_flags, i, nullptr); +void DexLayout::DumpIField(uint32_t idx, uint32_t flags, int i) { + DumpSField(idx, flags, i, nullptr); } /* @@ -1461,7 +1431,6 @@ void DexLayout::DumpClass(int idx, char** last_package) { for (uint32_t i = 0; i < static_fields->size(); i++) { DumpSField((*static_fields)[i].GetFieldId()->GetIndex(), (*static_fields)[i].GetAccessFlags(), - dex_ir::HiddenapiClassData::GetFlags(header_, class_def, &(*static_fields)[i]), i, i < encoded_values_size ? (*encoded_values)[i].get() : nullptr); } // for @@ -1478,7 +1447,6 @@ void DexLayout::DumpClass(int idx, char** last_package) { for (uint32_t i = 0; i < instance_fields->size(); i++) { DumpIField((*instance_fields)[i].GetFieldId()->GetIndex(), (*instance_fields)[i].GetAccessFlags(), - dex_ir::HiddenapiClassData::GetFlags(header_, class_def, &(*instance_fields)[i]), i); } // for } @@ -1494,9 +1462,8 @@ void DexLayout::DumpClass(int idx, char** last_package) { for (uint32_t i = 0; i < direct_methods->size(); i++) { DumpMethod((*direct_methods)[i].GetMethodId()->GetIndex(), (*direct_methods)[i].GetAccessFlags(), - dex_ir::HiddenapiClassData::GetFlags(header_, class_def, &(*direct_methods)[i]), (*direct_methods)[i].GetCodeItem(), - i); + i); } // for } } @@ -1511,7 +1478,6 @@ void DexLayout::DumpClass(int idx, char** last_package) { for (uint32_t i = 0; i < virtual_methods->size(); i++) { DumpMethod((*virtual_methods)[i].GetMethodId()->GetIndex(), (*virtual_methods)[i].GetAccessFlags(), - dex_ir::HiddenapiClassData::GetFlags(header_, class_def, &(*virtual_methods)[i]), (*virtual_methods)[i].GetCodeItem(), i); } // for diff --git a/dexlayout/dexlayout.h b/dexlayout/dexlayout.h index 6e006b7686..2bca10ddfb 100644 --- a/dexlayout/dexlayout.h +++ b/dexlayout/dexlayout.h @@ -148,7 +148,7 @@ class DexLayout { void DumpEncodedAnnotation(dex_ir::EncodedAnnotation* annotation); void DumpEncodedValue(const dex_ir::EncodedValue* data); void DumpFileHeader(); - void DumpIField(uint32_t idx, uint32_t flags, uint32_t hiddenapi_flags, int i); + void DumpIField(uint32_t idx, uint32_t flags, int i); void DumpInstruction(const dex_ir::CodeItem* code, uint32_t code_offset, uint32_t insn_idx, @@ -156,17 +156,9 @@ class DexLayout { const Instruction* dec_insn); void DumpInterface(const dex_ir::TypeId* type_item, int i); void DumpLocalInfo(const dex_ir::CodeItem* code); - void DumpMethod(uint32_t idx, - uint32_t flags, - uint32_t hiddenapi_flags, - const dex_ir::CodeItem* code, - int i); + void DumpMethod(uint32_t idx, uint32_t flags, const dex_ir::CodeItem* code, int i); void DumpPositionInfo(const dex_ir::CodeItem* code); - void DumpSField(uint32_t idx, - uint32_t flags, - uint32_t hiddenapi_flags, - int i, - dex_ir::EncodedValue* init); + void DumpSField(uint32_t idx, uint32_t flags, int i, dex_ir::EncodedValue* init); void DumpDexFile(); void LayoutClassDefsAndClassData(const DexFile* dex_file); diff --git a/dexlist/dexlist.cc b/dexlist/dexlist.cc index bdf3ca6f11..7d3ae71d5f 100644 --- a/dexlist/dexlist.cc +++ b/dexlist/dexlist.cc @@ -146,7 +146,7 @@ void dumpClass(const DexFile* pDexFile, u4 idx) { dumpMethod(pDexFile, fileName, method.GetIndex(), - method.GetAccessFlags(), + method.GetRawAccessFlags(), method.GetCodeItem(), method.GetCodeItemOffset()); } diff --git a/libdexfile/dex/class_accessor-inl.h b/libdexfile/dex/class_accessor-inl.h index 40bca564ae..21db2cf2be 100644 --- a/libdexfile/dex/class_accessor-inl.h +++ b/libdexfile/dex/class_accessor-inl.h @@ -28,54 +28,34 @@ namespace art { inline ClassAccessor::ClassAccessor(const ClassIteratorData& data) : ClassAccessor(data.dex_file_, data.class_def_idx_) {} -inline ClassAccessor::ClassAccessor(const DexFile& dex_file, - const DexFile::ClassDef& class_def, - bool parse_hiddenapi_class_data) - : ClassAccessor(dex_file, - dex_file.GetClassData(class_def), - dex_file.GetIndexForClassDef(class_def), - parse_hiddenapi_class_data) {} +inline ClassAccessor::ClassAccessor(const DexFile& dex_file, const DexFile::ClassDef& class_def) + : ClassAccessor(dex_file, dex_file.GetIndexForClassDef(class_def)) {} inline ClassAccessor::ClassAccessor(const DexFile& dex_file, uint32_t class_def_index) - : ClassAccessor(dex_file, dex_file.GetClassDef(class_def_index)) {} + : ClassAccessor(dex_file, + dex_file.GetClassData(dex_file.GetClassDef(class_def_index)), + class_def_index) {} inline ClassAccessor::ClassAccessor(const DexFile& dex_file, const uint8_t* class_data, - uint32_t class_def_index, - bool parse_hiddenapi_class_data) + uint32_t class_def_index) : dex_file_(dex_file), class_def_index_(class_def_index), ptr_pos_(class_data), - hiddenapi_ptr_pos_(nullptr), num_static_fields_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u), num_instance_fields_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u), num_direct_methods_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u), - num_virtual_methods_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u) { - if (parse_hiddenapi_class_data && class_def_index != DexFile::kDexNoIndex32) { - const DexFile::HiddenapiClassData* hiddenapi_class_data = dex_file.GetHiddenapiClassData(); - if (hiddenapi_class_data != nullptr) { - hiddenapi_ptr_pos_ = hiddenapi_class_data->GetFlagsPointer(class_def_index); - } - } -} + num_virtual_methods_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u) {} inline void ClassAccessor::Method::Read() { index_ += DecodeUnsignedLeb128(&ptr_pos_); access_flags_ = DecodeUnsignedLeb128(&ptr_pos_); code_off_ = DecodeUnsignedLeb128(&ptr_pos_); - if (hiddenapi_ptr_pos_ != nullptr) { - hiddenapi_flags_ = DecodeUnsignedLeb128(&hiddenapi_ptr_pos_); - DCHECK(HiddenApiAccessFlags::AreValidFlags(hiddenapi_flags_)); - } } inline void ClassAccessor::Field::Read() { index_ += DecodeUnsignedLeb128(&ptr_pos_); access_flags_ = DecodeUnsignedLeb128(&ptr_pos_); - if (hiddenapi_ptr_pos_ != nullptr) { - hiddenapi_flags_ = DecodeUnsignedLeb128(&hiddenapi_ptr_pos_); - DCHECK(HiddenApiAccessFlags::AreValidFlags(hiddenapi_flags_)); - } } template <typename DataType, typename Visitor> @@ -98,12 +78,12 @@ inline void ClassAccessor::VisitFieldsAndMethods( const InstanceFieldVisitor& instance_field_visitor, const DirectMethodVisitor& direct_method_visitor, const VirtualMethodVisitor& virtual_method_visitor) const { - Field field(dex_file_, ptr_pos_, hiddenapi_ptr_pos_); + Field field(dex_file_, ptr_pos_); VisitMembers(num_static_fields_, static_field_visitor, &field); field.NextSection(); VisitMembers(num_instance_fields_, instance_field_visitor, &field); - Method method(dex_file_, field.ptr_pos_, field.hiddenapi_ptr_pos_, /*is_static_or_direct*/ true); + Method method(dex_file_, field.ptr_pos_, /*is_static_or_direct*/ true); VisitMembers(num_direct_methods_, direct_method_visitor, &method); method.NextSection(); VisitMembers(num_virtual_methods_, virtual_method_visitor, &method); @@ -151,43 +131,19 @@ inline const DexFile::CodeItem* ClassAccessor::Method::GetCodeItem() const { inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Field>> ClassAccessor::GetFieldsInternal(size_t count) const { - return { - DataIterator<Field>(dex_file_, - 0u, - num_static_fields_, - count, - ptr_pos_, - hiddenapi_ptr_pos_), - DataIterator<Field>(dex_file_, - count, - num_static_fields_, - count, - // The following pointers are bogus but unused in the `end` iterator. - ptr_pos_, - hiddenapi_ptr_pos_) }; + return { DataIterator<Field>(dex_file_, 0u, num_static_fields_, count, ptr_pos_), + DataIterator<Field>(dex_file_, count, num_static_fields_, count, ptr_pos_) }; } // Return an iteration range for the first <count> methods. inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Method>> ClassAccessor::GetMethodsInternal(size_t count) const { // Skip over the fields. - Field field(dex_file_, ptr_pos_, hiddenapi_ptr_pos_); + Field field(dex_file_, ptr_pos_); VisitMembers(NumFields(), VoidFunctor(), &field); // Return the iterator pair. - return { - DataIterator<Method>(dex_file_, - 0u, - num_direct_methods_, - count, - field.ptr_pos_, - field.hiddenapi_ptr_pos_), - DataIterator<Method>(dex_file_, - count, - num_direct_methods_, - count, - // The following pointers are bogus but unused in the `end` iterator. - field.ptr_pos_, - field.hiddenapi_ptr_pos_) }; + return { DataIterator<Method>(dex_file_, 0u, num_direct_methods_, count, field.ptr_pos_), + DataIterator<Method>(dex_file_, count, num_direct_methods_, count, field.ptr_pos_) }; } inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Field>> ClassAccessor::GetFields() @@ -225,6 +181,14 @@ inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Method>> return { std::next(methods.begin(), NumDirectMethods()), methods.end() }; } +inline void ClassAccessor::Field::UnHideAccessFlags() const { + DexFile::UnHideAccessFlags(const_cast<uint8_t*>(ptr_pos_), GetAccessFlags(), /*is_method*/ false); +} + +inline void ClassAccessor::Method::UnHideAccessFlags() const { + DexFile::UnHideAccessFlags(const_cast<uint8_t*>(ptr_pos_), GetAccessFlags(), /*is_method*/ true); +} + inline dex::TypeIndex ClassAccessor::GetClassIdx() const { return dex_file_.GetClassDef(class_def_index_).class_idx_; } diff --git a/libdexfile/dex/class_accessor.h b/libdexfile/dex/class_accessor.h index e9c1a82c54..d40577f31f 100644 --- a/libdexfile/dex/class_accessor.h +++ b/libdexfile/dex/class_accessor.h @@ -20,6 +20,7 @@ #include "base/utils.h" #include "code_item_accessors.h" #include "dex_file.h" +#include "hidden_api_access_flags.h" #include "invoke_type.h" #include "method_reference.h" #include "modifiers.h" @@ -34,20 +35,22 @@ class ClassAccessor { class BaseItem { public: explicit BaseItem(const DexFile& dex_file, - const uint8_t* ptr_pos, - const uint8_t* hiddenapi_ptr_pos) - : dex_file_(dex_file), ptr_pos_(ptr_pos), hiddenapi_ptr_pos_(hiddenapi_ptr_pos) {} + const uint8_t* ptr_pos) : dex_file_(dex_file), ptr_pos_(ptr_pos) {} uint32_t GetIndex() const { return index_; } - uint32_t GetAccessFlags() const { + uint32_t GetRawAccessFlags() const { return access_flags_; } - uint32_t GetHiddenapiFlags() const { - return hiddenapi_flags_; + uint32_t GetAccessFlags() const { + return HiddenApiAccessFlags::RemoveFromDex(access_flags_); + } + + HiddenApiAccessFlags::ApiList DecodeHiddenAccessFlags() const { + return HiddenApiAccessFlags::DecodeFromDex(access_flags_); } bool IsFinal() const { @@ -63,21 +66,19 @@ class ClassAccessor { } bool MemberIsNative() const { - return GetAccessFlags() & kAccNative; + return GetRawAccessFlags() & kAccNative; } bool MemberIsFinal() const { - return GetAccessFlags() & kAccFinal; + return GetRawAccessFlags() & kAccFinal; } protected: // Internal data pointer for reading. const DexFile& dex_file_; const uint8_t* ptr_pos_ = nullptr; - const uint8_t* hiddenapi_ptr_pos_ = nullptr; uint32_t index_ = 0u; uint32_t access_flags_ = 0u; - uint32_t hiddenapi_flags_ = 0u; }; // A decoded version of the method of a class_data_item. @@ -106,13 +107,14 @@ class ClassAccessor { return is_static_or_direct_; } + // Unhide the hidden API access flags at the iterator position. TODO: Deprecate. + void UnHideAccessFlags() const; + private: - Method(const DexFile& dex_file, - const uint8_t* ptr_pos, - const uint8_t* hiddenapi_ptr_pos = nullptr, - bool is_static_or_direct = true) - : BaseItem(dex_file, ptr_pos, hiddenapi_ptr_pos), - is_static_or_direct_(is_static_or_direct) {} + explicit Method(const DexFile& dex_file, + const uint8_t* ptr_pos, + bool is_static_or_direct = true) + : BaseItem(dex_file, ptr_pos), is_static_or_direct_(is_static_or_direct) {} void Read(); @@ -148,15 +150,16 @@ class ClassAccessor { // A decoded version of the field of a class_data_item. class Field : public BaseItem { public: - Field(const DexFile& dex_file, - const uint8_t* ptr_pos, - const uint8_t* hiddenapi_ptr_pos = nullptr) - : BaseItem(dex_file, ptr_pos, hiddenapi_ptr_pos) {} + explicit Field(const DexFile& dex_file, + const uint8_t* ptr_pos) : BaseItem(dex_file, ptr_pos) {} bool IsStatic() const { return is_static_; } + // Unhide the hidden API access flags at the iterator position. TODO: Deprecate. + void UnHideAccessFlags() const; + private: void Read(); @@ -182,9 +185,8 @@ class ClassAccessor { uint32_t position, uint32_t partition_pos, uint32_t iterator_end, - const uint8_t* ptr_pos, - const uint8_t* hiddenapi_ptr_pos) - : data_(dex_file, ptr_pos, hiddenapi_ptr_pos), + const uint8_t* ptr_pos) + : data_(dex_file, ptr_pos), position_(position), partition_pos_(partition_pos), iterator_end_(iterator_end) { @@ -266,16 +268,13 @@ class ClassAccessor { // Not explicit specifically for range-based loops. ALWAYS_INLINE ClassAccessor(const ClassIteratorData& data); - ALWAYS_INLINE ClassAccessor(const DexFile& dex_file, - const DexFile::ClassDef& class_def, - bool parse_hiddenapi_class_data = false); + ALWAYS_INLINE ClassAccessor(const DexFile& dex_file, const DexFile::ClassDef& class_def); ALWAYS_INLINE ClassAccessor(const DexFile& dex_file, uint32_t class_def_index); ClassAccessor(const DexFile& dex_file, const uint8_t* class_data, - uint32_t class_def_index = DexFile::kDexNoIndex32, - bool parse_hiddenapi_class_data = false); + uint32_t class_def_index = DexFile::kDexNoIndex32); // Return the code item for a method. const DexFile::CodeItem* GetCodeItem(const Method& method) const; @@ -354,10 +353,6 @@ class ClassAccessor { return ptr_pos_ != nullptr; } - bool HasHiddenapiClassData() const { - return hiddenapi_ptr_pos_ != nullptr; - } - uint32_t GetClassDefIndex() const { return class_def_index_; } @@ -382,7 +377,6 @@ class ClassAccessor { const DexFile& dex_file_; const uint32_t class_def_index_; const uint8_t* ptr_pos_ = nullptr; // Pointer into stream of class_data_item. - const uint8_t* hiddenapi_ptr_pos_ = nullptr; // Pointer into stream of hiddenapi_metadata. const uint32_t num_static_fields_ = 0u; const uint32_t num_instance_fields_ = 0u; const uint32_t num_direct_methods_ = 0u; diff --git a/libdexfile/dex/dex_file.cc b/libdexfile/dex/dex_file.cc index 7ccb9c0bad..48f38ca8a1 100644 --- a/libdexfile/dex/dex_file.cc +++ b/libdexfile/dex/dex_file.cc @@ -46,6 +46,31 @@ static_assert(std::is_trivially_copyable<dex::StringIndex>::value, "StringIndex static_assert(sizeof(dex::TypeIndex) == sizeof(uint16_t), "TypeIndex size is wrong"); static_assert(std::is_trivially_copyable<dex::TypeIndex>::value, "TypeIndex not trivial"); +void DexFile::UnHideAccessFlags(uint8_t* data_ptr, + uint32_t new_access_flags, + bool is_method) { + // Go back 1 uleb to start. + data_ptr = ReverseSearchUnsignedLeb128(data_ptr); + if (is_method) { + // Methods have another uleb field before the access flags + data_ptr = ReverseSearchUnsignedLeb128(data_ptr); + } + DCHECK_EQ(HiddenApiAccessFlags::RemoveFromDex(DecodeUnsignedLeb128WithoutMovingCursor(data_ptr)), + new_access_flags); + UpdateUnsignedLeb128(data_ptr, new_access_flags); +} + +void DexFile::UnhideApis() const { + for (ClassAccessor accessor : GetClasses()) { + for (const ClassAccessor::Field& field : accessor.GetFields()) { + field.UnHideAccessFlags(); + } + for (const ClassAccessor::Method& method : accessor.GetMethods()) { + method.UnHideAccessFlags(); + } + } +} + uint32_t DexFile::CalculateChecksum() const { return CalculateChecksum(Begin(), Size()); } @@ -105,7 +130,6 @@ DexFile::DexFile(const uint8_t* base, num_method_handles_(0), call_site_ids_(nullptr), num_call_site_ids_(0), - hiddenapi_class_data_(nullptr), oat_dex_file_(oat_dex_file), container_(std::move(container)), is_compact_dex_(is_compact_dex), @@ -181,11 +205,6 @@ void DexFile::InitializeSectionsFromMapList() { } else if (map_item.type_ == kDexTypeCallSiteIdItem) { call_site_ids_ = reinterpret_cast<const CallSiteIdItem*>(Begin() + map_item.offset_); num_call_site_ids_ = map_item.size_; - } else if (map_item.type_ == kDexTypeHiddenapiClassData) { - hiddenapi_class_data_ = GetHiddenapiClassDataAtOffset(map_item.offset_); - } else { - // Pointers to other sections are not necessary to retain in the DexFile struct. - // Other items have pointers directly into their data. } } } diff --git a/libdexfile/dex/dex_file.h b/libdexfile/dex/dex_file.h index 6a52f67646..30d8b6d9bf 100644 --- a/libdexfile/dex/dex_file.h +++ b/libdexfile/dex/dex_file.h @@ -92,7 +92,7 @@ class DexFile { uint32_t endian_tag_ = 0; uint32_t link_size_ = 0; // unused uint32_t link_off_ = 0; // unused - uint32_t map_off_ = 0; // map list offset from data_off_ + uint32_t map_off_ = 0; // unused uint32_t string_ids_size_ = 0; // number of StringIds uint32_t string_ids_off_ = 0; // file offset of StringIds array uint32_t type_ids_size_ = 0; // number of TypeIds, we don't support more than 65535 @@ -134,7 +134,6 @@ class DexFile { kDexTypeAnnotationItem = 0x2004, kDexTypeEncodedArrayItem = 0x2005, kDexTypeAnnotationsDirectoryItem = 0x2006, - kDexTypeHiddenapiClassData = 0xF000, }; struct MapItem { @@ -148,8 +147,6 @@ class DexFile { uint32_t size_; MapItem list_[1]; - size_t Size() const { return sizeof(uint32_t) + (size_ * sizeof(MapItem)); } - private: DISALLOW_COPY_AND_ASSIGN(MapList); }; @@ -422,27 +419,6 @@ class DexFile { DISALLOW_COPY_AND_ASSIGN(AnnotationItem); }; - struct HiddenapiClassData { - uint32_t size_; // total size of the item - uint32_t flags_offset_[1]; // array of offsets from the beginning of this item, - // indexed by class def index - - // Returns a pointer to the beginning of a uleb128-stream of hiddenapi - // flags for a class def of given index. Values are in the same order - // as fields/methods in the class data. Returns null if the class does - // not have class data. - const uint8_t* GetFlagsPointer(uint32_t class_def_idx) const { - if (flags_offset_[class_def_idx] == 0) { - return nullptr; - } else { - return reinterpret_cast<const uint8_t*>(this) + flags_offset_[class_def_idx]; - } - } - - private: - DISALLOW_COPY_AND_ASSIGN(HiddenapiClassData); - }; - enum AnnotationResultStyle { // private kAllObjects, kPrimitivesOrObjects, @@ -861,14 +837,6 @@ class DexFile { return DataPointer<AnnotationItem>(offset); } - ALWAYS_INLINE const HiddenapiClassData* GetHiddenapiClassDataAtOffset(uint32_t offset) const { - return DataPointer<HiddenapiClassData>(offset); - } - - ALWAYS_INLINE const HiddenapiClassData* GetHiddenapiClassData() const { - return hiddenapi_class_data_; - } - const AnnotationItem* GetAnnotationItem(const AnnotationSetItem* set_item, uint32_t index) const { DCHECK_LE(index, set_item->size_); return GetAnnotationItemAtOffset(set_item->entries_[index]); @@ -1024,6 +992,12 @@ class DexFile { return container_.get(); } + // Changes the dex class data pointed to by data_ptr it to not have any hiddenapi flags. + static void UnHideAccessFlags(uint8_t* data_ptr, uint32_t new_access_flags, bool is_method); + + // Iterate dex classes and remove hiddenapi flags in fields and methods. + void UnhideApis() const; + IterationRange<ClassIterator> GetClasses() const; template <typename Visitor> @@ -1106,10 +1080,6 @@ class DexFile { // Number of elements in the call sites list. size_t num_call_site_ids_; - // Points to the base of the hiddenapi class data item_, or nullptr if the dex - // file does not have one. - const HiddenapiClassData* hiddenapi_class_data_; - // If this dex file was loaded from an oat file, oat_dex_file_ contains a // pointer to the OatDexFile it was loaded from. Otherwise oat_dex_file_ is // null. diff --git a/libdexfile/dex/dex_file_verifier.cc b/libdexfile/dex/dex_file_verifier.cc index 43471c3116..499a89b2ab 100644 --- a/libdexfile/dex/dex_file_verifier.cc +++ b/libdexfile/dex/dex_file_verifier.cc @@ -67,7 +67,6 @@ static uint32_t MapTypeToBitMask(DexFile::MapItemType map_item_type) { case DexFile::kDexTypeAnnotationItem: return 1 << 17; case DexFile::kDexTypeEncodedArrayItem: return 1 << 18; case DexFile::kDexTypeAnnotationsDirectoryItem: return 1 << 19; - case DexFile::kDexTypeHiddenapiClassData: return 1 << 20; } return 0; } @@ -95,7 +94,6 @@ static bool IsDataSectionType(DexFile::MapItemType map_item_type) { case DexFile::kDexTypeAnnotationItem: case DexFile::kDexTypeEncodedArrayItem: case DexFile::kDexTypeAnnotationsDirectoryItem: - case DexFile::kDexTypeHiddenapiClassData: return true; } return true; @@ -1098,7 +1096,7 @@ bool DexFileVerifier::CheckIntraClassDataItemFields(size_t count, return false; } if (!CheckClassDataItemField(curr_index, - field->GetAccessFlags(), + field->GetRawAccessFlags(), (*class_def)->access_flags_, *class_type_index, kStatic)) { @@ -1149,7 +1147,7 @@ bool DexFileVerifier::CheckIntraClassDataItemMethods(ClassAccessor::Method* meth return false; } if (!CheckClassDataItemMethod(curr_index, - method->GetAccessFlags(), + method->GetRawAccessFlags(), (*class_def)->access_flags_, *class_type_index, method->GetCodeItemOffset(), @@ -1557,107 +1555,6 @@ bool DexFileVerifier::CheckIntraAnnotationItem() { return true; } -bool DexFileVerifier::CheckIntraHiddenapiClassData() { - const DexFile::HiddenapiClassData* item = - reinterpret_cast<const DexFile::HiddenapiClassData*>(ptr_); - - // Check expected header size. - uint32_t num_header_elems = dex_file_->NumClassDefs() + 1; - uint32_t elem_size = sizeof(uint32_t); - uint32_t header_size = num_header_elems * elem_size; - if (!CheckListSize(item, num_header_elems, elem_size, "hiddenapi class data section header")) { - return false; - } - - // Check total size. - if (!CheckListSize(item, item->size_, 1u, "hiddenapi class data section")) { - return false; - } - - // Check that total size can fit header. - if (item->size_ < header_size) { - ErrorStringPrintf( - "Hiddenapi class data too short to store header (%u < %u)", item->size_, header_size); - return false; - } - - const uint8_t* data_end = ptr_ + item->size_; - ptr_ += header_size; - - // Check offsets for each class def. - for (uint32_t i = 0; i < dex_file_->NumClassDefs(); ++i) { - const DexFile::ClassDef& class_def = dex_file_->GetClassDef(i); - const uint8_t* class_data = dex_file_->GetClassData(class_def); - uint32_t offset = item->flags_offset_[i]; - - if (offset == 0) { - continue; - } - - // Check that class defs with no class data do not have any hiddenapi class data. - if (class_data == nullptr) { - ErrorStringPrintf( - "Hiddenapi class data offset not zero for class def %u with no class data", i); - return false; - } - - // Check that the offset is within the section. - if (offset > item->size_) { - ErrorStringPrintf( - "Hiddenapi class data offset out of section bounds (%u > %u) for class def %u", - offset, item->size_, i); - return false; - } - - // Check that the offset matches current pointer position. We do not allow - // offsets into already parsed data, or gaps between class def data. - uint32_t ptr_offset = ptr_ - reinterpret_cast<const uint8_t*>(item); - if (offset != ptr_offset) { - ErrorStringPrintf( - "Hiddenapi class data unexpected offset (%u != %u) for class def %u", - offset, ptr_offset, i); - return false; - } - - // Parse a uleb128 value for each field and method of this class. - bool failure = false; - auto fn_member = [&](const ClassAccessor::BaseItem& member, const char* member_type) { - if (failure) { - return; - } - uint32_t decoded_flags; - if (!DecodeUnsignedLeb128Checked(&ptr_, data_end, &decoded_flags)) { - ErrorStringPrintf("Hiddenapi class data value out of bounds (%p > %p) for %s %i", - ptr_, data_end, member_type, member.GetIndex()); - failure = true; - return; - } - if (!HiddenApiAccessFlags::AreValidFlags(decoded_flags)) { - ErrorStringPrintf("Hiddenapi class data flags invalid (%u) for %s %i", - decoded_flags, member_type, member.GetIndex()); - failure = true; - return; - } - }; - auto fn_field = [&](const ClassAccessor::Field& field) { fn_member(field, "field"); }; - auto fn_method = [&](const ClassAccessor::Method& method) { fn_member(method, "method"); }; - ClassAccessor accessor(*dex_file_, class_data); - accessor.VisitFieldsAndMethods(fn_field, fn_field, fn_method, fn_method); - if (failure) { - return false; - } - } - - if (ptr_ != data_end) { - ErrorStringPrintf("Hiddenapi class data wrong reported size (%u != %u)", - static_cast<uint32_t>(ptr_ - reinterpret_cast<const uint8_t*>(item)), - item->size_); - return false; - } - - return true; -} - bool DexFileVerifier::CheckIntraAnnotationsDirectoryItem() { const DexFile::AnnotationsDirectoryItem* item = reinterpret_cast<const DexFile::AnnotationsDirectoryItem*>(ptr_); @@ -1872,12 +1769,6 @@ bool DexFileVerifier::CheckIntraSectionIterate(size_t offset, uint32_t section_c } break; } - case DexFile::kDexTypeHiddenapiClassData: { - if (!CheckIntraHiddenapiClassData()) { - return false; - } - break; - } case DexFile::kDexTypeHeaderItem: case DexFile::kDexTypeMapList: break; @@ -2082,7 +1973,6 @@ bool DexFileVerifier::CheckIntraSection() { CHECK_INTRA_DATA_SECTION_CASE(DexFile::kDexTypeAnnotationItem) CHECK_INTRA_DATA_SECTION_CASE(DexFile::kDexTypeEncodedArrayItem) CHECK_INTRA_DATA_SECTION_CASE(DexFile::kDexTypeAnnotationsDirectoryItem) - CHECK_INTRA_DATA_SECTION_CASE(DexFile::kDexTypeHiddenapiClassData) #undef CHECK_INTRA_DATA_SECTION_CASE } @@ -2846,7 +2736,6 @@ bool DexFileVerifier::CheckInterSectionIterate(size_t offset, case DexFile::kDexTypeDebugInfoItem: case DexFile::kDexTypeAnnotationItem: case DexFile::kDexTypeEncodedArrayItem: - case DexFile::kDexTypeHiddenapiClassData: break; case DexFile::kDexTypeStringIdItem: { if (!CheckInterStringIdItem()) { @@ -2979,8 +2868,7 @@ bool DexFileVerifier::CheckInterSection() { case DexFile::kDexTypeAnnotationSetRefList: case DexFile::kDexTypeAnnotationSetItem: case DexFile::kDexTypeClassDataItem: - case DexFile::kDexTypeAnnotationsDirectoryItem: - case DexFile::kDexTypeHiddenapiClassData: { + case DexFile::kDexTypeAnnotationsDirectoryItem: { if (!CheckInterSectionIterate(section_offset, section_count, type)) { return false; } diff --git a/libdexfile/dex/dex_file_verifier.h b/libdexfile/dex/dex_file_verifier.h index a81df48398..79ddea43d4 100644 --- a/libdexfile/dex/dex_file_verifier.h +++ b/libdexfile/dex/dex_file_verifier.h @@ -126,7 +126,6 @@ class DexFileVerifier { bool CheckIntraDebugInfoItem(); bool CheckIntraAnnotationItem(); bool CheckIntraAnnotationsDirectoryItem(); - bool CheckIntraHiddenapiClassData(); template <DexFile::MapItemType kType> bool CheckIntraSectionIterate(size_t offset, uint32_t count); diff --git a/libdexfile/dex/hidden_api_access_flags.h b/libdexfile/dex/hidden_api_access_flags.h index 837056be80..369615d678 100644 --- a/libdexfile/dex/hidden_api_access_flags.h +++ b/libdexfile/dex/hidden_api_access_flags.h @@ -28,14 +28,31 @@ namespace art { * of information on whether the given class member should be hidden from apps * and under what circumstances. * - * Two bits are encoded for each class member in the HiddenapiClassData item, - * stored in a stream of uleb128-encoded values for each ClassDef item. - * The two bits correspond to values in the ApiList enum below. + * The encoding is different inside DexFile, where we are concerned with size, + * and at runtime where we want to optimize for speed of access. The class + * provides helper functions to decode/encode both of them. * - * At runtime, two bits are set aside in the uint32_t access flags in the - * intrinsics ordinal space (thus intrinsics need to be special-cased). These are - * two consecutive bits and they are directly used to store the integer value of - * the ApiList enum values. + * Encoding in DexFile + * =================== + * + * First bit is encoded as inversion of visibility flags (public/private/protected). + * At most one can be set for any given class member. If two or three are set, + * this is interpreted as the first bit being set and actual visibility flags + * being the complement of the encoded flags. + * + * Second bit is either encoded as bit 5 for fields and non-native methods, where + * it carries no other meaning. If a method is native (bit 8 set), bit 9 is used. + * + * Bits were selected so that they never increase the length of unsigned LEB-128 + * encoding of the access flags. + * + * Encoding at runtime + * =================== + * + * Two bits are set aside in the uint32_t access flags in the intrinsics ordinal + * space (thus intrinsics need to be special-cased). These are two consecutive + * bits and they are directly used to store the integer value of the ApiList + * enum values. * */ class HiddenApiAccessFlags { @@ -48,6 +65,27 @@ class HiddenApiAccessFlags { kNoList, }; + static ALWAYS_INLINE ApiList DecodeFromDex(uint32_t dex_access_flags) { + DexHiddenAccessFlags flags(dex_access_flags); + uint32_t int_value = (flags.IsFirstBitSet() ? 1 : 0) + (flags.IsSecondBitSet() ? 2 : 0); + return static_cast<ApiList>(int_value); + } + + static ALWAYS_INLINE uint32_t RemoveFromDex(uint32_t dex_access_flags) { + DexHiddenAccessFlags flags(dex_access_flags); + flags.SetFirstBit(false); + flags.SetSecondBit(false); + return flags.GetEncoding(); + } + + static ALWAYS_INLINE uint32_t EncodeForDex(uint32_t dex_access_flags, ApiList value) { + DexHiddenAccessFlags flags(RemoveFromDex(dex_access_flags)); + uint32_t int_value = static_cast<uint32_t>(value); + flags.SetFirstBit((int_value & 1) != 0); + flags.SetSecondBit((int_value & 2) != 0); + return flags.GetEncoding(); + } + static ALWAYS_INLINE ApiList DecodeFromRuntime(uint32_t runtime_access_flags) { // This is used in the fast path, only DCHECK here. DCHECK_EQ(runtime_access_flags & kAccIntrinsic, 0u); @@ -65,14 +103,47 @@ class HiddenApiAccessFlags { return runtime_access_flags | hidden_api_flags; } - static ALWAYS_INLINE bool AreValidFlags(uint32_t flags) { - return flags <= static_cast<uint32_t>(kBlacklist); - } - private: static const int kAccFlagsShift = CTZ(kAccHiddenApiBits); static_assert(IsPowerOfTwo((kAccHiddenApiBits >> kAccFlagsShift) + 1), "kAccHiddenApiBits are not continuous"); + + struct DexHiddenAccessFlags { + explicit DexHiddenAccessFlags(uint32_t access_flags) : access_flags_(access_flags) {} + + ALWAYS_INLINE uint32_t GetSecondFlag() { + return ((access_flags_ & kAccNative) != 0) ? kAccDexHiddenBitNative : kAccDexHiddenBit; + } + + ALWAYS_INLINE bool IsFirstBitSet() { + static_assert(IsPowerOfTwo(0u), "Following statement checks if *at most* one bit is set"); + return !IsPowerOfTwo(access_flags_ & kAccVisibilityFlags); + } + + ALWAYS_INLINE void SetFirstBit(bool value) { + if (IsFirstBitSet() != value) { + access_flags_ ^= kAccVisibilityFlags; + } + } + + ALWAYS_INLINE bool IsSecondBitSet() { + return (access_flags_ & GetSecondFlag()) != 0; + } + + ALWAYS_INLINE void SetSecondBit(bool value) { + if (value) { + access_flags_ |= GetSecondFlag(); + } else { + access_flags_ &= ~GetSecondFlag(); + } + } + + ALWAYS_INLINE uint32_t GetEncoding() const { + return access_flags_; + } + + uint32_t access_flags_; + }; }; inline std::ostream& operator<<(std::ostream& os, HiddenApiAccessFlags::ApiList value) { diff --git a/libdexfile/dex/modifiers.h b/libdexfile/dex/modifiers.h index 018b1419b1..38f8455b64 100644 --- a/libdexfile/dex/modifiers.h +++ b/libdexfile/dex/modifiers.h @@ -42,6 +42,11 @@ static constexpr uint32_t kAccEnum = 0x4000; // class, field, ic (1.5) static constexpr uint32_t kAccJavaFlagsMask = 0xffff; // bits set from Java sources (low 16) +// The following flags are used to insert hidden API access flags into boot class path dex files. +// They are decoded by ClassAccessor and removed from the access flags before used by the runtime. +static constexpr uint32_t kAccDexHiddenBit = 0x00000020; // field, method (not native) +static constexpr uint32_t kAccDexHiddenBitNative = 0x00000200; // method (native) + static constexpr uint32_t kAccConstructor = 0x00010000; // method (dex only) <(cl)init> static constexpr uint32_t kAccDeclaredSynchronized = 0x00020000; // method (dex only) static constexpr uint32_t kAccClassIsProxy = 0x00040000; // class (dex only) diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index 358b7ba287..86a36f292b 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -628,6 +628,9 @@ class OatDumper { CHECK(oat_dex_file != nullptr); CHECK(vdex_dex_file != nullptr); + // Remove hiddenapis + vdex_dex_file->UnhideApis(); + // If a CompactDex file is detected within a Vdex container, DexLayout is used to convert // back to a StandardDex file. Since the converted DexFile will most likely not reproduce // the original input Dex file, the `update_checksum_` option is used to recompute the @@ -1075,7 +1078,7 @@ class OatDumper { dex_file, method.GetIndex(), method.GetCodeItem(), - method.GetAccessFlags(), + method.GetRawAccessFlags(), &addr_found)) { success = false; } diff --git a/openjdkjvmti/fixed_up_dex_file.cc b/openjdkjvmti/fixed_up_dex_file.cc index eb93fc9c25..6745d91d53 100644 --- a/openjdkjvmti/fixed_up_dex_file.cc +++ b/openjdkjvmti/fixed_up_dex_file.cc @@ -71,6 +71,7 @@ static void DoDexUnquicken(const art::DexFile& new_dex_file, original_dex_file, /* decompile_return_instruction= */ true); } + new_dex_file.UnhideApis(); } static void DCheckVerifyDexFile(const art::DexFile& dex) { diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index dab8d589e6..c18abab8cb 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -3244,9 +3244,7 @@ void ClassLinker::LoadClass(Thread* self, const DexFile& dex_file, const DexFile::ClassDef& dex_class_def, Handle<mirror::Class> klass) { - ClassAccessor accessor(dex_file, - dex_class_def, - /* parse_hiddenapi_class_data= */ klass->IsBootStrapClassLoaded()); + ClassAccessor accessor(dex_file, dex_class_def); if (!accessor.HasClassData()) { return; } @@ -3362,8 +3360,8 @@ void ClassLinker::LoadField(const ClassAccessor::Field& field, // also set its runtime hidden API access flags. uint32_t access_flags = field.GetAccessFlags(); if (klass->IsBootStrapClassLoaded()) { - access_flags = HiddenApiAccessFlags::EncodeForRuntime( - access_flags, static_cast<HiddenApiAccessFlags::ApiList>(field.GetHiddenapiFlags())); + access_flags = + HiddenApiAccessFlags::EncodeForRuntime(access_flags, field.DecodeHiddenAccessFlags()); } dst->SetAccessFlags(access_flags); } @@ -3384,9 +3382,10 @@ void ClassLinker::LoadMethod(const DexFile& dex_file, // Get access flags from the DexFile. If this is a boot class path class, // also set its runtime hidden API access flags. uint32_t access_flags = method.GetAccessFlags(); + if (klass->IsBootStrapClassLoaded()) { - access_flags = HiddenApiAccessFlags::EncodeForRuntime( - access_flags, static_cast<HiddenApiAccessFlags::ApiList>(method.GetHiddenapiFlags())); + access_flags = + HiddenApiAccessFlags::EncodeForRuntime(access_flags, method.DecodeHiddenAccessFlags()); } if (UNLIKELY(strcmp("finalize", method_name) == 0)) { diff --git a/test/etc/default-build b/test/etc/default-build index 3e6699ad4e..8542ad0e92 100755 --- a/test/etc/default-build +++ b/test/etc/default-build @@ -323,8 +323,7 @@ function make_dexmerge() { function make_hiddenapi() { local args=( "encode" ) while [[ $# -gt 0 ]]; do - args+=("--input-dex=$1") - args+=("--output-dex=$1") + args+=("--dex=$1") shift done if [ -f api-light-greylist.txt ]; then diff --git a/tools/hiddenapi/hiddenapi.cc b/tools/hiddenapi/hiddenapi.cc index 06bea1a3bf..68211a1641 100644 --- a/tools/hiddenapi/hiddenapi.cc +++ b/tools/hiddenapi/hiddenapi.cc @@ -22,8 +22,6 @@ #include "android-base/stringprintf.h" #include "android-base/strings.h" -#include "base/bit_utils.h" -#include "base/stl_util.h" #include "base/mem_map.h" #include "base/os.h" #include "base/unix_file/fd_file.h" @@ -68,9 +66,8 @@ NO_RETURN static void Usage(const char* fmt, ...) { UsageError("Usage: hiddenapi [command_name] [options]..."); UsageError(""); UsageError(" Command \"encode\": encode API list membership in boot dex files"); - UsageError(" --input-dex=<filename>: dex file which belongs to boot class path"); - UsageError(" --output-dex=<filename>: file to write encoded dex into"); - UsageError(" input and output dex files are paired in order of appearance"); + UsageError(" --dex=<filename>: dex file which belongs to boot class path,"); + UsageError(" the file will be overwritten"); UsageError(""); UsageError(" --light-greylist=<filename>:"); UsageError(" --dark-greylist=<filename>:"); @@ -150,6 +147,30 @@ class DexMember { inline const DexClass& GetDeclaringClass() const { return klass_; } + // Sets hidden bits in access flags and writes them back into the DEX in memory. + // Note that this will not update the cached data of the class accessor + // until it iterates over this item again and therefore will fail a CHECK if + // it is called multiple times on the same DexMember. + void SetHidden(HiddenApiAccessFlags::ApiList value) const { + const uint32_t old_flags = item_.GetRawAccessFlags(); + const uint32_t new_flags = HiddenApiAccessFlags::EncodeForDex(old_flags, value); + CHECK_EQ(UnsignedLeb128Size(new_flags), UnsignedLeb128Size(old_flags)); + + // Locate the LEB128-encoded access flags in class data. + // `ptr` initially points to the next ClassData item. We iterate backwards + // until we hit the terminating byte of the previous Leb128 value. + const uint8_t* ptr = item_.GetDataPointer(); + if (IsMethod()) { + ptr = ReverseSearchUnsignedLeb128(ptr); + DCHECK_EQ(DecodeUnsignedLeb128WithoutMovingCursor(ptr), GetMethod().GetCodeItemOffset()); + } + ptr = ReverseSearchUnsignedLeb128(ptr); + DCHECK_EQ(DecodeUnsignedLeb128WithoutMovingCursor(ptr), old_flags); + + // Overwrite the access flags. + UpdateUnsignedLeb128(const_cast<uint8_t*>(ptr), new_flags); + } + inline bool IsMethod() const { return is_method_; } inline bool IsVirtualMethod() const { return IsMethod() && !GetMethod().IsStaticOrDirect(); } inline bool IsConstructor() const { return IsMethod() && HasAccessFlags(kAccConstructor); } @@ -241,10 +262,6 @@ class ClassPath final { }); } - std::vector<const DexFile*> GetDexFiles() const { - return MakeNonOwningPointerVector(dex_files_); - } - void UpdateDexChecksums() { for (auto& dex_file : dex_files_) { // Obtain a writeable pointer to the dex header. @@ -542,316 +559,6 @@ class Hierarchy final { std::map<std::string, HierarchyClass> classes_; }; -// Builder of dex section containing hiddenapi flags. -class HiddenapiClassDataBuilder final { - public: - explicit HiddenapiClassDataBuilder(const DexFile& dex_file) - : num_classdefs_(dex_file.NumClassDefs()), - next_class_def_idx_(0u), - class_def_has_non_zero_flags_(false), - dex_file_has_non_zero_flags_(false), - data_(sizeof(uint32_t) * (num_classdefs_ + 1), 0u) { - *GetSizeField() = GetCurrentDataSize(); - } - - // Notify the builder that new flags for the next class def - // will be written now. The builder records the current offset - // into the header. - void BeginClassDef(uint32_t idx) { - CHECK_EQ(next_class_def_idx_, idx); - CHECK_LT(idx, num_classdefs_); - GetOffsetArray()[idx] = GetCurrentDataSize(); - class_def_has_non_zero_flags_ = false; - } - - // Notify the builder that all flags for this class def have been - // written. The builder updates the total size of the data struct - // and may set offset for class def in header to zero if no data - // has been written. - void EndClassDef(uint32_t idx) { - CHECK_EQ(next_class_def_idx_, idx); - CHECK_LT(idx, num_classdefs_); - - ++next_class_def_idx_; - - if (!class_def_has_non_zero_flags_) { - // No need to store flags for this class. Remove the written flags - // and set offset in header to zero. - data_.resize(GetOffsetArray()[idx]); - GetOffsetArray()[idx] = 0u; - } - - dex_file_has_non_zero_flags_ |= class_def_has_non_zero_flags_; - - if (idx == num_classdefs_ - 1) { - if (dex_file_has_non_zero_flags_) { - // This was the last class def and we have generated non-zero hiddenapi - // flags. Update total size in the header. - *GetSizeField() = GetCurrentDataSize(); - } else { - // This was the last class def and we have not generated any non-zero - // hiddenapi flags. Clear all the data. - data_.clear(); - } - } - } - - // Append flags at the end of the data struct. This should be called - // between BeginClassDef and EndClassDef in the order of appearance of - // fields/methods in the class data stream. - void WriteFlags(uint32_t flags) { - EncodeUnsignedLeb128(&data_, flags); - class_def_has_non_zero_flags_ |= (flags != 0u); - } - - // Return backing data, assuming that all flags have been written. - const std::vector<uint8_t>& GetData() const { - CHECK_EQ(next_class_def_idx_, num_classdefs_) << "Incomplete data"; - return data_; - } - - private: - // Returns pointer to the size field in the header of this dex section. - uint32_t* GetSizeField() { - // Assume malloc() aligns allocated memory to at least uint32_t. - CHECK(IsAligned<sizeof(uint32_t)>(data_.data())); - return reinterpret_cast<uint32_t*>(data_.data()); - } - - // Returns pointer to array of offsets (indexed by class def indices) in the - // header of this dex section. - uint32_t* GetOffsetArray() { return &GetSizeField()[1]; } - uint32_t GetCurrentDataSize() const { return data_.size(); } - - // Number of class defs in this dex file. - const uint32_t num_classdefs_; - - // Next expected class def index. - uint32_t next_class_def_idx_; - - // Whether non-zero flags have been encountered for this class def. - bool class_def_has_non_zero_flags_; - - // Whether any non-zero flags have been encountered for this dex file. - bool dex_file_has_non_zero_flags_; - - // Vector containing the data of the built data structure. - std::vector<uint8_t> data_; -}; - -// Edits a dex file, inserting a new HiddenapiClassData section. -class DexFileEditor final { - public: - DexFileEditor(const DexFile& old_dex, const std::vector<uint8_t>& hiddenapi_class_data) - : old_dex_(old_dex), - hiddenapi_class_data_(hiddenapi_class_data), - loaded_dex_header_(nullptr), - loaded_dex_maplist_(nullptr) {} - - // Copies dex file into a backing data vector, appends the given HiddenapiClassData - // and updates the MapList. - void Encode() { - // We do not support non-standard dex encodings, e.g. compact dex. - CHECK(old_dex_.IsStandardDexFile()); - - // If there are no data to append, copy the old dex file and return. - if (hiddenapi_class_data_.empty()) { - AllocateMemory(old_dex_.Size()); - Append(old_dex_.Begin(), old_dex_.Size(), /* update_header= */ false); - return; - } - - // Find the old MapList, find its size. - const DexFile::MapList* old_map = old_dex_.GetMapList(); - CHECK_LT(old_map->size_, std::numeric_limits<uint32_t>::max()); - - // Compute the size of the new dex file. We append the HiddenapiClassData, - // one MapItem and possibly some padding to align the new MapList. - CHECK(IsAligned<kMapListAlignment>(old_dex_.Size())) - << "End of input dex file is not 4-byte aligned, possibly because its MapList is not " - << "at the end of the file."; - size_t size_delta = - RoundUp(hiddenapi_class_data_.size(), kMapListAlignment) + sizeof(DexFile::MapItem); - size_t new_size = old_dex_.Size() + size_delta; - AllocateMemory(new_size); - - // Copy the old dex file into the backing data vector. Load the copied - // dex file to obtain pointers to its header and MapList. - Append(old_dex_.Begin(), old_dex_.Size(), /* update_header= */ false); - ReloadDex(/* verify= */ false); - - // Truncate the new dex file before the old MapList. This assumes that - // the MapList is the last entry in the dex file. This is currently true - // for our tooling. - // TODO: Implement the general case by zero-ing the old MapList (turning - // it into padding. - RemoveOldMapList(); - - // Append HiddenapiClassData. - size_t payload_offset = AppendHiddenapiClassData(); - - // Wrute new MapList with an entry for HiddenapiClassData. - CreateMapListWithNewItem(payload_offset); - - // Check that the pre-computed size matches the actual size. - CHECK_EQ(offset_, new_size); - - // Reload to all data structures. - ReloadDex(/* verify= */ false); - - // Update the dex checksum. - UpdateChecksum(); - - // Run DexFileVerifier on the new dex file as a CHECK. - ReloadDex(/* verify= */ true); - } - - // Writes the edited dex file into a file. - void WriteTo(const std::string& path) { - CHECK(!data_.empty()); - std::ofstream ofs(path.c_str(), std::ofstream::out | std::ofstream::binary); - ofs.write(reinterpret_cast<const char*>(data_.data()), data_.size()); - ofs.flush(); - CHECK(ofs.good()); - ofs.close(); - } - - private: - static constexpr size_t kMapListAlignment = 4u; - static constexpr size_t kHiddenapiClassDataAlignment = 4u; - - void ReloadDex(bool verify) { - std::string error_msg; - DexFileLoader loader; - loaded_dex_ = loader.Open( - data_.data(), - data_.size(), - "test_location", - old_dex_.GetLocationChecksum(), - /* oat_dex_file= */ nullptr, - /* verify= */ verify, - /* verify_checksum= */ verify, - &error_msg); - if (loaded_dex_.get() == nullptr) { - LOG(FATAL) << "Failed to load edited dex file: " << error_msg; - UNREACHABLE(); - } - - // Load the location of header and map list before we start editing the file. - loaded_dex_header_ = const_cast<DexFile::Header*>(&loaded_dex_->GetHeader()); - loaded_dex_maplist_ = const_cast<DexFile::MapList*>(loaded_dex_->GetMapList()); - } - - DexFile::Header& GetHeader() const { - CHECK(loaded_dex_header_ != nullptr); - return *loaded_dex_header_; - } - - DexFile::MapList& GetMapList() const { - CHECK(loaded_dex_maplist_ != nullptr); - return *loaded_dex_maplist_; - } - - void AllocateMemory(size_t total_size) { - data_.clear(); - data_.resize(total_size); - CHECK(IsAligned<kMapListAlignment>(data_.data())); - CHECK(IsAligned<kHiddenapiClassDataAlignment>(data_.data())); - offset_ = 0; - } - - uint8_t* GetCurrentDataPtr() { - return data_.data() + offset_; - } - - void UpdateDataSize(off_t delta, bool update_header) { - offset_ += delta; - if (update_header) { - DexFile::Header& header = GetHeader(); - header.file_size_ += delta; - header.data_size_ += delta; - } - } - - template<typename T> - T* Append(const T* src, size_t len, bool update_header = true) { - CHECK_LE(offset_ + len, data_.size()); - uint8_t* dst = GetCurrentDataPtr(); - memcpy(dst, src, len); - UpdateDataSize(len, update_header); - return reinterpret_cast<T*>(dst); - } - - void InsertPadding(size_t alignment) { - size_t len = RoundUp(offset_, alignment) - offset_; - std::vector<uint8_t> padding(len, 0); - Append(padding.data(), padding.size()); - } - - void RemoveOldMapList() { - size_t map_size = GetMapList().Size(); - uint8_t* map_start = reinterpret_cast<uint8_t*>(&GetMapList()); - CHECK_EQ(map_start + map_size, GetCurrentDataPtr()) << "MapList not at the end of dex file"; - UpdateDataSize(-static_cast<off_t>(map_size), /* update_header= */ true); - CHECK_EQ(map_start, GetCurrentDataPtr()); - loaded_dex_maplist_ = nullptr; // do not use this map list any more - } - - void CreateMapListWithNewItem(size_t payload_offset) { - InsertPadding(/* alignment= */ kMapListAlignment); - - size_t new_map_offset = offset_; - DexFile::MapList* map = Append(old_dex_.GetMapList(), old_dex_.GetMapList()->Size()); - - // Check last map entry is a pointer to itself. - DexFile::MapItem& old_item = map->list_[map->size_ - 1]; - CHECK(old_item.type_ == DexFile::kDexTypeMapList); - CHECK_EQ(old_item.size_, 1u); - CHECK_EQ(old_item.offset_, GetHeader().map_off_); - - // Create a new MapItem entry with new MapList details. - DexFile::MapItem new_item; - new_item.type_ = old_item.type_; - new_item.size_ = old_item.size_; - new_item.offset_ = new_map_offset; - - // Update pointer in the header. - GetHeader().map_off_ = new_map_offset; - - // Append a new MapItem and return its pointer. - map->size_++; - Append(&new_item, sizeof(DexFile::MapItem)); - - // Change penultimate entry to point to metadata. - old_item.type_ = DexFile::kDexTypeHiddenapiClassData; - old_item.size_ = 1u; // there is only one section - old_item.offset_ = payload_offset; - } - - size_t AppendHiddenapiClassData() { - size_t payload_offset = offset_; - CHECK_EQ(kMapListAlignment, kHiddenapiClassDataAlignment); - CHECK(IsAligned<kHiddenapiClassDataAlignment>(payload_offset)) - << "Should not need to align the section, previous data was already aligned"; - Append(hiddenapi_class_data_.data(), hiddenapi_class_data_.size()); - return payload_offset; - } - - void UpdateChecksum() { - GetHeader().checksum_ = loaded_dex_->CalculateChecksum(); - } - - const DexFile& old_dex_; - const std::vector<uint8_t>& hiddenapi_class_data_; - - std::vector<uint8_t> data_; - size_t offset_; - - std::unique_ptr<const DexFile> loaded_dex_; - DexFile::Header* loaded_dex_header_; - DexFile::MapList* loaded_dex_maplist_; -}; - class HiddenApi final { public: HiddenApi() {} @@ -883,10 +590,8 @@ class HiddenApi final { if (command == "encode") { for (int i = 1; i < argc; ++i) { const StringPiece option(argv[i]); - if (option.starts_with("--input-dex=")) { - boot_dex_paths_.push_back(option.substr(strlen("--input-dex=")).ToString()); - } else if (option.starts_with("--output-dex=")) { - output_dex_paths_.push_back(option.substr(strlen("--output-dex=")).ToString()); + if (option.starts_with("--dex=")) { + boot_dex_paths_.push_back(option.substr(strlen("--dex=")).ToString()); } else if (option.starts_with("--light-greylist=")) { light_greylist_path_ = option.substr(strlen("--light-greylist=")).ToString(); } else if (option.starts_with("--dark-greylist=")) { @@ -925,9 +630,7 @@ class HiddenApi final { void EncodeAccessFlags() { if (boot_dex_paths_.empty()) { - Usage("No input DEX files specified"); - } else if (output_dex_paths_.size() != boot_dex_paths_.size()) { - Usage("Number of input DEX files does not match number of output DEX files"); + Usage("No boot DEX files specified"); } // Load dex signatures. @@ -936,41 +639,16 @@ class HiddenApi final { OpenApiFile(dark_greylist_path_, api_list, HiddenApiAccessFlags::kDarkGreylist); OpenApiFile(blacklist_path_, api_list, HiddenApiAccessFlags::kBlacklist); - // Iterate over input dex files and insert HiddenapiClassData sections. - for (size_t i = 0; i < boot_dex_paths_.size(); ++i) { - const std::string& input_path = boot_dex_paths_[i]; - const std::string& output_path = output_dex_paths_[i]; - - ClassPath boot_classpath({ input_path }, /* open_writable= */ false); - std::vector<const DexFile*> input_dex_files = boot_classpath.GetDexFiles(); - CHECK_EQ(input_dex_files.size(), 1u); - const DexFile& input_dex = *input_dex_files[0]; - - HiddenapiClassDataBuilder builder(input_dex); - boot_classpath.ForEachDexClass([&api_list, &builder](const DexClass& boot_class) { - builder.BeginClassDef(boot_class.GetClassDefIndex()); - if (boot_class.GetData() != nullptr) { - auto fn_shared = [&](const DexMember& boot_member) { - // TODO: Load whitelist and CHECK that entry was found. - auto it = api_list.find(boot_member.GetApiEntry()); - builder.WriteFlags( - (it == api_list.end()) ? HiddenApiAccessFlags::kWhitelist : it->second); - }; - auto fn_field = [&](const ClassAccessor::Field& boot_field) { - fn_shared(DexMember(boot_class, boot_field)); - }; - auto fn_method = [&](const ClassAccessor::Method& boot_method) { - fn_shared(DexMember(boot_class, boot_method)); - }; - boot_class.VisitFieldsAndMethods(fn_field, fn_field, fn_method, fn_method); - } - builder.EndClassDef(boot_class.GetClassDefIndex()); - }); + // Open all dex files. + ClassPath boot_classpath(boot_dex_paths_, /* open_writable= */ true); - DexFileEditor dex_editor(input_dex, builder.GetData()); - dex_editor.Encode(); - dex_editor.WriteTo(output_path); - } + // Set access flags of all members. + boot_classpath.ForEachDexMember([&api_list](const DexMember& boot_member) { + auto it = api_list.find(boot_member.GetApiEntry()); + boot_member.SetHidden(it == api_list.end() ? HiddenApiAccessFlags::kWhitelist : it->second); + }); + + boot_classpath.UpdateDexChecksums(); } void OpenApiFile(const std::string& path, @@ -1070,9 +748,6 @@ class HiddenApi final { // Paths to DEX files which should be processed. std::vector<std::string> boot_dex_paths_; - // Output paths where modified DEX files should be written. - std::vector<std::string> output_dex_paths_; - // Set of public API stub classpaths. Each classpath is formed by a list // of DEX/APK files in the order they appear on the classpath. std::vector<std::vector<std::string>> stub_classpaths_; @@ -1090,8 +765,6 @@ class HiddenApi final { } // namespace art int main(int argc, char** argv) { - art::original_argc = argc; - art::original_argv = argv; android::base::InitLogging(argv); art::MemMap::Init(); art::HiddenApi().Run(argc, argv); diff --git a/tools/hiddenapi/hiddenapi_test.cc b/tools/hiddenapi/hiddenapi_test.cc index cdf797e598..799546e07b 100644 --- a/tools/hiddenapi/hiddenapi_test.cc +++ b/tools/hiddenapi/hiddenapi_test.cc @@ -47,7 +47,6 @@ class HiddenApiTest : public CommonRuntimeTest { const std::vector<std::string>& extra_args, ScratchFile* out_dex) { std::string error; - ScratchFile in_dex; std::unique_ptr<ZipArchive> jar( ZipArchive::Open(GetTestDexFileName("HiddenApi").c_str(), &error)); if (jar == nullptr) { @@ -59,7 +58,7 @@ class HiddenApiTest : public CommonRuntimeTest { LOG(FATAL) << "Could not find classes.dex in test file " << GetTestDexFileName("HiddenApi") << ": " << error; UNREACHABLE(); - } else if (!jar_classes_dex->ExtractToFile(*in_dex.GetFile(), &error)) { + } else if (!jar_classes_dex->ExtractToFile(*out_dex->GetFile(), &error)) { LOG(FATAL) << "Could not extract classes.dex from test file " << GetTestDexFileName("HiddenApi") << ": " << error; UNREACHABLE(); @@ -69,8 +68,7 @@ class HiddenApiTest : public CommonRuntimeTest { argv_str.push_back(GetHiddenApiCmd()); argv_str.insert(argv_str.end(), extra_args.begin(), extra_args.end()); argv_str.push_back("encode"); - argv_str.push_back("--input-dex=" + in_dex.GetFilename()); - argv_str.push_back("--output-dex=" + out_dex->GetFilename()); + argv_str.push_back("--dex=" + out_dex->GetFilename()); argv_str.push_back("--light-greylist=" + light_greylist.GetFilename()); argv_str.push_back("--dark-greylist=" + dark_greylist.GetFilename()); argv_str.push_back("--blacklist=" + blacklist.GetFilename()); @@ -94,7 +92,7 @@ class HiddenApiTest : public CommonRuntimeTest { } std::unique_ptr<const DexFile> dex_file(dex_loader.OpenDex( - fd.Release(), /* location= */ file.GetFilename(), /* verify= */ true, + fd.Release(), /* location= */ file.GetFilename(), /* verify= */ false, /* verify_checksum= */ true, /* mmap_shared= */ false, &error_msg)); if (dex_file.get() == nullptr) { LOG(FATAL) << "Open failed for '" << file.GetFilename() << "' " << error_msg; @@ -128,20 +126,16 @@ class HiddenApiTest : public CommonRuntimeTest { uint32_t expected_visibility, const DexFile::ClassDef& class_def, const DexFile& dex_file) { - ClassAccessor accessor(dex_file, class_def, /* parse hiddenapi flags */ true); + ClassAccessor accessor(dex_file, class_def); CHECK(accessor.HasClassData()) << "Class " << accessor.GetDescriptor() << " has no data"; - if (!accessor.HasHiddenapiClassData()) { - return HiddenApiAccessFlags::kWhitelist; - } - for (const ClassAccessor::Field& field : accessor.GetFields()) { const DexFile::FieldId& fid = dex_file.GetFieldId(field.GetIndex()); if (strcmp(name, dex_file.GetFieldName(fid)) == 0) { const uint32_t actual_visibility = field.GetAccessFlags() & kAccVisibilityFlags; CHECK_EQ(actual_visibility, expected_visibility) << "Field " << name << " in class " << accessor.GetDescriptor(); - return static_cast<HiddenApiAccessFlags::ApiList>(field.GetHiddenapiFlags()); + return field.DecodeHiddenAccessFlags(); } } @@ -155,13 +149,9 @@ class HiddenApiTest : public CommonRuntimeTest { bool expected_native, const DexFile::ClassDef& class_def, const DexFile& dex_file) { - ClassAccessor accessor(dex_file, class_def, /* parse hiddenapi flags */ true); + ClassAccessor accessor(dex_file, class_def); CHECK(accessor.HasClassData()) << "Class " << accessor.GetDescriptor() << " has no data"; - if (!accessor.HasHiddenapiClassData()) { - return HiddenApiAccessFlags::kWhitelist; - } - for (const ClassAccessor::Method& method : accessor.GetMethods()) { const DexFile::MethodId& mid = dex_file.GetMethodId(method.GetIndex()); if (strcmp(name, dex_file.GetMethodName(mid)) == 0) { @@ -170,7 +160,7 @@ class HiddenApiTest : public CommonRuntimeTest { const uint32_t actual_visibility = method.GetAccessFlags() & kAccVisibilityFlags; CHECK_EQ(actual_visibility, expected_visibility) << "Method " << name << " in class " << accessor.GetDescriptor(); - return static_cast<HiddenApiAccessFlags::ApiList>(method.GetHiddenapiFlags()); + return method.DecodeHiddenAccessFlags(); } } |