diff options
105 files changed, 1125 insertions, 1469 deletions
diff --git a/Android.mk b/Android.mk index 3388b35aca..ba131c64e7 100644 --- a/Android.mk +++ b/Android.mk @@ -474,7 +474,7 @@ endif define build-art-hiddenapi $(shell if [ ! -d frameworks/base ]; then \ mkdir -p ${TARGET_OUT_COMMON_INTERMEDIATES}/PACKAGING; \ - touch ${TARGET_OUT_COMMON_INTERMEDIATES}/PACKAGING/hiddenapi-{whitelist,blacklist,dark-greylist,light-greylist}.txt; \ + touch ${TARGET_OUT_COMMON_INTERMEDIATES}/PACKAGING/hiddenapi-flags.csv; \ fi;) endef diff --git a/cmdline/cmdline.h b/cmdline/cmdline.h index 95ab12324c..81a21793d9 100644 --- a/cmdline/cmdline.h +++ b/cmdline/cmdline.h @@ -85,7 +85,9 @@ static bool LocationToFilename(const std::string& location, InstructionSet isa, } } -static Runtime* StartRuntime(const char* boot_image_location, InstructionSet instruction_set) { +static Runtime* StartRuntime(const char* boot_image_location, + InstructionSet instruction_set, + const std::vector<const char*>& runtime_args) { CHECK(boot_image_location != nullptr); RuntimeOptions options; @@ -101,13 +103,19 @@ static Runtime* StartRuntime(const char* boot_image_location, InstructionSet ins std::string boot_image_option; boot_image_option += "-Ximage:"; boot_image_option += boot_image_location; - options.push_back(std::make_pair(boot_image_option.c_str(), nullptr)); + options.push_back(std::make_pair(boot_image_option, nullptr)); } // Instruction set. options.push_back( std::make_pair("imageinstructionset", reinterpret_cast<const void*>(GetInstructionSetString(instruction_set)))); + + // Explicit runtime args. + for (const char* runtime_arg : runtime_args) { + options.push_back(std::make_pair(runtime_arg, nullptr)); + } + // None of the command line tools need sig chain. If this changes we'll need // to upgrade this option to a proper parameter. options.push_back(std::make_pair("-Xno-sig-chain", nullptr)); @@ -154,6 +162,14 @@ struct CmdlineArgs { PrintUsage(); return false; } + } else if (option == "--runtime-arg") { + if (i + 1 == argc) { + fprintf(stderr, "Missing argument for --runtime-arg\n"); + PrintUsage(); + return false; + } + ++i; + runtime_args_.push_back(argv[i]); } else if (option.starts_with("--output=")) { output_name_ = option.substr(strlen("--output=")).ToString(); const char* filename = output_name_.c_str(); @@ -209,6 +225,12 @@ struct CmdlineArgs { " Default: %s\n" "\n", GetInstructionSetString(kRuntimeISA)); + usage += + " --runtime-arg <argument> used to specify various arguments for the runtime\n" + " such as initial heap size, maximum heap size, and verbose output.\n" + " Use a separate --runtime-arg switch for each argument.\n" + " Example: --runtime-arg -Xms256m\n" + "\n"; usage += // Optional. " --output=<file> may be used to send the output to a file.\n" " Example: --output=/tmp/oatdump.txt\n" @@ -221,6 +243,8 @@ struct CmdlineArgs { const char* boot_image_location_ = nullptr; // Specified by --instruction-set. InstructionSet instruction_set_ = InstructionSet::kNone; + // Runtime arguments specified by --runtime-arg. + std::vector<const char*> runtime_args_; // Specified by --output. std::ostream* os_ = &std::cout; std::unique_ptr<std::ofstream> out_; // If something besides cout is used @@ -383,7 +407,7 @@ struct CmdlineMain { Runtime* CreateRuntime(CmdlineArgs* args) { CHECK(args != nullptr); - return StartRuntime(args->boot_image_location_, args->instruction_set_); + return StartRuntime(args->boot_image_location_, args->instruction_set_, args_->runtime_args_); } }; } // namespace art diff --git a/compiler/compiled_method.cc b/compiler/compiled_method.cc index ef9d919c75..58f7e4f227 100644 --- a/compiler/compiled_method.cc +++ b/compiler/compiled_method.cc @@ -73,7 +73,7 @@ size_t CompiledCode::CodeDelta(InstructionSet instruction_set) { } default: LOG(FATAL) << "Unknown InstructionSet: " << instruction_set; - return 0; + UNREACHABLE(); } } @@ -94,7 +94,7 @@ const void* CompiledCode::CodePointer(const void* code_pointer, InstructionSet i } default: LOG(FATAL) << "Unknown InstructionSet: " << instruction_set; - return nullptr; + UNREACHABLE(); } } diff --git a/compiler/jni/quick/arm/calling_convention_arm.cc b/compiler/jni/quick/arm/calling_convention_arm.cc index 54f193b551..8b4bab722f 100644 --- a/compiler/jni/quick/arm/calling_convention_arm.cc +++ b/compiler/jni/quick/arm/calling_convention_arm.cc @@ -173,7 +173,7 @@ bool ArmManagedRuntimeCallingConvention::IsCurrentParamOnStack() { ManagedRegister ArmManagedRuntimeCallingConvention::CurrentParamRegister() { LOG(FATAL) << "Should not reach here"; - return ManagedRegister::NoRegister(); + UNREACHABLE(); } FrameOffset ArmManagedRuntimeCallingConvention::CurrentParamStackOffset() { diff --git a/compiler/jni/quick/arm64/calling_convention_arm64.cc b/compiler/jni/quick/arm64/calling_convention_arm64.cc index 328ecbbc5c..4e6221ef6d 100644 --- a/compiler/jni/quick/arm64/calling_convention_arm64.cc +++ b/compiler/jni/quick/arm64/calling_convention_arm64.cc @@ -181,7 +181,7 @@ bool Arm64ManagedRuntimeCallingConvention::IsCurrentParamOnStack() { ManagedRegister Arm64ManagedRuntimeCallingConvention::CurrentParamRegister() { LOG(FATAL) << "Should not reach here"; - return ManagedRegister::NoRegister(); + UNREACHABLE(); } FrameOffset Arm64ManagedRuntimeCallingConvention::CurrentParamStackOffset() { diff --git a/compiler/jni/quick/mips/calling_convention_mips.cc b/compiler/jni/quick/mips/calling_convention_mips.cc index 5ec1addcb9..d3d489ee36 100644 --- a/compiler/jni/quick/mips/calling_convention_mips.cc +++ b/compiler/jni/quick/mips/calling_convention_mips.cc @@ -124,7 +124,7 @@ bool MipsManagedRuntimeCallingConvention::IsCurrentParamOnStack() { ManagedRegister MipsManagedRuntimeCallingConvention::CurrentParamRegister() { LOG(FATAL) << "Should not reach here"; - return ManagedRegister::NoRegister(); + UNREACHABLE(); } FrameOffset MipsManagedRuntimeCallingConvention::CurrentParamStackOffset() { diff --git a/compiler/jni/quick/mips64/calling_convention_mips64.cc b/compiler/jni/quick/mips64/calling_convention_mips64.cc index a7012aefa8..3c7cee6306 100644 --- a/compiler/jni/quick/mips64/calling_convention_mips64.cc +++ b/compiler/jni/quick/mips64/calling_convention_mips64.cc @@ -109,7 +109,7 @@ bool Mips64ManagedRuntimeCallingConvention::IsCurrentParamOnStack() { ManagedRegister Mips64ManagedRuntimeCallingConvention::CurrentParamRegister() { LOG(FATAL) << "Should not reach here"; - return ManagedRegister::NoRegister(); + UNREACHABLE(); } FrameOffset Mips64ManagedRuntimeCallingConvention::CurrentParamStackOffset() { diff --git a/compiler/jni/quick/x86/calling_convention_x86.cc b/compiler/jni/quick/x86/calling_convention_x86.cc index ad58e3820d..71e601926b 100644 --- a/compiler/jni/quick/x86/calling_convention_x86.cc +++ b/compiler/jni/quick/x86/calling_convention_x86.cc @@ -257,7 +257,7 @@ bool X86JniCallingConvention::IsCurrentParamOnStack() { ManagedRegister X86JniCallingConvention::CurrentParamRegister() { LOG(FATAL) << "Should not reach here"; - return ManagedRegister::NoRegister(); + UNREACHABLE(); } FrameOffset X86JniCallingConvention::CurrentParamStackOffset() { diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc index c2e83cd2c2..2184f99d76 100644 --- a/compiler/optimizing/code_generator.cc +++ b/compiler/optimizing/code_generator.cc @@ -1662,7 +1662,7 @@ QuickEntrypointEnum CodeGenerator::GetArrayAllocationEntrypoint(HNewArray* new_a case 3: return kQuickAllocArrayResolved64; } LOG(FATAL) << "Unreachable"; - return kQuickAllocArrayResolved; + UNREACHABLE(); } } // namespace art diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index 48b50ea5d6..bbf167d615 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -3046,7 +3046,7 @@ void InstructionCodeGeneratorARM64::VisitDivZeroCheck(HDivZeroCheck* instruction if (!DataType::IsIntegralType(type)) { LOG(FATAL) << "Unexpected type " << type << " for DivZeroCheck."; - return; + UNREACHABLE(); } if (value.IsConstant()) { diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc index d5b734d55a..dad18134de 100644 --- a/compiler/optimizing/code_generator_arm_vixl.cc +++ b/compiler/optimizing/code_generator_arm_vixl.cc @@ -1037,26 +1037,26 @@ static uint32_t ComputeSRegisterListMask(const SRegisterList& regs) { size_t CodeGeneratorARMVIXL::SaveCoreRegister(size_t stack_index ATTRIBUTE_UNUSED, uint32_t reg_id ATTRIBUTE_UNUSED) { TODO_VIXL32(FATAL); - return 0; + UNREACHABLE(); } // Restores the register from the stack. Returns the size taken on stack. size_t CodeGeneratorARMVIXL::RestoreCoreRegister(size_t stack_index ATTRIBUTE_UNUSED, uint32_t reg_id ATTRIBUTE_UNUSED) { TODO_VIXL32(FATAL); - return 0; + UNREACHABLE(); } size_t CodeGeneratorARMVIXL::SaveFloatingPointRegister(size_t stack_index ATTRIBUTE_UNUSED, uint32_t reg_id ATTRIBUTE_UNUSED) { TODO_VIXL32(FATAL); - return 0; + UNREACHABLE(); } size_t CodeGeneratorARMVIXL::RestoreFloatingPointRegister(size_t stack_index ATTRIBUTE_UNUSED, uint32_t reg_id ATTRIBUTE_UNUSED) { TODO_VIXL32(FATAL); - return 0; + UNREACHABLE(); } static void GenerateDataProcInstruction(HInstruction::InstructionKind kind, @@ -2268,7 +2268,7 @@ Location InvokeDexCallingConventionVisitorARMVIXL::GetNextLocation(DataType::Typ case DataType::Type::kUint64: case DataType::Type::kVoid: LOG(FATAL) << "Unexpected parameter type " << type; - break; + UNREACHABLE(); } return Location::NoLocation(); } diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc index c6d0f3f618..c536dd3db5 100644 --- a/compiler/optimizing/code_generator_mips.cc +++ b/compiler/optimizing/code_generator_mips.cc @@ -147,7 +147,7 @@ Location InvokeDexCallingConventionVisitorMIPS::GetNextLocation(DataType::Type t case DataType::Type::kUint64: case DataType::Type::kVoid: LOG(FATAL) << "Unexpected parameter type " << type; - break; + UNREACHABLE(); } // Space on the stack is reserved for all arguments. diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc index 039b3ca3ff..016aac791c 100644 --- a/compiler/optimizing/code_generator_mips64.cc +++ b/compiler/optimizing/code_generator_mips64.cc @@ -3642,7 +3642,7 @@ void InstructionCodeGeneratorMIPS64::VisitDivZeroCheck(HDivZeroCheck* instructio if (!DataType::IsIntegralType(type)) { LOG(FATAL) << "Unexpected type " << type << " for DivZeroCheck."; - return; + UNREACHABLE(); } if (value.IsConstant()) { diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index fba4da63cc..1b74d22a81 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -1228,7 +1228,7 @@ Location InvokeDexCallingConventionVisitorX86::GetNextLocation(DataType::Type ty case DataType::Type::kUint64: case DataType::Type::kVoid: LOG(FATAL) << "Unexpected parameter type " << type; - break; + UNREACHABLE(); } return Location::NoLocation(); } @@ -2989,7 +2989,7 @@ void LocationsBuilderX86::VisitAdd(HAdd* add) { default: LOG(FATAL) << "Unexpected add type " << add->GetResultType(); - break; + UNREACHABLE(); } } diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index e7212cd479..781f2724a5 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -2425,7 +2425,7 @@ Location InvokeDexCallingConventionVisitorX86_64::GetNextLocation(DataType::Type case DataType::Type::kUint64: case DataType::Type::kVoid: LOG(FATAL) << "Unexpected parameter type " << type; - break; + UNREACHABLE(); } return Location::NoLocation(); } diff --git a/compiler/optimizing/induction_var_analysis.cc b/compiler/optimizing/induction_var_analysis.cc index a4d638f4c6..3a10d5831d 100644 --- a/compiler/optimizing/induction_var_analysis.cc +++ b/compiler/optimizing/induction_var_analysis.cc @@ -1074,8 +1074,8 @@ bool HInductionVarAnalysis::IsTaken(InductionInfo* lower_expr, && lower_value >= upper_value; default: LOG(FATAL) << "CONDITION UNREACHABLE"; + UNREACHABLE(); } - return false; // not certain, may be untaken } bool HInductionVarAnalysis::IsFinite(InductionInfo* upper_expr, @@ -1099,8 +1099,8 @@ bool HInductionVarAnalysis::IsFinite(InductionInfo* upper_expr, return (IsAtLeast(upper_expr, &value) && value >= (min - stride_value)); default: LOG(FATAL) << "CONDITION UNREACHABLE"; + UNREACHABLE(); } - return false; // not certain, may be infinite } bool HInductionVarAnalysis::FitsNarrowerControl(InductionInfo* lower_expr, diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc index 2b6ae2019f..4c6d6bacd8 100644 --- a/compiler/optimizing/instruction_simplifier.cc +++ b/compiler/optimizing/instruction_simplifier.cc @@ -749,8 +749,8 @@ static HCondition* GetOppositeConditionSwapOps(ArenaAllocator* allocator, HInstr return new (allocator) HBelowOrEqual(rhs, lhs); default: LOG(FATAL) << "Unknown ConditionType " << cond->GetKind(); + UNREACHABLE(); } - return nullptr; } static bool CmpHasBoolType(HInstruction* input, HInstruction* cmp) { diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc index 3f225f354c..d1fba31792 100644 --- a/compiler/optimizing/nodes.cc +++ b/compiler/optimizing/nodes.cc @@ -1231,7 +1231,7 @@ bool HInstructionList::FoundBefore(const HInstruction* instruction1, } } LOG(FATAL) << "Did not find an order between two instructions of the same block."; - return true; + UNREACHABLE(); } bool HInstruction::StrictlyDominates(HInstruction* other_instruction) const { @@ -1254,7 +1254,7 @@ bool HInstruction::StrictlyDominates(HInstruction* other_instruction) const { } else { // There is no order among phis. LOG(FATAL) << "There is no dominance between phis of a same block."; - return false; + UNREACHABLE(); } } else { // `this` is not a phi. diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 31832b4220..edd61897a9 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -685,7 +685,7 @@ class Dex2Oat final { } struct ParserOptions { - std::vector<const char*> oat_symbols; + std::vector<std::string> oat_symbols; std::string boot_image_filename; int64_t watch_dog_timeout_in_ms = -1; bool watch_dog_enabled = true; @@ -835,9 +835,7 @@ class Dex2Oat final { } if (dex_locations_.empty()) { - for (const char* dex_file_name : dex_filenames_) { - dex_locations_.push_back(dex_file_name); - } + dex_locations_ = dex_filenames_; } else if (dex_locations_.size() != dex_filenames_.size()) { Usage("--dex-location arguments do not match --dex-file arguments"); } @@ -1256,8 +1254,8 @@ class Dex2Oat final { // OAT and VDEX file handling if (oat_fd_ == -1) { DCHECK(!oat_filenames_.empty()); - for (const char* oat_filename : oat_filenames_) { - std::unique_ptr<File> oat_file(OS::CreateEmptyFile(oat_filename)); + for (const std::string& oat_filename : oat_filenames_) { + std::unique_ptr<File> oat_file(OS::CreateEmptyFile(oat_filename.c_str())); if (oat_file == nullptr) { PLOG(ERROR) << "Failed to create oat file: " << oat_filename; return false; @@ -1355,7 +1353,7 @@ class Dex2Oat final { } vdex_files_.push_back(std::move(vdex_file)); - oat_filenames_.push_back(oat_location_.c_str()); + oat_filenames_.push_back(oat_location_); } // If we're updating in place a vdex file, be defensive and put an invalid vdex magic in case @@ -1403,7 +1401,8 @@ class Dex2Oat final { MemMap input_file = zip_entry->MapDirectlyOrExtract( VdexFile::kVdexNameInDmFile, kDexMetadata, - &error_msg); + &error_msg, + alignof(VdexFile)); if (!input_file.IsValid()) { LOG(WARNING) << "Could not open vdex file in DexMetadata archive: " << error_msg; } else { @@ -2129,12 +2128,12 @@ class Dex2Oat final { for (size_t i = 0; i < oat_unstripped_.size(); ++i) { // If we don't want to strip in place, copy from stripped location to unstripped location. // We need to strip after image creation because FixupElf needs to use .strtab. - if (strcmp(oat_unstripped_[i], oat_filenames_[i]) != 0) { + if (oat_unstripped_[i] != oat_filenames_[i]) { DCHECK(oat_files_[i].get() != nullptr && oat_files_[i]->IsOpened()); TimingLogger::ScopedTiming t("dex2oat OatFile copy", timings_); std::unique_ptr<File>& in = oat_files_[i]; - std::unique_ptr<File> out(OS::CreateEmptyFile(oat_unstripped_[i])); + std::unique_ptr<File> out(OS::CreateEmptyFile(oat_unstripped_[i].c_str())); int64_t in_length = in->GetLength(); if (in_length < 0) { PLOG(ERROR) << "Failed to get the length of oat file: " << in->GetPath(); @@ -2363,11 +2362,13 @@ class Dex2Oat final { DCHECK_EQ(dex_filenames_.size(), dex_locations_.size()); size_t kept = 0u; for (size_t i = 0, size = dex_filenames_.size(); i != size; ++i) { - if (!OS::FileExists(dex_filenames_[i])) { + if (!OS::FileExists(dex_filenames_[i].c_str())) { LOG(WARNING) << "Skipping non-existent dex file '" << dex_filenames_[i] << "'"; } else { - dex_filenames_[kept] = dex_filenames_[i]; - dex_locations_[kept] = dex_locations_[i]; + if (kept != i) { + dex_filenames_[kept] = dex_filenames_[i]; + dex_locations_[kept] = dex_locations_[i]; + } ++kept; } } @@ -2395,7 +2396,8 @@ class Dex2Oat final { DCHECK_EQ(oat_writers_.size(), dex_filenames_.size()); DCHECK_EQ(oat_writers_.size(), dex_locations_.size()); for (size_t i = 0, size = oat_writers_.size(); i != size; ++i) { - if (!oat_writers_[i]->AddDexFileSource(dex_filenames_[i], dex_locations_[i])) { + if (!oat_writers_[i]->AddDexFileSource(dex_filenames_[i].c_str(), + dex_locations_[i].c_str())) { return false; } } @@ -2404,7 +2406,8 @@ class Dex2Oat final { DCHECK_EQ(dex_filenames_.size(), dex_locations_.size()); DCHECK_NE(dex_filenames_.size(), 0u); for (size_t i = 0; i != dex_filenames_.size(); ++i) { - if (!oat_writers_[0]->AddDexFileSource(dex_filenames_[i], dex_locations_[i])) { + if (!oat_writers_[0]->AddDexFileSource(dex_filenames_[i].c_str(), + dex_locations_[i].c_str())) { return false; } } @@ -2564,7 +2567,7 @@ class Dex2Oat final { CHECK(image_writer_ != nullptr); if (!IsBootImage()) { CHECK(image_filenames_.empty()); - image_filenames_.push_back(app_image_file_name_.c_str()); + image_filenames_.push_back(app_image_file_name_); } if (!image_writer_->Write(app_image_fd_, image_filenames_, @@ -2727,8 +2730,8 @@ class Dex2Oat final { std::vector<std::unique_ptr<File>> oat_files_; std::vector<std::unique_ptr<File>> vdex_files_; std::string oat_location_; - std::vector<const char*> oat_filenames_; - std::vector<const char*> oat_unstripped_; + std::vector<std::string> oat_filenames_; + std::vector<std::string> oat_unstripped_; bool strip_; int oat_fd_; int input_vdex_fd_; @@ -2739,13 +2742,13 @@ class Dex2Oat final { int dm_fd_; std::string dm_file_location_; std::unique_ptr<ZipArchive> dm_file_; - std::vector<const char*> dex_filenames_; - std::vector<const char*> dex_locations_; + std::vector<std::string> dex_filenames_; + std::vector<std::string> dex_locations_; int zip_fd_; std::string zip_location_; std::string boot_image_filename_; std::vector<const char*> runtime_args_; - std::vector<const char*> image_filenames_; + std::vector<std::string> image_filenames_; uintptr_t image_base_; const char* image_classes_zip_filename_; const char* image_classes_filename_; diff --git a/dex2oat/linker/image_test.h b/dex2oat/linker/image_test.h index 1400779bfe..844a72803e 100644 --- a/dex2oat/linker/image_test.h +++ b/dex2oat/linker/image_test.h @@ -201,14 +201,6 @@ inline void ImageTest::DoCompile(ImageHeader::StorageMode storage_mode, } std::unordered_map<const DexFile*, size_t> dex_file_to_oat_index_map; - std::vector<const char*> oat_filename_vector; - for (const std::string& file : oat_filenames) { - oat_filename_vector.push_back(file.c_str()); - } - std::vector<const char*> image_filename_vector; - for (const std::string& file : image_filenames) { - image_filename_vector.push_back(file.c_str()); - } size_t image_idx = 0; for (const DexFile* dex_file : class_path) { dex_file_to_oat_index_map.emplace(dex_file, image_idx); @@ -218,7 +210,7 @@ inline void ImageTest::DoCompile(ImageHeader::StorageMode storage_mode, std::unique_ptr<ImageWriter> writer(new ImageWriter(*compiler_options_, kRequestedImageBase, storage_mode, - oat_filename_vector, + oat_filenames, dex_file_to_oat_index_map, /*class_loader=*/ nullptr, /*dirty_image_objects=*/ nullptr)); @@ -232,15 +224,11 @@ inline void ImageTest::DoCompile(ImageHeader::StorageMode storage_mode, t.NewTiming("WriteElf"); SafeMap<std::string, std::string> key_value_store; - std::vector<const char*> dex_filename_vector; - for (size_t i = 0; i < class_path.size(); ++i) { - dex_filename_vector.push_back(""); - } key_value_store.Put(OatHeader::kBootClassPathKey, gc::space::ImageSpace::GetMultiImageBootClassPath( - dex_filename_vector, - oat_filename_vector, - image_filename_vector)); + out_helper.dex_file_locations, + oat_filenames, + image_filenames)); std::vector<std::unique_ptr<ElfWriter>> elf_writers; std::vector<std::unique_ptr<OatWriter>> oat_writers; @@ -272,7 +260,7 @@ inline void ImageTest::DoCompile(ImageHeader::StorageMode storage_mode, bool dex_files_ok = oat_writers[i]->WriteAndOpenDexFiles( out_helper.vdex_files[i].GetFile(), rodata.back(), - &key_value_store, + (i == 0u) ? &key_value_store : nullptr, /* verify */ false, // Dex files may be dex-to-dex-ed, don't verify. /* update_input_vdex */ false, /* copy_dex_files */ CopyOption::kOnlyIfCompressed, @@ -357,8 +345,8 @@ inline void ImageTest::DoCompile(ImageHeader::StorageMode storage_mode, } bool success_image = writer->Write(kInvalidFd, - image_filename_vector, - oat_filename_vector); + image_filenames, + oat_filenames); ASSERT_TRUE(success_image); for (size_t i = 0, size = oat_filenames.size(); i != size; ++i) { diff --git a/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc index 3ab1cf9f40..231ac04f8c 100644 --- a/dex2oat/linker/image_writer.cc +++ b/dex2oat/linker/image_writer.cc @@ -662,8 +662,8 @@ class ImageWriter::ImageFileGuard { }; bool ImageWriter::Write(int image_fd, - const std::vector<const char*>& image_filenames, - const std::vector<const char*>& oat_filenames) { + const std::vector<std::string>& image_filenames, + const std::vector<std::string>& oat_filenames) { // If image_fd or oat_fd are not kInvalidFd then we may have empty strings in image_filenames or // oat_filenames. CHECK(!image_filenames.empty()); @@ -715,11 +715,11 @@ bool ImageWriter::Write(int image_fd, ImageHeader* primary_header = reinterpret_cast<ImageHeader*>(image_infos_[0].image_.Begin()); ImageFileGuard primary_image_file; for (size_t i = 0; i < image_filenames.size(); ++i) { - const char* image_filename = image_filenames[i]; + const std::string& image_filename = image_filenames[i]; ImageInfo& image_info = GetImageInfo(i); ImageFileGuard image_file; if (image_fd != kInvalidFd) { - if (strlen(image_filename) == 0u) { + if (image_filename.empty()) { image_file.reset(new File(image_fd, unix_file::kCheckSafeUsage)); // Empty the file in case it already exists. if (image_file != nullptr) { @@ -730,7 +730,7 @@ bool ImageWriter::Write(int image_fd, LOG(ERROR) << "image fd " << image_fd << " name " << image_filename; } } else { - image_file.reset(OS::CreateEmptyFile(image_filename)); + image_file.reset(OS::CreateEmptyFile(image_filename.c_str())); } if (image_file == nullptr) { @@ -951,7 +951,7 @@ void ImageWriter::SetImageBinSlot(mirror::Object* object, BinSlot bin_slot) { oss << ". Lock owner:" << lw.ThinLockOwner(); } LOG(FATAL) << oss.str(); - break; + UNREACHABLE(); } case LockWord::kUnlocked: // No hash, don't need to save it. @@ -3508,7 +3508,7 @@ ImageWriter::ImageWriter( const CompilerOptions& compiler_options, uintptr_t image_begin, ImageHeader::StorageMode image_storage_mode, - const std::vector<const char*>& oat_filenames, + const std::vector<std::string>& oat_filenames, const std::unordered_map<const DexFile*, size_t>& dex_file_oat_index_map, jobject class_loader, const HashSet<std::string>* dirty_image_objects) diff --git a/dex2oat/linker/image_writer.h b/dex2oat/linker/image_writer.h index 782bbd2fc2..33bacf8c1b 100644 --- a/dex2oat/linker/image_writer.h +++ b/dex2oat/linker/image_writer.h @@ -79,7 +79,7 @@ class ImageWriter final { ImageWriter(const CompilerOptions& compiler_options, uintptr_t image_begin, ImageHeader::StorageMode image_storage_mode, - const std::vector<const char*>& oat_filenames, + const std::vector<std::string>& oat_filenames, const std::unordered_map<const DexFile*, size_t>& dex_file_oat_index_map, jobject class_loader, const HashSet<std::string>* dirty_image_objects); @@ -142,8 +142,8 @@ class ImageWriter final { // If oat_fd is not kInvalidFd, then we use that for the oat file. Otherwise we open // the names in oat_filenames. bool Write(int image_fd, - const std::vector<const char*>& image_filenames, - const std::vector<const char*>& oat_filenames) + const std::vector<std::string>& image_filenames, + const std::vector<std::string>& oat_filenames) REQUIRES(!Locks::mutator_lock_); uintptr_t GetOatDataBegin(size_t oat_index) { @@ -785,7 +785,7 @@ class ImageWriter final { const ImageHeader::StorageMode image_storage_mode_; // The file names of oat files. - const std::vector<const char*>& oat_filenames_; + const std::vector<std::string>& oat_filenames_; // Map of dex files to the indexes of oat files that they were compiled into. const std::unordered_map<const DexFile*, size_t>& dex_file_oat_index_map_; diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc index 9aaabc49dd..6b17ef6e87 100644 --- a/dex2oat/linker/oat_writer.cc +++ b/dex2oat/linker/oat_writer.cc @@ -3682,7 +3682,7 @@ bool OatWriter::OpenDexFiles( for (OatDexFile& oat_dex_file : oat_dex_files_) { std::string error_msg; maps.emplace_back(oat_dex_file.source_.GetZipEntry()->MapDirectlyOrExtract( - oat_dex_file.dex_file_location_data_, "zipped dex", &error_msg)); + oat_dex_file.dex_file_location_data_, "zipped dex", &error_msg, alignof(DexFile))); MemMap* map = &maps.back(); if (!map->IsValid()) { LOG(ERROR) << error_msg; diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc index 7450964fdf..598a0f846b 100644 --- a/dex2oat/linker/oat_writer_test.cc +++ b/dex2oat/linker/oat_writer_test.cc @@ -119,7 +119,8 @@ class OatTest : public CommonCompilerTest { return false; } } - return DoWriteElf(vdex_file, oat_file, oat_writer, key_value_store, verify); + return DoWriteElf( + vdex_file, oat_file, oat_writer, key_value_store, verify, CopyOption::kOnlyIfCompressed); } bool WriteElf(File* vdex_file, @@ -127,6 +128,7 @@ class OatTest : public CommonCompilerTest { const std::vector<const char*>& dex_filenames, SafeMap<std::string, std::string>& key_value_store, bool verify, + CopyOption copy, ProfileCompilationInfo* profile_compilation_info) { TimingLogger timings("WriteElf", false, false); ClearBootImageOption(); @@ -139,7 +141,7 @@ class OatTest : public CommonCompilerTest { return false; } } - return DoWriteElf(vdex_file, oat_file, oat_writer, key_value_store, verify); + return DoWriteElf(vdex_file, oat_file, oat_writer, key_value_store, verify, copy); } bool WriteElf(File* vdex_file, @@ -147,7 +149,8 @@ class OatTest : public CommonCompilerTest { File&& zip_fd, const char* location, SafeMap<std::string, std::string>& key_value_store, - bool verify) { + bool verify, + CopyOption copy) { TimingLogger timings("WriteElf", false, false); ClearBootImageOption(); OatWriter oat_writer(*compiler_options_, @@ -157,14 +160,15 @@ class OatTest : public CommonCompilerTest { if (!oat_writer.AddZippedDexFilesSource(std::move(zip_fd), location)) { return false; } - return DoWriteElf(vdex_file, oat_file, oat_writer, key_value_store, verify); + return DoWriteElf(vdex_file, oat_file, oat_writer, key_value_store, verify, copy); } bool DoWriteElf(File* vdex_file, File* oat_file, OatWriter& oat_writer, SafeMap<std::string, std::string>& key_value_store, - bool verify) { + bool verify, + CopyOption copy) { std::unique_ptr<ElfWriter> elf_writer = CreateElfWriterQuick( compiler_driver_->GetCompilerOptions(), oat_file); @@ -178,7 +182,7 @@ class OatTest : public CommonCompilerTest { &key_value_store, verify, /*update_input_vdex=*/ false, - CopyOption::kOnlyIfCompressed, + copy, &opened_dex_files_maps, &opened_dex_files)) { return false; @@ -257,7 +261,7 @@ class OatTest : public CommonCompilerTest { } void TestDexFileInput(bool verify, bool low_4gb, bool use_profile); - void TestZipFileInput(bool verify); + void TestZipFileInput(bool verify, CopyOption copy); void TestZipFileInputWithEmptyDex(); std::unique_ptr<QuickCompilerCallbacks> callbacks_; @@ -587,6 +591,7 @@ void OatTest::TestDexFileInput(bool verify, bool low_4gb, bool use_profile) { input_filenames, key_value_store, verify, + CopyOption::kOnlyIfCompressed, profile_compilation_info.get()); // In verify mode, we expect failure. @@ -663,7 +668,7 @@ TEST_F(OatTest, DexFileFailsVerifierWithLayout) { TestDexFileInput(/*verify*/true, /*low_4gb*/false, /*use_profile*/true); } -void OatTest::TestZipFileInput(bool verify) { +void OatTest::TestZipFileInput(bool verify, CopyOption copy) { TimingLogger timings("OatTest::DexFileInput", false, false); ScratchFile zip_file; @@ -719,6 +724,7 @@ void OatTest::TestZipFileInput(bool verify) { input_filenames, key_value_store, verify, + copy, /*profile_compilation_info=*/ nullptr); if (verify) { @@ -769,7 +775,8 @@ void OatTest::TestZipFileInput(bool verify) { std::move(zip_fd), zip_file.GetFilename().c_str(), key_value_store, - verify); + verify, + copy); if (verify) { ASSERT_FALSE(success); } else { @@ -809,11 +816,15 @@ void OatTest::TestZipFileInput(bool verify) { } TEST_F(OatTest, ZipFileInputCheckOutput) { - TestZipFileInput(false); + TestZipFileInput(false, CopyOption::kOnlyIfCompressed); +} + +TEST_F(OatTest, ZipFileInputCheckOutputWithoutCopy) { + TestZipFileInput(false, CopyOption::kNever); } TEST_F(OatTest, ZipFileInputCheckVerifier) { - TestZipFileInput(true); + TestZipFileInput(true, CopyOption::kOnlyIfCompressed); } void OatTest::TestZipFileInputWithEmptyDex() { @@ -833,6 +844,7 @@ void OatTest::TestZipFileInputWithEmptyDex() { input_filenames, key_value_store, /*verify=*/ false, + CopyOption::kOnlyIfCompressed, profile_compilation_info.get()); ASSERT_FALSE(success); } diff --git a/dexoptanalyzer/dexoptanalyzer.cc b/dexoptanalyzer/dexoptanalyzer.cc index 2b97fb402a..acf0f94572 100644 --- a/dexoptanalyzer/dexoptanalyzer.cc +++ b/dexoptanalyzer/dexoptanalyzer.cc @@ -97,6 +97,11 @@ NO_RETURN static void Usage(const char *fmt, ...) { UsageError(" oat file is up to date. Defaults to $ANDROID_ROOT/framework/boot.art."); UsageError(" Example: --image=/system/framework/boot.art"); UsageError(""); + UsageError(" --runtime-arg <argument>: used to specify various arguments for the runtime,"); + UsageError(" such as initial heap size, maximum heap size, and verbose output."); + UsageError(" Use a separate --runtime-arg switch for each argument."); + UsageError(" Example: --runtime-arg -Xms256m"); + UsageError(""); UsageError(" --android-data=<directory>: optional, the directory which should be used as"); UsageError(" android-data. By default ANDROID_DATA env variable is used."); UsageError(""); @@ -168,6 +173,12 @@ class DexoptAnalyzer final { } } else if (option.starts_with("--image=")) { image_ = option.substr(strlen("--image=")).ToString(); + } else if (option == "--runtime-arg") { + if (i + 1 == argc) { + Usage("Missing argument for --runtime-arg\n"); + } + ++i; + runtime_args_.push_back(argv[i]); } else if (option.starts_with("--android-data=")) { // Overwrite android-data if needed (oat file assistant relies on a valid directory to // compute dalvik-cache folder). This is mostly used in tests. @@ -218,10 +229,14 @@ class DexoptAnalyzer final { RuntimeOptions options; // The image could be custom, so make sure we explicitly pass it. std::string img = "-Ximage:" + image_; - options.push_back(std::make_pair(img.c_str(), nullptr)); + options.push_back(std::make_pair(img, nullptr)); // The instruction set of the image should match the instruction set we will test. const void* isa_opt = reinterpret_cast<const void*>(GetInstructionSetString(isa_)); options.push_back(std::make_pair("imageinstructionset", isa_opt)); + // Explicit runtime args. + for (const char* runtime_arg : runtime_args_) { + options.push_back(std::make_pair(runtime_arg, nullptr)); + } // Disable libsigchain. We don't don't need it to evaluate DexOptNeeded status. options.push_back(std::make_pair("-Xno-sig-chain", nullptr)); // Pretend we are a compiler so that we can re-use the same infrastructure to load a different @@ -289,6 +304,7 @@ class DexoptAnalyzer final { bool assume_profile_changed_; bool downgrade_; std::string image_; + std::vector<const char*> runtime_args_; int oat_fd_ = -1; int vdex_fd_ = -1; // File descriptor corresponding to apk, dex_file, or zip. diff --git a/disassembler/disassembler.cc b/disassembler/disassembler.cc index aee690e036..0662334852 100644 --- a/disassembler/disassembler.cc +++ b/disassembler/disassembler.cc @@ -75,7 +75,7 @@ Disassembler* Disassembler::Create(InstructionSet instruction_set, DisassemblerO #endif default: UNIMPLEMENTED(FATAL) << static_cast<uint32_t>(instruction_set); - return nullptr; + UNREACHABLE(); } } diff --git a/libartbase/base/file_utils.cc b/libartbase/base/file_utils.cc index 1d106b2cdb..f8d6016315 100644 --- a/libartbase/base/file_utils.cc +++ b/libartbase/base/file_utils.cc @@ -157,7 +157,7 @@ static const char* GetAndroidDir(const char* env_var, const char* default_dir) { return dir; } else { LOG(FATAL) << error_msg; - return nullptr; + UNREACHABLE(); } } diff --git a/libartbase/base/hiddenapi_flags.h b/libartbase/base/hiddenapi_flags.h index 8e7269cc60..9ea01d7f3b 100644 --- a/libartbase/base/hiddenapi_flags.h +++ b/libartbase/base/hiddenapi_flags.h @@ -58,6 +58,8 @@ class ApiList { "greylist-max-o", }; + static constexpr const char* kInvalidName = "invalid"; + static constexpr SdkVersion kMaxSdkVersions[] { /* whitelist */ SdkVersion::kMax, /* greylist */ SdkVersion::kMax, @@ -70,7 +72,7 @@ class ApiList { explicit ApiList(Value value) : value_(value) {} - const Value value_; + Value value_; public: static ApiList Whitelist() { return ApiList(Value::kWhitelist); } @@ -87,6 +89,14 @@ class ApiList { return Invalid(); } + // Decodes ApiList from its integer value. + static ApiList FromIntValue(IntValueType int_value) { + if (MinValue().GetIntValue() <= int_value && int_value <= MaxValue().GetIntValue()) { + return ApiList(static_cast<Value>(int_value)); + } + return Invalid(); + } + // Returns the ApiList with a given name. static ApiList FromName(const std::string& str) { for (IntValueType i = MinValue().GetIntValue(); i <= MaxValue().GetIntValue(); i++) { @@ -108,7 +118,7 @@ class ApiList { return static_cast<IntValueType>(value_); } - const char* GetName() const { return kNames[GetIntValue()]; } + const char* GetName() const { return IsValid() ? kNames[GetIntValue()]: kInvalidName; } SdkVersion GetMaxAllowedSdkVersion() const { return kMaxSdkVersions[GetIntValue()]; } diff --git a/libartbase/base/zip_archive.cc b/libartbase/base/zip_archive.cc index 8ceea83be4..a7f4b28c84 100644 --- a/libartbase/base/zip_archive.cc +++ b/libartbase/base/zip_archive.cc @@ -189,8 +189,9 @@ MemMap ZipEntry::MapDirectlyFromFile(const char* zip_filename, std::string* erro MemMap ZipEntry::MapDirectlyOrExtract(const char* zip_filename, const char* entry_filename, - std::string* error_msg) { - if (IsUncompressed() && GetFileDescriptor(handle_) >= 0) { + std::string* error_msg, + size_t alignment) { + if (IsUncompressed() && IsAlignedTo(alignment) && GetFileDescriptor(handle_) >= 0) { std::string local_error_msg; MemMap ret = MapDirectlyFromFile(zip_filename, &local_error_msg); if (ret.IsValid()) { diff --git a/libartbase/base/zip_archive.h b/libartbase/base/zip_archive.h index d326a9e9d7..fc04ec1e91 100644 --- a/libartbase/base/zip_archive.h +++ b/libartbase/base/zip_archive.h @@ -59,7 +59,8 @@ class ZipEntry { MemMap MapDirectlyOrExtract(const char* zip_filename, const char* entry_filename, - std::string* error_msg); + std::string* error_msg, + size_t alignment); uint32_t GetUncompressedLength(); uint32_t GetCrc32(); diff --git a/libdexfile/dex/dex_instruction.cc b/libdexfile/dex/dex_instruction.cc index 8378211c43..83663c50e8 100644 --- a/libdexfile/dex/dex_instruction.cc +++ b/libdexfile/dex/dex_instruction.cc @@ -85,7 +85,7 @@ int32_t Instruction::GetTargetOffset() const { default: LOG(FATAL) << "Tried to access the branch offset of an instruction " << Name() << " which does not have a target operand."; } - return 0; + UNREACHABLE(); } bool Instruction::CanFlowThrough() const { diff --git a/libprofile/profile/profile_compilation_info.cc b/libprofile/profile/profile_compilation_info.cc index 6bd49a43eb..02f6344863 100644 --- a/libprofile/profile/profile_compilation_info.cc +++ b/libprofile/profile/profile_compilation_info.cc @@ -1197,7 +1197,8 @@ ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::OpenSource( } // TODO(calin) pass along file names to assist with debugging. - MemMap map = zip_entry->MapDirectlyOrExtract(kDexMetadataProfileEntry, "profile file", error); + MemMap map = zip_entry->MapDirectlyOrExtract( + kDexMetadataProfileEntry, "profile file", error, alignof(ProfileSource)); if (map.IsValid()) { source->reset(ProfileSource::Create(std::move(map))); diff --git a/openjdkjvm/OpenjdkJvm.cc b/openjdkjvm/OpenjdkJvm.cc index 8d0200c346..7a388c9583 100644 --- a/openjdkjvm/OpenjdkJvm.cc +++ b/openjdkjvm/OpenjdkJvm.cc @@ -434,36 +434,37 @@ JNIEXPORT void JVM_SetNativeThreadName(JNIEnv* env, jobject jthread, jstring jav } } -JNIEXPORT jint JVM_IHashCode(JNIEnv* env ATTRIBUTE_UNUSED, +JNIEXPORT __attribute__((noreturn)) jint JVM_IHashCode(JNIEnv* env ATTRIBUTE_UNUSED, jobject javaObject ATTRIBUTE_UNUSED) { UNIMPLEMENTED(FATAL) << "JVM_IHashCode is not implemented"; - return 0; + UNREACHABLE(); } -JNIEXPORT jlong JVM_NanoTime(JNIEnv* env ATTRIBUTE_UNUSED, jclass unused ATTRIBUTE_UNUSED) { +JNIEXPORT __attribute__((noreturn)) jlong JVM_NanoTime(JNIEnv* env ATTRIBUTE_UNUSED, jclass unused ATTRIBUTE_UNUSED) { UNIMPLEMENTED(FATAL) << "JVM_NanoTime is not implemented"; - return 0L; + UNREACHABLE(); } -JNIEXPORT void JVM_ArrayCopy(JNIEnv* /* env */, jclass /* unused */, jobject /* javaSrc */, +JNIEXPORT __attribute__((noreturn)) void JVM_ArrayCopy(JNIEnv* /* env */, jclass /* unused */, jobject /* javaSrc */, jint /* srcPos */, jobject /* javaDst */, jint /* dstPos */, jint /* length */) { UNIMPLEMENTED(FATAL) << "JVM_ArrayCopy is not implemented"; + UNREACHABLE(); } -JNIEXPORT jint JVM_FindSignal(const char* name ATTRIBUTE_UNUSED) { +JNIEXPORT __attribute__((noreturn)) jint JVM_FindSignal(const char* name ATTRIBUTE_UNUSED) { LOG(FATAL) << "JVM_FindSignal is not implemented"; - return 0; + UNREACHABLE(); } -JNIEXPORT void* JVM_RegisterSignal(jint signum ATTRIBUTE_UNUSED, void* handler ATTRIBUTE_UNUSED) { +JNIEXPORT __attribute__((noreturn)) void* JVM_RegisterSignal(jint signum ATTRIBUTE_UNUSED, void* handler ATTRIBUTE_UNUSED) { LOG(FATAL) << "JVM_RegisterSignal is not implemented"; - return nullptr; + UNREACHABLE(); } -JNIEXPORT jboolean JVM_RaiseSignal(jint signum ATTRIBUTE_UNUSED) { +JNIEXPORT __attribute__((noreturn)) jboolean JVM_RaiseSignal(jint signum ATTRIBUTE_UNUSED) { LOG(FATAL) << "JVM_RaiseSignal is not implemented"; - return JNI_FALSE; + UNREACHABLE(); } JNIEXPORT __attribute__((noreturn)) void JVM_Halt(jint code) { diff --git a/openjdkjvmti/events.cc b/openjdkjvmti/events.cc index a96436e95a..7fb6a15220 100644 --- a/openjdkjvmti/events.cc +++ b/openjdkjvmti/events.cc @@ -960,7 +960,7 @@ static uint32_t GetInstrumentationEventsFor(ArtJvmtiEvent event) { return art::instrumentation::Instrumentation::kExceptionHandled; default: LOG(FATAL) << "Unknown event "; - return 0; + UNREACHABLE(); } } diff --git a/runtime/art_method.cc b/runtime/art_method.cc index abfdd5547d..882291f20b 100644 --- a/runtime/art_method.cc +++ b/runtime/art_method.cc @@ -70,7 +70,7 @@ ArtMethod* ArtMethod::GetCanonicalMethod(PointerSize pointer_size) { } else { ObjPtr<mirror::Class> declaring_class = GetDeclaringClass(); DCHECK(declaring_class->IsInterface()); - ArtMethod* ret = declaring_class->FindInterfaceMethod(declaring_class->GetDexCache(), + ArtMethod* ret = declaring_class->FindInterfaceMethod(GetDexCache(), GetDexMethodIndex(), pointer_size); DCHECK(ret != nullptr); @@ -79,10 +79,11 @@ ArtMethod* ArtMethod::GetCanonicalMethod(PointerSize pointer_size) { } ArtMethod* ArtMethod::GetNonObsoleteMethod() { - DCHECK_EQ(kRuntimePointerSize, Runtime::Current()->GetClassLinker()->GetImagePointerSize()); if (LIKELY(!IsObsolete())) { return this; - } else if (IsDirect()) { + } + DCHECK_EQ(kRuntimePointerSize, Runtime::Current()->GetClassLinker()->GetImagePointerSize()); + if (IsDirect()) { return &GetDeclaringClass()->GetDirectMethodsSlice(kRuntimePointerSize)[GetMethodIndex()]; } else { return GetDeclaringClass()->GetVTableEntry(GetMethodIndex(), kRuntimePointerSize); @@ -504,10 +505,10 @@ static const OatFile::OatMethod FindOatMethodFor(ArtMethod* method, << method->PrettyMethod(); } DCHECK_EQ(oat_method_index, - GetOatMethodIndexFromMethodIndex(*declaring_class->GetDexCache()->GetDexFile(), + GetOatMethodIndexFromMethodIndex(declaring_class->GetDexFile(), method->GetDeclaringClass()->GetDexClassDefIndex(), method->GetDexMethodIndex())); - OatFile::OatClass oat_class = OatFile::FindOatClass(*declaring_class->GetDexCache()->GetDexFile(), + OatFile::OatClass oat_class = OatFile::FindOatClass(declaring_class->GetDexFile(), declaring_class->GetDexClassDefIndex(), found); if (!(*found)) { @@ -543,7 +544,7 @@ bool ArtMethod::EqualParameters(Handle<mirror::ObjectArray<mirror::Class>> param } ArrayRef<const uint8_t> ArtMethod::GetQuickenedInfo() { - const DexFile& dex_file = GetDeclaringClass()->GetDexFile(); + const DexFile& dex_file = *GetDexFile(); const OatDexFile* oat_dex_file = dex_file.GetOatDexFile(); if (oat_dex_file == nullptr || (oat_dex_file->GetOatFile() == nullptr)) { return ArrayRef<const uint8_t>(); diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc index fcf6bb25e3..7388c2e307 100644 --- a/runtime/common_runtime_test.cc +++ b/runtime/common_runtime_test.cc @@ -139,7 +139,7 @@ void CommonRuntimeTestImpl::SetUp() { PreRuntimeCreate(); if (!Runtime::Create(options, false)) { LOG(FATAL) << "Failed to create runtime"; - return; + UNREACHABLE(); } PostRuntimeCreate(); runtime_.reset(Runtime::Current()); diff --git a/runtime/common_throws.cc b/runtime/common_throws.cc index 0dc07231b6..62788b14ea 100644 --- a/runtime/common_throws.cc +++ b/runtime/common_throws.cc @@ -717,7 +717,7 @@ void ThrowNullPointerExceptionFromDexPC(bool check_address, uintptr_t addr) { << instr.DumpString(dex_file) << " in " << method->PrettyMethod(); - break; + UNREACHABLE(); } } } diff --git a/runtime/debugger.cc b/runtime/debugger.cc index 4af97f0f35..80140b3aa1 100644 --- a/runtime/debugger.cc +++ b/runtime/debugger.cc @@ -1228,7 +1228,7 @@ size_t Dbg::GetTagWidth(JDWP::JdwpTag tag) { return 8; default: LOG(FATAL) << "Unknown tag " << tag; - return -1; + UNREACHABLE(); } } @@ -2266,7 +2266,7 @@ JDWP::JdwpThreadStatus Dbg::ToJdwpThreadStatus(ThreadState state) { // Don't add a 'default' here so the compiler can spot incompatible enum changes. } LOG(FATAL) << "Unknown thread state: " << state; - return JDWP::TS_ZOMBIE; + UNREACHABLE(); } JDWP::JdwpError Dbg::GetThreadStatus(JDWP::ObjectId thread_id, JDWP::JdwpThreadStatus* pThreadStatus, @@ -3155,7 +3155,7 @@ void Dbg::ProcessDeoptimizationRequest(const DeoptimizationRequest& request) { break; default: LOG(FATAL) << "Unsupported deoptimization request kind " << request.GetKind(); - break; + UNREACHABLE(); } } @@ -3233,7 +3233,7 @@ void Dbg::RequestDeoptimizationLocked(const DeoptimizationRequest& req) { } default: { LOG(FATAL) << "Unknown deoptimization request kind " << req.GetKind(); - break; + UNREACHABLE(); } } } diff --git a/runtime/dex/dex_file_annotations.cc b/runtime/dex/dex_file_annotations.cc index 6434828298..9127a27bc8 100644 --- a/runtime/dex/dex_file_annotations.cc +++ b/runtime/dex/dex_file_annotations.cc @@ -240,7 +240,7 @@ bool SkipAnnotationValue(const DexFile& dex_file, const uint8_t** annotation_ptr break; default: LOG(FATAL) << StringPrintf("Bad annotation element value byte 0x%02x", value_type); - return false; + UNREACHABLE(); } annotation += width; diff --git a/runtime/entrypoints/quick/quick_jni_entrypoints.cc b/runtime/entrypoints/quick/quick_jni_entrypoints.cc index 3c41a8c3b5..5c86bbb39e 100644 --- a/runtime/entrypoints/quick/quick_jni_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_jni_entrypoints.cc @@ -252,7 +252,7 @@ extern uint64_t GenericJniMethodEnd(Thread* self, return 0; default: LOG(FATAL) << "Unexpected return shorty character " << return_shorty_char; - return 0; + UNREACHABLE(); } } } diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc index 8737f3fc28..6deb509427 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc @@ -297,7 +297,7 @@ class QuickArgumentVisitor { case 4: return (6 * GetBytesPerGprSpillLocation(kRuntimeISA)); default: LOG(FATAL) << "Unexpected GPR index: " << gpr_index; - return 0; + UNREACHABLE(); } } #else diff --git a/runtime/gc/allocator/rosalloc.cc b/runtime/gc/allocator/rosalloc.cc index b90a95d802..d4b9fabd0f 100644 --- a/runtime/gc/allocator/rosalloc.cc +++ b/runtime/gc/allocator/rosalloc.cc @@ -286,7 +286,7 @@ void* RosAlloc::AllocPages(Thread* self, size_t num_pages, uint8_t page_map_type break; default: LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(page_map_type); - break; + UNREACHABLE(); } if (kIsDebugBuild) { // Clear the first page since it is not madvised due to the magic number. @@ -325,7 +325,7 @@ size_t RosAlloc::FreePages(Thread* self, void* ptr, bool already_zero) { LOG(FATAL) << "Unreachable - " << __PRETTY_FUNCTION__ << " : " << "pm_idx=" << pm_idx << ", pm_type=" << static_cast<int>(pm_type) << ", ptr=" << std::hex << reinterpret_cast<intptr_t>(ptr); - return 0; + UNREACHABLE(); } // Update the page map and count the number of pages. size_t num_pages = 1; @@ -514,7 +514,7 @@ size_t RosAlloc::FreeInternal(Thread* self, void* ptr) { return FreePages(self, ptr, false); case kPageMapLargeObjectPart: LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(page_map_[pm_idx]); - return 0; + UNREACHABLE(); case kPageMapRunPart: { // Find the beginning of the run. do { @@ -529,11 +529,11 @@ size_t RosAlloc::FreeInternal(Thread* self, void* ptr) { case kPageMapReleased: case kPageMapEmpty: LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(page_map_[pm_idx]); - return 0; + UNREACHABLE(); } default: LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(page_map_[pm_idx]); - return 0; + UNREACHABLE(); } } DCHECK(run != nullptr); @@ -1307,7 +1307,7 @@ size_t RosAlloc::UsableSize(const void* ptr) { case kPageMapEmpty: LOG(FATAL) << "Unreachable - " << __PRETTY_FUNCTION__ << ": pm_idx=" << pm_idx << ", ptr=" << std::hex << reinterpret_cast<intptr_t>(ptr); - break; + UNREACHABLE(); case kPageMapLargeObject: { size_t num_pages = 1; size_t idx = pm_idx + 1; @@ -1321,7 +1321,7 @@ size_t RosAlloc::UsableSize(const void* ptr) { case kPageMapLargeObjectPart: LOG(FATAL) << "Unreachable - " << __PRETTY_FUNCTION__ << ": pm_idx=" << pm_idx << ", ptr=" << std::hex << reinterpret_cast<intptr_t>(ptr); - break; + UNREACHABLE(); case kPageMapRun: case kPageMapRunPart: { // Find the beginning of the run. @@ -1340,10 +1340,9 @@ size_t RosAlloc::UsableSize(const void* ptr) { } default: { LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(page_map_[pm_idx]); - break; + UNREACHABLE(); } } - return 0; } bool RosAlloc::Trim() { @@ -1456,7 +1455,7 @@ void RosAlloc::InspectAll(void (*handler)(void* start, void* end, size_t used_by } case kPageMapLargeObjectPart: LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(pm); - break; + UNREACHABLE(); case kPageMapRun: { // The start of a run. Run* run = reinterpret_cast<Run*>(base_ + i * kPageSize); @@ -1476,10 +1475,10 @@ void RosAlloc::InspectAll(void (*handler)(void* start, void* end, size_t used_by } case kPageMapRunPart: LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(pm); - break; + UNREACHABLE(); default: LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(pm); - break; + UNREACHABLE(); } } } @@ -1809,7 +1808,7 @@ void RosAlloc::Verify() { } case kPageMapLargeObjectPart: LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(pm) << std::endl << DumpPageMap(); - break; + UNREACHABLE(); case kPageMapRun: { // The start of a run. Run* run = reinterpret_cast<Run*>(base_ + i * kPageSize); @@ -1837,7 +1836,7 @@ void RosAlloc::Verify() { // Fall-through. default: LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(pm) << std::endl << DumpPageMap(); - break; + UNREACHABLE(); } } } @@ -2030,7 +2029,7 @@ size_t RosAlloc::ReleasePages() { break; // Skip. default: LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(pm); - break; + UNREACHABLE(); } } return reclaimed_bytes; @@ -2138,7 +2137,7 @@ void RosAlloc::DumpStats(std::ostream& os) { case kPageMapLargeObjectPart: LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(pm) << std::endl << DumpPageMap(); - break; + UNREACHABLE(); case kPageMapRun: { Run* run = reinterpret_cast<Run*>(base_ + i * kPageSize); size_t idx = run->size_bracket_idx_; @@ -2157,7 +2156,7 @@ void RosAlloc::DumpStats(std::ostream& os) { default: LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(pm) << std::endl << DumpPageMap(); - break; + UNREACHABLE(); } } os << "RosAlloc stats:\n"; diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc index 4359bea421..f767360066 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -2169,7 +2169,7 @@ void Heap::TransitionCollector(CollectorType collector_type) { default: { LOG(FATAL) << "Attempted to transition to invalid collector type " << static_cast<size_t>(collector_type); - break; + UNREACHABLE(); } } ChangeCollector(collector_type); diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc index 5f131d38a8..c772bdab18 100644 --- a/runtime/gc/space/image_space.cc +++ b/runtime/gc/space/image_space.cc @@ -2322,9 +2322,9 @@ void ImageSpace::Dump(std::ostream& os) const { } std::string ImageSpace::GetMultiImageBootClassPath( - const std::vector<const char*>& dex_locations, - const std::vector<const char*>& oat_filenames, - const std::vector<const char*>& image_filenames) { + const std::vector<std::string>& dex_locations, + const std::vector<std::string>& oat_filenames, + const std::vector<std::string>& image_filenames) { DCHECK_GT(oat_filenames.size(), 1u); // If the image filename was adapted (e.g., for our tests), we need to change this here, // too, but need to strip all path components (they will be re-established when loading). diff --git a/runtime/gc/space/image_space.h b/runtime/gc/space/image_space.h index b940d88de8..aa45ed3952 100644 --- a/runtime/gc/space/image_space.h +++ b/runtime/gc/space/image_space.h @@ -128,9 +128,9 @@ class ImageSpace : public MemMapSpace { const std::string& boot_classpath, std::vector<std::string>* image_filenames); - static std::string GetMultiImageBootClassPath(const std::vector<const char*>& dex_locations, - const std::vector<const char*>& oat_filenames, - const std::vector<const char*>& image_filenames); + static std::string GetMultiImageBootClassPath(const std::vector<std::string>& dex_locations, + const std::vector<std::string>& oat_filenames, + const std::vector<std::string>& image_filenames); // Returns true if the dex checksums in the given oat file match the // checksums of the original dex files on disk. This is intended to be used diff --git a/runtime/gc/space/space.cc b/runtime/gc/space/space.cc index a8bd7b816e..e7961eb256 100644 --- a/runtime/gc/space/space.cc +++ b/runtime/gc/space/space.cc @@ -63,7 +63,7 @@ BumpPointerSpace* Space::AsBumpPointerSpace() { RegionSpace* Space::AsRegionSpace() { LOG(FATAL) << "Unreachable"; - return nullptr; + UNREACHABLE(); } AllocSpace* Space::AsAllocSpace() { diff --git a/runtime/hidden_api.cc b/runtime/hidden_api.cc index d3df7fd38d..6cdba73c30 100644 --- a/runtime/hidden_api.cc +++ b/runtime/hidden_api.cc @@ -280,11 +280,15 @@ uint32_t GetDexFlags(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) { uint32_t flags = kInvalidDexFlags; DCHECK(!AreValidDexFlags(flags)); + // Use the non-obsolete method to avoid DexFile mismatch between + // the method index and the declaring class. + uint32_t method_index = method->GetNonObsoleteMethod()->GetDexMethodIndex(); + ClassAccessor accessor(declaring_class->GetDexFile(), *class_def, /* parse_hiddenapi_class_data= */ true); auto fn_visit = [&](const ClassAccessor::Method& dex_method) { - if (dex_method.GetIndex() == method->GetDexMethodIndex()) { + if (dex_method.GetIndex() == method_index) { flags = dex_method.GetHiddenapiFlags(); } }; diff --git a/runtime/hprof/hprof.cc b/runtime/hprof/hprof.cc index 832bacbb3d..3abe4c529a 100644 --- a/runtime/hprof/hprof.cc +++ b/runtime/hprof/hprof.cc @@ -1051,7 +1051,7 @@ void Hprof::MarkRootObject(const mirror::Object* obj, jobject jni_obj, HprofHeap case HPROF_ROOT_REFERENCE_CLEANUP: case HPROF_UNREACHABLE: LOG(FATAL) << "obsolete tag " << static_cast<int>(heap_tag); - break; + UNREACHABLE(); } ++objects_in_segment_; diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc index fe6154792c..e52a1c90d3 100644 --- a/runtime/interpreter/interpreter_common.cc +++ b/runtime/interpreter/interpreter_common.cc @@ -1876,7 +1876,7 @@ void RecordArrayElementsInTransaction(ObjPtr<mirror::Array> array, int32_t count default: LOG(FATAL) << "Unsupported primitive type " << primitive_component_type << " in fill-array-data"; - break; + UNREACHABLE(); } } diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h index 1c724212f5..bf84227560 100644 --- a/runtime/interpreter/interpreter_common.h +++ b/runtime/interpreter/interpreter_common.h @@ -44,7 +44,7 @@ #include "handle_scope-inl.h" #include "interpreter_mterp_impl.h" #include "interpreter_switch_impl.h" -#include "jit/jit-inl.h" +#include "jit/jit.h" #include "mirror/call_site.h" #include "mirror/class-inl.h" #include "mirror/dex_cache.h" diff --git a/runtime/interpreter/interpreter_switch_impl-inl.h b/runtime/interpreter/interpreter_switch_impl-inl.h index aec2aa2564..94cb3de9f8 100644 --- a/runtime/interpreter/interpreter_switch_impl-inl.h +++ b/runtime/interpreter/interpreter_switch_impl-inl.h @@ -26,7 +26,7 @@ #include "dex/dex_instruction_list.h" #include "experimental_flags.h" #include "interpreter_common.h" -#include "jit/jit-inl.h" +#include "jit/jit.h" #include "jvalue-inl.h" #include "mirror/string-alloc-inl.h" #include "nth_caller_visitor.h" diff --git a/runtime/interpreter/mterp/mterp.cc b/runtime/interpreter/mterp/mterp.cc index 0633f5bb21..912c44463f 100644 --- a/runtime/interpreter/mterp/mterp.cc +++ b/runtime/interpreter/mterp/mterp.cc @@ -887,11 +887,9 @@ extern "C" ssize_t MterpSetUpHotnessCountdown(ArtMethod* method, int32_t countdown_value = jit::kJitHotnessDisabled; jit::Jit* jit = Runtime::Current()->GetJit(); if (jit != nullptr) { - // We need to add batch size to ensure the threshold gets passed even after rounding. - constexpr int32_t kBatchSize = jit::kJitSamplesBatchSize; - int32_t warm_threshold = static_cast<int32_t>(jit->WarmMethodThreshold()) + kBatchSize; - int32_t hot_threshold = static_cast<int32_t>(jit->HotMethodThreshold()) + kBatchSize; - int32_t osr_threshold = static_cast<int32_t>(jit->OSRMethodThreshold()) + kBatchSize; + int32_t warm_threshold = jit->WarmMethodThreshold(); + int32_t hot_threshold = jit->HotMethodThreshold(); + int32_t osr_threshold = jit->OSRMethodThreshold(); if (hotness_count < warm_threshold) { countdown_value = warm_threshold - hotness_count; } else if (hotness_count < hot_threshold) { diff --git a/runtime/jdwp/jdwp_event.cc b/runtime/jdwp/jdwp_event.cc index 0353ea7462..7ce70cb3d4 100644 --- a/runtime/jdwp/jdwp_event.cc +++ b/runtime/jdwp/jdwp_event.cc @@ -554,7 +554,7 @@ static bool ModsMatch(JdwpEvent* pEvent, const ModBasket& basket) break; default: LOG(FATAL) << "unknown mod kind " << pMod->modKind; - break; + UNREACHABLE(); } } return true; diff --git a/runtime/jdwp/jdwp_request.cc b/runtime/jdwp/jdwp_request.cc index 6af267e674..a77962e2fa 100644 --- a/runtime/jdwp/jdwp_request.cc +++ b/runtime/jdwp/jdwp_request.cc @@ -70,7 +70,7 @@ uint64_t Request::ReadValue(size_t width) { case 2: value = Read2BE(); break; case 4: value = Read4BE(); break; case 8: value = Read8BE(); break; - default: LOG(FATAL) << width; break; + default: LOG(FATAL) << width; } return value; } diff --git a/runtime/jit/jit-inl.h b/runtime/jit/jit-inl.h deleted file mode 100644 index 80324addcb..0000000000 --- a/runtime/jit/jit-inl.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2018 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. - */ - -#ifndef ART_RUNTIME_JIT_JIT_INL_H_ -#define ART_RUNTIME_JIT_JIT_INL_H_ - -#include "jit/jit.h" - -#include "art_method.h" -#include "base/bit_utils.h" -#include "thread.h" -#include "runtime-inl.h" - -namespace art { -namespace jit { - -inline bool Jit::ShouldUsePriorityThreadWeight(Thread* self) { - return self->IsJitSensitiveThread() && Runtime::Current()->InJankPerceptibleProcessState(); -} - -inline void Jit::AddSamples(Thread* self, - ArtMethod* method, - uint16_t samples, - bool with_backedges) { - if (Jit::ShouldUsePriorityThreadWeight(self)) { - samples *= PriorityThreadWeight(); - } - uint32_t old_count = method->GetCounter(); - uint32_t new_count = old_count + samples; - - // The full check is fairly expensive so we just add to hotness most of the time, - // and we do the full check only when some of the higher bits of the count change. - // NB: The method needs to see the transitions of the counter past the thresholds. - uint32_t old_batch = RoundDown(old_count, kJitSamplesBatchSize); // Clear lower bits. - uint32_t new_batch = RoundDown(new_count, kJitSamplesBatchSize); // Clear lower bits. - if (UNLIKELY(old_batch == 0)) { - // For low sample counts, we check every time (which is important for tests). - if (!MaybeCompileMethod(self, method, old_count, new_count, with_backedges)) { - // Tests may check that the counter is 0 for methods that we never compile. - return; // Ignore the samples for now and retry later. - } - } else if (UNLIKELY(old_batch != new_batch)) { - // For high sample counts, we check only when we move past the batch boundary. - if (!MaybeCompileMethod(self, method, old_batch, new_batch, with_backedges)) { - // OSR compilation will ignore the samples if they don't have backedges. - return; // Ignore the samples for now and retry later. - } - } - - method->SetCounter(new_count); -} - -} // namespace jit -} // namespace art - -#endif // ART_RUNTIME_JIT_JIT_INL_H_ diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc index 2fc418b7d8..4a3ef07819 100644 --- a/runtime/jit/jit.cc +++ b/runtime/jit/jit.cc @@ -28,7 +28,6 @@ #include "debugger.h" #include "entrypoints/runtime_asm_entrypoints.h" #include "interpreter/interpreter.h" -#include "jit-inl.h" #include "jit_code_cache.h" #include "jni/java_vm_ext.h" #include "mirror/method_handle_impl.h" @@ -150,6 +149,10 @@ JitOptions* JitOptions::CreateFromRuntimeArguments(const RuntimeArgumentMap& opt return jit_options; } +bool Jit::ShouldUsePriorityThreadWeight(Thread* self) { + return self->IsJitSensitiveThread() && Runtime::Current()->InJankPerceptibleProcessState(); +} + void Jit::DumpInfo(std::ostream& os) { code_cache_->Dump(os); cumulative_timings_.Dump(os); @@ -625,25 +628,21 @@ static bool IgnoreSamplesForMethod(ArtMethod* method) REQUIRES_SHARED(Locks::mut return false; } -bool Jit::MaybeCompileMethod(Thread* self, - ArtMethod* method, - uint32_t old_count, - uint32_t new_count, - bool with_backedges) { +void Jit::AddSamples(Thread* self, ArtMethod* method, uint16_t count, bool with_backedges) { if (thread_pool_ == nullptr) { // Should only see this when shutting down, starting up, or in zygote, which doesn't // have a thread pool. DCHECK(Runtime::Current()->IsShuttingDown(self) || !Runtime::Current()->IsFinishedStarting() || Runtime::Current()->IsZygote()); - return false; + return; } if (IgnoreSamplesForMethod(method)) { - return false; + return; } if (HotMethodThreshold() == 0) { // Tests might request JIT on first use (compiled synchronously in the interpreter). - return false; + return; } DCHECK(thread_pool_ != nullptr); DCHECK_GT(WarmMethodThreshold(), 0); @@ -652,9 +651,15 @@ bool Jit::MaybeCompileMethod(Thread* self, DCHECK_GE(PriorityThreadWeight(), 1); DCHECK_LE(PriorityThreadWeight(), HotMethodThreshold()); - if (old_count < WarmMethodThreshold() && new_count >= WarmMethodThreshold()) { - // Note: Native method have no "warm" state or profiling info. - if (!method->IsNative() && method->GetProfilingInfo(kRuntimePointerSize) == nullptr) { + uint16_t starting_count = method->GetCounter(); + if (Jit::ShouldUsePriorityThreadWeight(self)) { + count *= PriorityThreadWeight(); + } + uint32_t new_count = starting_count + count; + // Note: Native method have no "warm" state or profiling info. + if (LIKELY(!method->IsNative()) && starting_count < WarmMethodThreshold()) { + if ((new_count >= WarmMethodThreshold()) && + (method->GetProfilingInfo(kRuntimePointerSize) == nullptr)) { bool success = ProfilingInfo::Create(self, method, /* retry_allocation= */ false); if (success) { VLOG(jit) << "Start profiling " << method->PrettyMethod(); @@ -664,7 +669,7 @@ bool Jit::MaybeCompileMethod(Thread* self, // Calling ProfilingInfo::Create might put us in a suspended state, which could // lead to the thread pool being deleted when we are shutting down. DCHECK(Runtime::Current()->IsShuttingDown(self)); - return false; + return; } if (!success) { @@ -673,26 +678,31 @@ bool Jit::MaybeCompileMethod(Thread* self, thread_pool_->AddTask(self, new JitCompileTask(method, JitCompileTask::kAllocateProfile)); } } - } - if (UseJitCompilation()) { - if (old_count < HotMethodThreshold() && new_count >= HotMethodThreshold()) { - if (!code_cache_->ContainsPc(method->GetEntryPointFromQuickCompiledCode())) { + // Avoid jumping more than one state at a time. + new_count = std::min(new_count, static_cast<uint32_t>(HotMethodThreshold() - 1)); + } else if (UseJitCompilation()) { + if (starting_count < HotMethodThreshold()) { + if ((new_count >= HotMethodThreshold()) && + !code_cache_->ContainsPc(method->GetEntryPointFromQuickCompiledCode())) { DCHECK(thread_pool_ != nullptr); thread_pool_->AddTask(self, new JitCompileTask(method, JitCompileTask::kCompile)); } - } - if (old_count < OSRMethodThreshold() && new_count >= OSRMethodThreshold()) { + // Avoid jumping more than one state at a time. + new_count = std::min(new_count, static_cast<uint32_t>(OSRMethodThreshold() - 1)); + } else if (starting_count < OSRMethodThreshold()) { if (!with_backedges) { - return false; + // If the samples don't contain any back edge, we don't increment the hotness. + return; } DCHECK(!method->IsNative()); // No back edges reported for native methods. - if (!code_cache_->IsOsrCompiled(method)) { + if ((new_count >= OSRMethodThreshold()) && !code_cache_->IsOsrCompiled(method)) { DCHECK(thread_pool_ != nullptr); thread_pool_->AddTask(self, new JitCompileTask(method, JitCompileTask::kCompileOsr)); } } } - return true; + // Update hotness counter + method->SetCounter(new_count); } class ScopedSetRuntimeThread { diff --git a/runtime/jit/jit.h b/runtime/jit/jit.h index 2027719bd9..e12b032feb 100644 --- a/runtime/jit/jit.h +++ b/runtime/jit/jit.h @@ -47,7 +47,6 @@ static constexpr int16_t kJitHotnessDisabled = -2; // At what priority to schedule jit threads. 9 is the lowest foreground priority on device. // See android/os/Process.java. static constexpr int kJitPoolThreadPthreadDefaultPriority = 9; -static constexpr uint32_t kJitSamplesBatchSize = 32; // Must be power of 2. class JitOptions { public: @@ -218,10 +217,7 @@ class Jit { void MethodEntered(Thread* thread, ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_); - ALWAYS_INLINE void AddSamples(Thread* self, - ArtMethod* method, - uint16_t samples, - bool with_backedges) + void AddSamples(Thread* self, ArtMethod* method, uint16_t samples, bool with_backedges) REQUIRES_SHARED(Locks::mutator_lock_); void InvokeVirtualOrInterface(ObjPtr<mirror::Object> this_object, @@ -295,15 +291,6 @@ class Jit { private: Jit(JitCodeCache* code_cache, JitOptions* options); - // Compile the method if the number of samples passes a threshold. - // Returns false if we can not compile now - don't increment the counter and retry later. - bool MaybeCompileMethod(Thread* self, - ArtMethod* method, - uint32_t old_count, - uint32_t new_count, - bool with_backedges) - REQUIRES_SHARED(Locks::mutator_lock_); - static bool BindCompilerMethods(std::string* error_msg); // JIT compiler diff --git a/runtime/jni/check_jni.cc b/runtime/jni/check_jni.cc index 48f99815fd..727929930b 100644 --- a/runtime/jni/check_jni.cc +++ b/runtime/jni/check_jni.cc @@ -880,7 +880,7 @@ class ScopedCheck { break; case kDirectByteBuffer: UNIMPLEMENTED(FATAL); - break; + UNREACHABLE(); case kString: okay = obj->GetClass()->IsStringClass(); break; @@ -2945,7 +2945,7 @@ class CheckJNI { break; case Primitive::kPrimVoid: LOG(FATAL) << "Unexpected type: " << type; - break; + UNREACHABLE(); } if (sc.Check(soa, false, result_check, &result)) { return result; @@ -3031,7 +3031,7 @@ class CheckJNI { break; case Primitive::kPrimVoid: LOG(FATAL) << "Unexpected type: " << type; - break; + UNREACHABLE(); } JniValueType result; result.V = nullptr; diff --git a/runtime/mirror/object.cc b/runtime/mirror/object.cc index 9b38576fc5..f6adc800e4 100644 --- a/runtime/mirror/object.cc +++ b/runtime/mirror/object.cc @@ -225,11 +225,10 @@ int32_t Object::IdentityHashCode() { } default: { LOG(FATAL) << "Invalid state during hashcode " << lw.GetState(); - break; + UNREACHABLE(); } } } - UNREACHABLE(); } void Object::CheckFieldAssignmentImpl(MemberOffset field_offset, ObjPtr<Object> new_value) { diff --git a/runtime/monitor.cc b/runtime/monitor.cc index 647928391b..7240357979 100644 --- a/runtime/monitor.cc +++ b/runtime/monitor.cc @@ -168,11 +168,11 @@ bool Monitor::Install(Thread* self) { } case LockWord::kUnlocked: { LOG(FATAL) << "Inflating unlocked lock word"; - break; + UNREACHABLE(); } default: { LOG(FATAL) << "Invalid monitor state " << lw.GetState(); - return false; + UNREACHABLE(); } } LockWord fat(this, lw.GCState()); @@ -1236,7 +1236,7 @@ bool Monitor::MonitorExit(Thread* self, mirror::Object* obj) { } default: { LOG(FATAL) << "Invalid monitor state " << lock_word.GetState(); - return false; + UNREACHABLE(); } } } @@ -1280,7 +1280,7 @@ void Monitor::Wait(Thread* self, mirror::Object *obj, int64_t ms, int32_t ns, case LockWord::kFatLocked: // Unreachable given the loop condition above. Fall-through. default: { LOG(FATAL) << "Invalid monitor state " << lock_word.GetState(); - return; + UNREACHABLE(); } } } @@ -1320,7 +1320,7 @@ void Monitor::DoNotify(Thread* self, mirror::Object* obj, bool notify_all) { } default: { LOG(FATAL) << "Invalid monitor state " << lock_word.GetState(); - return; + UNREACHABLE(); } } } diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index c1ccd33774..5c5523d9c8 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -1920,7 +1920,7 @@ OatFile::OatClass::OatClass(const OatFile* oat_file, } case kOatClassMax: { LOG(FATAL) << "Invalid OatClassType " << type_; - break; + UNREACHABLE(); } } } diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc index d4e3d54a99..0d570c39ae 100644 --- a/runtime/quick_exception_handler.cc +++ b/runtime/quick_exception_handler.cc @@ -227,7 +227,7 @@ void QuickExceptionHandler::FindCatch(ObjPtr<mirror::Throwable> exception) { LOG(INFO) << "Handler is upcall"; } if (handler_method_ != nullptr) { - const DexFile* dex_file = handler_method_->GetDeclaringClass()->GetDexCache()->GetDexFile(); + const DexFile* dex_file = handler_method_->GetDexFile(); int line_number = annotations::GetLineNumFromPC(dex_file, handler_method_, handler_dex_pc_); LOG(INFO) << "Handler: " << handler_method_->PrettyMethod() << " (line: " << line_number << ")"; diff --git a/runtime/runtime.cc b/runtime/runtime.cc index 9cbbd4172d..ab79b9e1a0 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -1241,7 +1241,6 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) { } case JdwpProvider::kUnset: { LOG(FATAL) << "Illegal jdwp provider " << jdwp_provider_ << " was not filtered out!"; - break; } } callbacks_->AddThreadLifecycleCallback(Dbg::GetThreadLifecycleCallback()); @@ -1856,7 +1855,7 @@ int32_t Runtime::GetStat(int kind) { return 0; // backward compatibility default: LOG(FATAL) << "Unknown statistic " << kind; - return -1; // unreachable + UNREACHABLE(); } } diff --git a/runtime/thread.cc b/runtime/thread.cc index 33cd9bbb67..6c41ae42b7 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -1952,8 +1952,7 @@ struct StackDumpVisitor : public MonitorObjectsStackVisitor { override REQUIRES_SHARED(Locks::mutator_lock_) { m = m->GetInterfaceMethodIfProxy(kRuntimePointerSize); - ObjPtr<mirror::Class> c = m->GetDeclaringClass(); - ObjPtr<mirror::DexCache> dex_cache = c->GetDexCache(); + ObjPtr<mirror::DexCache> dex_cache = m->GetDexCache(); int line_number = -1; if (dex_cache != nullptr) { // be tolerant of bad input const DexFile* dex_file = dex_cache->GetDexFile(); diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc index 23e57a2f21..4bbd81a70d 100644 --- a/runtime/thread_list.cc +++ b/runtime/thread_list.cc @@ -1561,7 +1561,7 @@ uint32_t ThreadList::AllocThreadId(Thread* self) { } } LOG(FATAL) << "Out of internal thread ids"; - return 0; + UNREACHABLE(); } void ThreadList::ReleaseThreadId(Thread* self, uint32_t id) { diff --git a/runtime/transaction.cc b/runtime/transaction.cc index e4bf447a6f..62482fd898 100644 --- a/runtime/transaction.cc +++ b/runtime/transaction.cc @@ -531,7 +531,7 @@ void Transaction::ObjectLog::UndoFieldWrite(mirror::Object* obj, break; default: LOG(FATAL) << "Unknown value kind " << static_cast<int>(field_value.kind); - break; + UNREACHABLE(); } } @@ -558,7 +558,7 @@ void Transaction::InternStringLog::Undo(InternTable* intern_table) const { break; default: LOG(FATAL) << "Unknown interned string kind"; - break; + UNREACHABLE(); } break; } @@ -572,13 +572,13 @@ void Transaction::InternStringLog::Undo(InternTable* intern_table) const { break; default: LOG(FATAL) << "Unknown interned string kind"; - break; + UNREACHABLE(); } break; } default: LOG(FATAL) << "Unknown interned string op"; - break; + UNREACHABLE(); } } @@ -669,9 +669,10 @@ void Transaction::ArrayLog::UndoArrayWrite(mirror::Array* array, break; case Primitive::kPrimNot: LOG(FATAL) << "ObjectArray should be treated as Object"; - break; + UNREACHABLE(); default: LOG(FATAL) << "Unsupported type " << array_type; + UNREACHABLE(); } } diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc index 5300e2d389..cde885c288 100644 --- a/runtime/well_known_classes.cc +++ b/runtime/well_known_classes.cc @@ -276,7 +276,7 @@ ArtMethod* WellKnownClasses::StringInitToStringFactory(ArtMethod* string_init) { STRING_INIT_LIST(TO_STRING_FACTORY) #undef TO_STRING_FACTORY LOG(FATAL) << "Could not find StringFactory method for String.<init>"; - return nullptr; + UNREACHABLE(); } uint32_t WellKnownClasses::StringInitToEntryPoint(ArtMethod* string_init) { @@ -288,7 +288,7 @@ uint32_t WellKnownClasses::StringInitToEntryPoint(ArtMethod* string_init) { STRING_INIT_LIST(TO_ENTRY_POINT) #undef TO_ENTRY_POINT LOG(FATAL) << "Could not find StringFactory method for String.<init>"; - return 0; + UNREACHABLE(); } #undef STRING_INIT_LIST diff --git a/test/674-hiddenapi/api-blacklist.txt b/test/674-hiddenapi/api-blacklist.txt deleted file mode 100644 index 4a67fb8ebf..0000000000 --- a/test/674-hiddenapi/api-blacklist.txt +++ /dev/null @@ -1,27 +0,0 @@ -LNullaryConstructorBlacklist;-><init>()V -LParentClass;->fieldPublicBlacklist:I -LParentClass;->fieldPublicBlacklistB:I -LParentClass;->fieldPackageBlacklist:I -LParentClass;->fieldProtectedBlacklist:I -LParentClass;->fieldPrivateBlacklist:I -LParentClass;->fieldPublicStaticBlacklist:I -LParentClass;->fieldPublicStaticBlacklistB:I -LParentClass;->fieldPackageStaticBlacklist:I -LParentClass;->fieldProtectedStaticBlacklist:I -LParentClass;->fieldPrivateStaticBlacklist:I -LParentClass;->methodPublicBlacklist()I -LParentClass;->methodPackageBlacklist()I -LParentClass;->methodProtectedBlacklist()I -LParentClass;->methodPrivateBlacklist()I -LParentClass;->methodPublicStaticBlacklist()I -LParentClass;->methodPackageStaticBlacklist()I -LParentClass;->methodProtectedStaticBlacklist()I -LParentClass;->methodPrivateStaticBlacklist()I -LParentClass;-><init>(IC)V -LParentClass;-><init>(FC)V -LParentClass;-><init>(JC)V -LParentClass;-><init>(DC)V -LParentInterface;->fieldPublicStaticBlacklist:I -LParentInterface;->methodPublicBlacklist()I -LParentInterface;->methodPublicStaticBlacklist()I -LParentInterface;->methodPublicDefaultBlacklist()I
\ No newline at end of file diff --git a/test/674-hiddenapi/api-dark-greylist.txt b/test/674-hiddenapi/api-dark-greylist.txt deleted file mode 100644 index e010a0a07f..0000000000 --- a/test/674-hiddenapi/api-dark-greylist.txt +++ /dev/null @@ -1,27 +0,0 @@ -LNullaryConstructorDarkGreylist;-><init>()V -LParentClass;->fieldPublicDarkGreylist:I -LParentClass;->fieldPublicDarkGreylistB:I -LParentClass;->fieldPackageDarkGreylist:I -LParentClass;->fieldProtectedDarkGreylist:I -LParentClass;->fieldPrivateDarkGreylist:I -LParentClass;->fieldPublicStaticDarkGreylist:I -LParentClass;->fieldPublicStaticDarkGreylistB:I -LParentClass;->fieldPackageStaticDarkGreylist:I -LParentClass;->fieldProtectedStaticDarkGreylist:I -LParentClass;->fieldPrivateStaticDarkGreylist:I -LParentClass;->methodPublicDarkGreylist()I -LParentClass;->methodPackageDarkGreylist()I -LParentClass;->methodProtectedDarkGreylist()I -LParentClass;->methodPrivateDarkGreylist()I -LParentClass;->methodPublicStaticDarkGreylist()I -LParentClass;->methodPackageStaticDarkGreylist()I -LParentClass;->methodProtectedStaticDarkGreylist()I -LParentClass;->methodPrivateStaticDarkGreylist()I -LParentClass;-><init>(IB)V -LParentClass;-><init>(FB)V -LParentClass;-><init>(JB)V -LParentClass;-><init>(DB)V -LParentInterface;->fieldPublicStaticDarkGreylist:I -LParentInterface;->methodPublicDarkGreylist()I -LParentInterface;->methodPublicStaticDarkGreylist()I -LParentInterface;->methodPublicDefaultDarkGreylist()I
\ No newline at end of file diff --git a/test/674-hiddenapi/api-light-greylist.txt b/test/674-hiddenapi/api-light-greylist.txt deleted file mode 100644 index 4be793fd0c..0000000000 --- a/test/674-hiddenapi/api-light-greylist.txt +++ /dev/null @@ -1,27 +0,0 @@ -LNullaryConstructorLightGreylist;-><init>()V -LParentClass;->fieldPublicLightGreylist:I -LParentClass;->fieldPublicLightGreylistB:I -LParentClass;->fieldPackageLightGreylist:I -LParentClass;->fieldProtectedLightGreylist:I -LParentClass;->fieldPrivateLightGreylist:I -LParentClass;->fieldPublicStaticLightGreylist:I -LParentClass;->fieldPublicStaticLightGreylistB:I -LParentClass;->fieldPackageStaticLightGreylist:I -LParentClass;->fieldProtectedStaticLightGreylist:I -LParentClass;->fieldPrivateStaticLightGreylist:I -LParentClass;->methodPublicLightGreylist()I -LParentClass;->methodPackageLightGreylist()I -LParentClass;->methodProtectedLightGreylist()I -LParentClass;->methodPrivateLightGreylist()I -LParentClass;->methodPublicStaticLightGreylist()I -LParentClass;->methodPackageStaticLightGreylist()I -LParentClass;->methodProtectedStaticLightGreylist()I -LParentClass;->methodPrivateStaticLightGreylist()I -LParentClass;-><init>(IZ)V -LParentClass;-><init>(FZ)V -LParentClass;-><init>(JZ)V -LParentClass;-><init>(DZ)V -LParentInterface;->fieldPublicStaticLightGreylist:I -LParentInterface;->methodPublicLightGreylist()I -LParentInterface;->methodPublicStaticLightGreylist()I -LParentInterface;->methodPublicDefaultLightGreylist()I
\ No newline at end of file diff --git a/test/674-hiddenapi/hiddenapi-flags.csv b/test/674-hiddenapi/hiddenapi-flags.csv new file mode 100644 index 0000000000..d875bdfeea --- /dev/null +++ b/test/674-hiddenapi/hiddenapi-flags.csv @@ -0,0 +1,81 @@ +LNullaryConstructorBlacklist;-><init>()V,blacklist +LNullaryConstructorDarkGreylist;-><init>()V,greylist-max-o +LNullaryConstructorLightGreylist;-><init>()V,greylist +LParentClass;->fieldPackageBlacklist:I,blacklist +LParentClass;->fieldPackageDarkGreylist:I,greylist-max-o +LParentClass;->fieldPackageLightGreylist:I,greylist +LParentClass;->fieldPackageStaticBlacklist:I,blacklist +LParentClass;->fieldPackageStaticDarkGreylist:I,greylist-max-o +LParentClass;->fieldPackageStaticLightGreylist:I,greylist +LParentClass;->fieldPrivateBlacklist:I,blacklist +LParentClass;->fieldPrivateDarkGreylist:I,greylist-max-o +LParentClass;->fieldPrivateLightGreylist:I,greylist +LParentClass;->fieldPrivateStaticBlacklist:I,blacklist +LParentClass;->fieldPrivateStaticDarkGreylist:I,greylist-max-o +LParentClass;->fieldPrivateStaticLightGreylist:I,greylist +LParentClass;->fieldProtectedBlacklist:I,blacklist +LParentClass;->fieldProtectedDarkGreylist:I,greylist-max-o +LParentClass;->fieldProtectedLightGreylist:I,greylist +LParentClass;->fieldProtectedStaticBlacklist:I,blacklist +LParentClass;->fieldProtectedStaticDarkGreylist:I,greylist-max-o +LParentClass;->fieldProtectedStaticLightGreylist:I,greylist +LParentClass;->fieldPublicBlacklistB:I,blacklist +LParentClass;->fieldPublicBlacklist:I,blacklist +LParentClass;->fieldPublicDarkGreylistB:I,greylist-max-o +LParentClass;->fieldPublicDarkGreylist:I,greylist-max-o +LParentClass;->fieldPublicLightGreylistB:I,greylist +LParentClass;->fieldPublicLightGreylist:I,greylist +LParentClass;->fieldPublicStaticBlacklistB:I,blacklist +LParentClass;->fieldPublicStaticBlacklist:I,blacklist +LParentClass;->fieldPublicStaticDarkGreylistB:I,greylist-max-o +LParentClass;->fieldPublicStaticDarkGreylist:I,greylist-max-o +LParentClass;->fieldPublicStaticLightGreylistB:I,greylist +LParentClass;->fieldPublicStaticLightGreylist:I,greylist +LParentClass;-><init>(DB)V,greylist-max-o +LParentClass;-><init>(DC)V,blacklist +LParentClass;-><init>(DZ)V,greylist +LParentClass;-><init>(FB)V,greylist-max-o +LParentClass;-><init>(FC)V,blacklist +LParentClass;-><init>(FZ)V,greylist +LParentClass;-><init>(IB)V,greylist-max-o +LParentClass;-><init>(IC)V,blacklist +LParentClass;-><init>(IZ)V,greylist +LParentClass;-><init>(JB)V,greylist-max-o +LParentClass;-><init>(JC)V,blacklist +LParentClass;-><init>(JZ)V,greylist +LParentClass;->methodPackageBlacklist()I,blacklist +LParentClass;->methodPackageDarkGreylist()I,greylist-max-o +LParentClass;->methodPackageLightGreylist()I,greylist +LParentClass;->methodPackageStaticBlacklist()I,blacklist +LParentClass;->methodPackageStaticDarkGreylist()I,greylist-max-o +LParentClass;->methodPackageStaticLightGreylist()I,greylist +LParentClass;->methodPrivateBlacklist()I,blacklist +LParentClass;->methodPrivateDarkGreylist()I,greylist-max-o +LParentClass;->methodPrivateLightGreylist()I,greylist +LParentClass;->methodPrivateStaticBlacklist()I,blacklist +LParentClass;->methodPrivateStaticDarkGreylist()I,greylist-max-o +LParentClass;->methodPrivateStaticLightGreylist()I,greylist +LParentClass;->methodProtectedBlacklist()I,blacklist +LParentClass;->methodProtectedDarkGreylist()I,greylist-max-o +LParentClass;->methodProtectedLightGreylist()I,greylist +LParentClass;->methodProtectedStaticBlacklist()I,blacklist +LParentClass;->methodProtectedStaticDarkGreylist()I,greylist-max-o +LParentClass;->methodProtectedStaticLightGreylist()I,greylist +LParentClass;->methodPublicBlacklist()I,blacklist +LParentClass;->methodPublicDarkGreylist()I,greylist-max-o +LParentClass;->methodPublicLightGreylist()I,greylist +LParentClass;->methodPublicStaticBlacklist()I,blacklist +LParentClass;->methodPublicStaticDarkGreylist()I,greylist-max-o +LParentClass;->methodPublicStaticLightGreylist()I,greylist +LParentInterface;->fieldPublicStaticBlacklist:I,blacklist +LParentInterface;->fieldPublicStaticDarkGreylist:I,greylist-max-o +LParentInterface;->fieldPublicStaticLightGreylist:I,greylist +LParentInterface;->methodPublicBlacklist()I,blacklist +LParentInterface;->methodPublicDarkGreylist()I,greylist-max-o +LParentInterface;->methodPublicDefaultBlacklist()I,blacklist +LParentInterface;->methodPublicDefaultDarkGreylist()I,greylist-max-o +LParentInterface;->methodPublicDefaultLightGreylist()I,greylist +LParentInterface;->methodPublicLightGreylist()I,greylist +LParentInterface;->methodPublicStaticBlacklist()I,blacklist +LParentInterface;->methodPublicStaticDarkGreylist()I,greylist-max-o +LParentInterface;->methodPublicStaticLightGreylist()I,greylist diff --git a/test/999-redefine-hiddenapi/api-blacklist.txt b/test/999-redefine-hiddenapi/api-blacklist.txt deleted file mode 100644 index 63e37aa757..0000000000 --- a/test/999-redefine-hiddenapi/api-blacklist.txt +++ /dev/null @@ -1,2 +0,0 @@ -Lart/Test999;->foo()V -Lart/Test999;->bar:I diff --git a/test/999-redefine-hiddenapi/hiddenapi-flags.csv b/test/999-redefine-hiddenapi/hiddenapi-flags.csv new file mode 100644 index 0000000000..7f632d38ce --- /dev/null +++ b/test/999-redefine-hiddenapi/hiddenapi-flags.csv @@ -0,0 +1,2 @@ +Lart/Test999;->foo()V,blacklist +Lart/Test999;->bar:I,blacklist diff --git a/test/999-redefine-hiddenapi/src-redefine/gen.sh b/test/999-redefine-hiddenapi/src-redefine/gen.sh index f78a025265..b5e2aea0bb 100755 --- a/test/999-redefine-hiddenapi/src-redefine/gen.sh +++ b/test/999-redefine-hiddenapi/src-redefine/gen.sh @@ -25,7 +25,7 @@ CLASS="art/Test999" d8 --output . "$TMP/${CLASS}.class" && hiddenapi encode --input-dex="$TMP/classes.dex" \ --output-dex="$TMP/classes-hiddenapi.dex" \ - --flags="$DIR/../hiddenapi-flags.csv" \ + --api-flags="$DIR/../hiddenapi-flags.csv" \ --no-force-assign-all) echo ' private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(' diff --git a/test/etc/default-build b/test/etc/default-build index 3e6699ad4e..5eba804507 100755 --- a/test/etc/default-build +++ b/test/etc/default-build @@ -92,7 +92,7 @@ else HAS_SRC_DEX2OAT_UNRESOLVED=false fi -if [ -f api-light-greylist.txt -o -f api-dark-greylist.txt -o -f api-blacklist.txt ]; then +if [ -f hiddenapi-flags.csv ]; then HAS_HIDDENAPI_SPEC=true else HAS_HIDDENAPI_SPEC=false @@ -327,15 +327,8 @@ function make_hiddenapi() { args+=("--output-dex=$1") shift done - if [ -f api-light-greylist.txt ]; then - args+=("--light-greylist=api-light-greylist.txt") - fi - if [ -f api-dark-greylist.txt ]; then - args+=("--dark-greylist=api-dark-greylist.txt") - fi - if [ -f api-blacklist.txt ]; then - args+=("--blacklist=api-blacklist.txt") - fi + args+=("--api-flags=hiddenapi-flags.csv") + args+=("--no-force-assign-all") ${HIDDENAPI} "${args[@]}" } diff --git a/test/ti-agent/common_helper.cc b/test/ti-agent/common_helper.cc index f5e1e1bc07..3be48a3b80 100644 --- a/test/ti-agent/common_helper.cc +++ b/test/ti-agent/common_helper.cc @@ -24,6 +24,7 @@ #include "jvmti.h" #include "jvmti_helper.h" +#include "ti_macros.h" namespace art { @@ -87,7 +88,7 @@ jobject GetJavaValueByType(JNIEnv* env, char type, jvalue value) { break; default: LOG(FATAL) << "Unable to figure out type!"; - return nullptr; + UNREACHABLE(); } std::ostringstream oss; oss << "(" << type << ")L" << name << ";"; diff --git a/tools/class2greylist/src/com/android/class2greylist/AnnotationConsumer.java b/tools/class2greylist/src/com/android/class2greylist/AnnotationConsumer.java new file mode 100644 index 0000000000..0f5f413476 --- /dev/null +++ b/tools/class2greylist/src/com/android/class2greylist/AnnotationConsumer.java @@ -0,0 +1,18 @@ +package com.android.class2greylist; + +import java.util.Map; +import java.util.Set; + +public interface AnnotationConsumer { + /** + * Handle a parsed annotation for a class member. + * + * @param apiSignature Signature of the class member. + * @param annotationProperties Map of stringified properties of this annotation. + * @param parsedFlags Array of flags parsed from the annotation for this member. + */ + public void consume(String apiSignature, Map<String, String> annotationProperties, + Set<String> parsedFlags); + + public void close(); +} diff --git a/tools/class2greylist/src/com/android/class2greylist/AnnotationHandler.java b/tools/class2greylist/src/com/android/class2greylist/AnnotationHandler.java index 92d2ab6d79..ba1f583707 100644 --- a/tools/class2greylist/src/com/android/class2greylist/AnnotationHandler.java +++ b/tools/class2greylist/src/com/android/class2greylist/AnnotationHandler.java @@ -1,11 +1,27 @@ package com.android.class2greylist; +import java.util.Map; +import java.util.HashMap; + import org.apache.bcel.classfile.AnnotationEntry; +import org.apache.bcel.classfile.ElementValuePair; + /** - * Interface for an annotation handler, which handle individual annotations on + * Base class for an annotation handler, which handle individual annotations on * class members. */ -public interface AnnotationHandler { - void handleAnnotation(AnnotationEntry annotation, AnnotationContext context); +public abstract class AnnotationHandler { + abstract void handleAnnotation(AnnotationEntry annotation, AnnotationContext context); + + protected Map<String, String> stringifyAnnotationProperties(AnnotationEntry annotation) { + Map<String, String> content = new HashMap<String, String>(); + + // Stringify all annotation properties. + for (ElementValuePair prop : annotation.getElementValuePairs()) { + content.put(prop.getNameString(), prop.getValue().stringifyValue()); + } + + return content; + } } diff --git a/tools/class2greylist/src/com/android/class2greylist/AnnotationPropertyWriter.java b/tools/class2greylist/src/com/android/class2greylist/AnnotationPropertyWriter.java new file mode 100644 index 0000000000..aacd9639cd --- /dev/null +++ b/tools/class2greylist/src/com/android/class2greylist/AnnotationPropertyWriter.java @@ -0,0 +1,56 @@ +package com.android.class2greylist; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +public class AnnotationPropertyWriter implements AnnotationConsumer { + + private final PrintStream mOutput; + private final List<Map<String, String>> mContents; + private final Set<String> mColumns; + + public AnnotationPropertyWriter(String csvFile) throws FileNotFoundException { + mOutput = new PrintStream(new FileOutputStream(new File(csvFile))); + mContents = new ArrayList<>(); + mColumns = new HashSet<>(); + } + + public void consume(String apiSignature, Map<String, String> annotationProperties, + Set<String> parsedFlags) { + // Clone properties map. + Map<String, String> contents = new HashMap(annotationProperties); + + // Append the member signature. + contents.put("signature", apiSignature); + + // Store data. + mColumns.addAll(contents.keySet()); + mContents.add(contents); + } + + public void close() { + // Sort columns by name and print header row. + List<String> columns = new ArrayList<>(mColumns); + columns.sort(Comparator.naturalOrder()); + mOutput.println(columns.stream().collect(Collectors.joining(","))); + + // Sort contents according to columns and print. + for (Map<String, String> row : mContents) { + mOutput.println(columns.stream().map(column -> row.getOrDefault(column, "")) + .collect(Collectors.joining(","))); + } + + // Close output. + mOutput.close(); + } +} diff --git a/tools/class2greylist/src/com/android/class2greylist/Class2Greylist.java b/tools/class2greylist/src/com/android/class2greylist/Class2Greylist.java index 870f85a2c3..621ee11fa7 100644 --- a/tools/class2greylist/src/com/android/class2greylist/Class2Greylist.java +++ b/tools/class2greylist/src/com/android/class2greylist/Class2Greylist.java @@ -42,6 +42,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.HashMap; import java.util.Set; import java.util.function.Predicate; @@ -57,17 +58,28 @@ public class Class2Greylist { "Ldalvik/annotation/compat/UnsupportedAppUsage;"); private static final Set<String> WHITELIST_ANNOTATIONS = ImmutableSet.of(); + public static final String FLAG_WHITELIST = "whitelist"; + public static final String FLAG_GREYLIST = "greylist"; + public static final String FLAG_BLACKLIST = "blacklist"; + public static final String FLAG_GREYLIST_MAX_O = "greylist-max-o"; + + private static final Map<Integer, String> TARGET_SDK_TO_LIST_MAP; + static { + Map<Integer, String> map = new HashMap<>(); + map.put(null, FLAG_GREYLIST); + map.put(26, FLAG_GREYLIST_MAX_O); + map.put(28, FLAG_GREYLIST); + TARGET_SDK_TO_LIST_MAP = Collections.unmodifiableMap(map); + } + private final Status mStatus; private final String mPublicApiListFile; - private final String[] mPerSdkOutputFiles; - private final String mWhitelistFile; + private final String mCsvFlagsFile; private final String mCsvMetadataFile; private final String[] mJarFiles; - private final GreylistConsumer mOutput; - private final Predicate<Integer> mAllowedSdkVersions; + private final AnnotationConsumer mOutput; private final Set<String> mPublicApis; - public static void main(String[] args) { Options options = new Options(); options.addOption(OptionBuilder @@ -76,19 +88,9 @@ public class Class2Greylist { .withDescription("Public API list file. Used to de-dupe bridge methods.") .create("p")); options.addOption(OptionBuilder - .withLongOpt("write-greylist") - .hasArgs() - .withDescription( - "Specify file to write greylist to. Can be specified multiple times. " + - "Format is either just a filename, or \"int[,int,...]:filename\". If " + - "integers are given, members with matching maxTargetSdk values are " + - "written to the file; if no integer or \"none\" is given, members with " + - "no maxTargetSdk are written.") - .create("g")); - options.addOption(OptionBuilder - .withLongOpt("write-whitelist") + .withLongOpt("write-flags-csv") .hasArgs(1) - .withDescription("Specify file to write whitelist to.") + .withDescription("Specify file to write hiddenapi flags to.") .create('w')); options.addOption(OptionBuilder .withLongOpt("debug") @@ -106,7 +108,7 @@ public class Class2Greylist { .hasArgs(1) .withDescription("Specify a file to write API metaadata to. This is a CSV file " + "containing any annotation properties for all members. Do not use in " + - "conjunction with --write-greylist or --write-whitelist.") + "conjunction with --write-flags-csv.") .create('c')); options.addOption(OptionBuilder .withLongOpt("help") @@ -144,7 +146,6 @@ public class Class2Greylist { Class2Greylist c2gl = new Class2Greylist( status, cmd.getOptionValue('p', null), - cmd.getOptionValues('g'), cmd.getOptionValue('w', null), cmd.getOptionValue('c', null), jarFiles); @@ -163,34 +164,18 @@ public class Class2Greylist { } @VisibleForTesting - Class2Greylist(Status status, String publicApiListFile, String[] perSdkLevelOutputFiles, - String whitelistOutputFile, String csvMetadataFile, String[] jarFiles) + Class2Greylist(Status status, String publicApiListFile, String csvFlagsFile, + String csvMetadataFile, String[] jarFiles) throws IOException { mStatus = status; mPublicApiListFile = publicApiListFile; - mPerSdkOutputFiles = perSdkLevelOutputFiles; - mWhitelistFile = whitelistOutputFile; + mCsvFlagsFile = csvFlagsFile; mCsvMetadataFile = csvMetadataFile; mJarFiles = jarFiles; if (mCsvMetadataFile != null) { - mOutput = new CsvGreylistConsumer(mStatus, mCsvMetadataFile); - mAllowedSdkVersions = x -> true; + mOutput = new AnnotationPropertyWriter(mCsvMetadataFile); } else { - Map<Integer, String> outputFiles = readGreylistMap(mStatus, mPerSdkOutputFiles); - mOutput = new FileWritingGreylistConsumer(mStatus, outputFiles, mWhitelistFile); - mAllowedSdkVersions = new Predicate<Integer>(){ - @Override - public boolean test(Integer i) { - return outputFiles.keySet().contains(i); - } - - @Override - public String toString() { - // we reply on this toString behaviour for readable error messages in - // GreylistAnnotationHandler - return Joiner.on(",").join(outputFiles.keySet()); - } - }; + mOutput = new HiddenapiFlagsWriter(mCsvFlagsFile); } if (mPublicApiListFile != null) { @@ -203,14 +188,15 @@ public class Class2Greylist { private Map<String, AnnotationHandler> createAnnotationHandlers() { Builder<String, AnnotationHandler> builder = ImmutableMap.builder(); - GreylistAnnotationHandler greylistAnnotationHandler = new GreylistAnnotationHandler( - mStatus, mOutput, mPublicApis, mAllowedSdkVersions); + UnsupportedAppUsageAnnotationHandler greylistAnnotationHandler = + new UnsupportedAppUsageAnnotationHandler( + mStatus, mOutput, mPublicApis, TARGET_SDK_TO_LIST_MAP); GREYLIST_ANNOTATIONS.forEach(a -> builder.put(a, greylistAnnotationHandler)); return builder .put(CovariantReturnTypeHandler.ANNOTATION_NAME, - new CovariantReturnTypeHandler(mOutput, mPublicApis)) + new CovariantReturnTypeHandler(mOutput, mPublicApis, FLAG_WHITELIST)) .put(CovariantReturnTypeMultiHandler.ANNOTATION_NAME, - new CovariantReturnTypeMultiHandler(mOutput, mPublicApis)) + new CovariantReturnTypeMultiHandler(mOutput, mPublicApis, FLAG_WHITELIST)) .build(); } @@ -230,48 +216,6 @@ public class Class2Greylist { mOutput.close(); } - @VisibleForTesting - static Map<Integer, String> readGreylistMap(Status status, String[] argValues) { - Map<Integer, String> map = new HashMap<>(); - for (String sdkFile : argValues) { - List<Integer> maxTargetSdks = new ArrayList<>(); - String filename; - int colonPos = sdkFile.indexOf(':'); - if (colonPos != -1) { - String[] targets = sdkFile.substring(0, colonPos).split(","); - for (String target : targets) { - if ("none".equals(target)) { - maxTargetSdks.add(null); - } else { - try { - maxTargetSdks.add(Integer.valueOf(target)); - } catch (NumberFormatException nfe) { - status.error("Not a valid integer: %s from argument value '%s'", - sdkFile.substring(0, colonPos), sdkFile); - } - } - } - filename = sdkFile.substring(colonPos + 1); - if (filename.length() == 0) { - status.error("Not a valid file name: %s from argument value '%s'", - filename, sdkFile); - } - } else { - maxTargetSdks.add(null); - filename = sdkFile; - } - for (Integer maxTargetSdk : maxTargetSdks) { - if (map.containsKey(maxTargetSdk)) { - status.error("Multiple output files for maxTargetSdk %s", - maxTargetSdk == null ? "none" : maxTargetSdk); - } else { - map.put(maxTargetSdk, filename); - } - } - } - return map; - } - private static void dumpAllMembers(Status status, String[] jarFiles) { for (String jarFile : jarFiles) { status.debug("Processing jar file %s", jarFile); diff --git a/tools/class2greylist/src/com/android/class2greylist/CovariantReturnTypeHandler.java b/tools/class2greylist/src/com/android/class2greylist/CovariantReturnTypeHandler.java index afd15b4c59..b8de7e92fa 100644 --- a/tools/class2greylist/src/com/android/class2greylist/CovariantReturnTypeHandler.java +++ b/tools/class2greylist/src/com/android/class2greylist/CovariantReturnTypeHandler.java @@ -1,12 +1,18 @@ package com.android.class2greylist; import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableSet; import org.apache.bcel.classfile.AnnotationEntry; +import org.apache.bcel.classfile.Constant; +import org.apache.bcel.classfile.ConstantPool; +import org.apache.bcel.classfile.ElementValue; import org.apache.bcel.classfile.ElementValuePair; import org.apache.bcel.classfile.Method; +import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.Set; /** @@ -20,19 +26,22 @@ import java.util.Set; * <p>Methods are also validated against the public API list, to assert that * the annotated method is already a public API. */ -public class CovariantReturnTypeHandler implements AnnotationHandler { +public class CovariantReturnTypeHandler extends AnnotationHandler { private static final String SHORT_NAME = "CovariantReturnType"; public static final String ANNOTATION_NAME = "Ldalvik/annotation/codegen/CovariantReturnType;"; private static final String RETURN_TYPE = "returnType"; - private final GreylistConsumer mConsumer; + private final AnnotationConsumer mAnnotationConsumer; private final Set<String> mPublicApis; + private final String mHiddenapiFlag; - public CovariantReturnTypeHandler(GreylistConsumer consumer, Set<String> publicApis) { - mConsumer = consumer; + public CovariantReturnTypeHandler(AnnotationConsumer consumer, Set<String> publicApis, + String hiddenapiFlag) { + mAnnotationConsumer = consumer; mPublicApis = publicApis; + mHiddenapiFlag = hiddenapiFlag; } @Override @@ -74,7 +83,9 @@ public class CovariantReturnTypeHandler implements AnnotationHandler { signature, SHORT_NAME); return; } - mConsumer.whitelistEntry(signature); + + mAnnotationConsumer.consume(signature, stringifyAnnotationProperties(annotation), + ImmutableSet.of(mHiddenapiFlag)); } private String findReturnType(AnnotationEntry a) { diff --git a/tools/class2greylist/src/com/android/class2greylist/CovariantReturnTypeMultiHandler.java b/tools/class2greylist/src/com/android/class2greylist/CovariantReturnTypeMultiHandler.java index bd0bf79169..f2bc5254fa 100644 --- a/tools/class2greylist/src/com/android/class2greylist/CovariantReturnTypeMultiHandler.java +++ b/tools/class2greylist/src/com/android/class2greylist/CovariantReturnTypeMultiHandler.java @@ -18,7 +18,7 @@ import java.util.Set; * * <p>The enclosed annotations are passed to {@link CovariantReturnTypeHandler}. */ -public class CovariantReturnTypeMultiHandler implements AnnotationHandler { +public class CovariantReturnTypeMultiHandler extends AnnotationHandler { public static final String ANNOTATION_NAME = "Ldalvik/annotation/codegen/CovariantReturnType$CovariantReturnTypes;"; @@ -28,14 +28,15 @@ public class CovariantReturnTypeMultiHandler implements AnnotationHandler { private final CovariantReturnTypeHandler mWrappedHandler; private final String mInnerAnnotationName; - public CovariantReturnTypeMultiHandler(GreylistConsumer consumer, Set<String> publicApis) { - this(consumer, publicApis, CovariantReturnTypeHandler.ANNOTATION_NAME); + public CovariantReturnTypeMultiHandler(AnnotationConsumer consumer, Set<String> publicApis, + String hiddenapiFlag) { + this(consumer, publicApis, hiddenapiFlag, CovariantReturnTypeHandler.ANNOTATION_NAME); } @VisibleForTesting - public CovariantReturnTypeMultiHandler(GreylistConsumer consumer, Set<String> publicApis, - String innerAnnotationName) { - mWrappedHandler = new CovariantReturnTypeHandler(consumer, publicApis); + public CovariantReturnTypeMultiHandler(AnnotationConsumer consumer, Set<String> publicApis, + String hiddenapiFlag, String innerAnnotationName) { + mWrappedHandler = new CovariantReturnTypeHandler(consumer, publicApis, hiddenapiFlag); mInnerAnnotationName = innerAnnotationName; } diff --git a/tools/class2greylist/src/com/android/class2greylist/CsvGreylistConsumer.java b/tools/class2greylist/src/com/android/class2greylist/CsvGreylistConsumer.java deleted file mode 100644 index 7d28b317f0..0000000000 --- a/tools/class2greylist/src/com/android/class2greylist/CsvGreylistConsumer.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.android.class2greylist; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.PrintStream; -import java.util.Map; - -public class CsvGreylistConsumer implements GreylistConsumer { - - private final Status mStatus; - private final CsvWriter mCsvWriter; - - public CsvGreylistConsumer(Status status, String csvMetadataFile) throws FileNotFoundException { - mStatus = status; - mCsvWriter = new CsvWriter( - new PrintStream(new FileOutputStream(new File(csvMetadataFile)))); - } - - @Override - public void greylistEntry(String signature, Integer maxTargetSdk, - Map<String, String> annotationProperties) { - annotationProperties.put("signature", signature); - mCsvWriter.addRow(annotationProperties); - } - - @Override - public void whitelistEntry(String signature) { - } - - @Override - public void close() { - mCsvWriter.close(); - } -} diff --git a/tools/class2greylist/src/com/android/class2greylist/CsvWriter.java b/tools/class2greylist/src/com/android/class2greylist/CsvWriter.java deleted file mode 100644 index 3cfec30f23..0000000000 --- a/tools/class2greylist/src/com/android/class2greylist/CsvWriter.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.android.class2greylist; - -import com.google.common.base.Joiner; - -import java.io.PrintStream; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - -/** - * Helper class for writing data to a CSV file. - * - * This class does not write anything to its output until it is closed, so it can gather a set of - * all columns before writing the header row. - */ -public class CsvWriter { - - private final PrintStream mOutput; - private final ArrayList<Map<String, String>> mContents; - private final Set<String> mColumns; - - public CsvWriter(PrintStream out) { - mOutput = out; - mContents = new ArrayList<>(); - mColumns = new HashSet<>(); - } - - public void addRow(Map<String, String> values) { - mColumns.addAll(values.keySet()); - mContents.add(values); - } - - public void close() { - List<String> columns = new ArrayList<>(mColumns); - columns.sort(Comparator.naturalOrder()); - mOutput.println(columns.stream().collect(Collectors.joining(","))); - for (Map<String, String> row : mContents) { - mOutput.println(columns.stream().map(column -> row.getOrDefault(column, "")).collect( - Collectors.joining(","))); - } - mOutput.close(); - } - - -} diff --git a/tools/class2greylist/src/com/android/class2greylist/FileWritingGreylistConsumer.java b/tools/class2greylist/src/com/android/class2greylist/FileWritingGreylistConsumer.java deleted file mode 100644 index b3ed1b16f9..0000000000 --- a/tools/class2greylist/src/com/android/class2greylist/FileWritingGreylistConsumer.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.android.class2greylist; - -import com.google.common.annotations.VisibleForTesting; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.PrintStream; -import java.util.HashMap; -import java.util.Map; - -public class FileWritingGreylistConsumer implements GreylistConsumer { - - private final Status mStatus; - private final Map<Integer, PrintStream> mSdkToPrintStreamMap; - private final PrintStream mWhitelistStream; - - private static PrintStream openFile(String filename) throws FileNotFoundException { - if (filename == null) { - return null; - } - return new PrintStream(new FileOutputStream(new File(filename))); - } - - @VisibleForTesting - public static Map<Integer, PrintStream> openFiles( - Map<Integer, String> filenames) throws FileNotFoundException { - Map<String, PrintStream> streamsByName = new HashMap<>(); - Map<Integer, PrintStream> streams = new HashMap<>(); - for (Map.Entry<Integer, String> entry : filenames.entrySet()) { - if (!streamsByName.containsKey(entry.getValue())) { - streamsByName.put(entry.getValue(), openFile(entry.getValue())); - } - streams.put(entry.getKey(), streamsByName.get(entry.getValue())); - } - return streams; - } - - public FileWritingGreylistConsumer(Status status, Map<Integer, String> sdkToFilenameMap, - String whitelistFile) throws FileNotFoundException { - mStatus = status; - mSdkToPrintStreamMap = openFiles(sdkToFilenameMap); - mWhitelistStream = openFile(whitelistFile); - } - - @Override - public void greylistEntry( - String signature, Integer maxTargetSdk, Map<String, String> annotationProperties) { - PrintStream p = mSdkToPrintStreamMap.get(maxTargetSdk); - if (p == null) { - mStatus.error("No output file for signature %s with maxTargetSdk of %d", signature, - maxTargetSdk == null ? "<absent>" : maxTargetSdk.toString()); - return; - } - p.println(signature); - } - - @Override - public void whitelistEntry(String signature) { - if (mWhitelistStream != null) { - mWhitelistStream.println(signature); - } - } - - @Override - public void close() { - for (PrintStream p : mSdkToPrintStreamMap.values()) { - p.close(); - } - if (mWhitelistStream != null) { - mWhitelistStream.close(); - } - } -} diff --git a/tools/class2greylist/src/com/android/class2greylist/GreylistAnnotationHandler.java b/tools/class2greylist/src/com/android/class2greylist/GreylistAnnotationHandler.java deleted file mode 100644 index 72c0ea4206..0000000000 --- a/tools/class2greylist/src/com/android/class2greylist/GreylistAnnotationHandler.java +++ /dev/null @@ -1,149 +0,0 @@ -package com.android.class2greylist; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Joiner; - -import org.apache.bcel.Const; -import org.apache.bcel.classfile.AnnotationEntry; -import org.apache.bcel.classfile.ElementValue; -import org.apache.bcel.classfile.ElementValuePair; -import org.apache.bcel.classfile.FieldOrMethod; -import org.apache.bcel.classfile.Method; -import org.apache.bcel.classfile.SimpleElementValue; - -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import java.util.function.Predicate; - -/** - * Processes {@code UnsupportedAppUsage} annotations to generate greylist - * entries. - * - * Any annotations with a {@link #EXPECTED_SIGNATURE} property will have their - * generated signature verified against this, and an error will be reported if - * it does not match. Exclusions are made for bridge methods. - * - * Any {@link #MAX_TARGET_SDK} properties will be validated against the given - * set of valid values, then passed through to the greylist consumer. - */ -public class GreylistAnnotationHandler implements AnnotationHandler { - - // properties of greylist annotations: - private static final String EXPECTED_SIGNATURE = "expectedSignature"; - private static final String MAX_TARGET_SDK = "maxTargetSdk"; - - private final Status mStatus; - private final Predicate<GreylistMember> mGreylistFilter; - private final GreylistConsumer mGreylistConsumer; - private final Predicate<Integer> mValidMaxTargetSdkValues; - - /** - * Represents a member of a class file (a field or method). - */ - @VisibleForTesting - public static class GreylistMember { - - /** - * Signature of this member. - */ - public final String signature; - /** - * Indicates if this is a synthetic bridge method. - */ - public final boolean bridge; - /** - * Max target SDK of property this member, if it is set, else null. - * - * Note: even though the annotation itself specified a default value, - * that default value is not encoded into instances of the annotation - * in class files. So when no value is specified in source, it will - * result in null appearing in here. - */ - public final Integer maxTargetSdk; - - public GreylistMember(String signature, boolean bridge, Integer maxTargetSdk) { - this.signature = signature; - this.bridge = bridge; - this.maxTargetSdk = maxTargetSdk; - } - } - - public GreylistAnnotationHandler( - Status status, - GreylistConsumer greylistConsumer, - Set<String> publicApis, - Predicate<Integer> validMaxTargetSdkValues) { - this(status, greylistConsumer, - member -> !(member.bridge && publicApis.contains(member.signature)), - validMaxTargetSdkValues); - } - - @VisibleForTesting - public GreylistAnnotationHandler( - Status status, - GreylistConsumer greylistConsumer, - Predicate<GreylistMember> greylistFilter, - Predicate<Integer> validMaxTargetSdkValues) { - mStatus = status; - mGreylistConsumer = greylistConsumer; - mGreylistFilter = greylistFilter; - mValidMaxTargetSdkValues = validMaxTargetSdkValues; - } - - @Override - public void handleAnnotation(AnnotationEntry annotation, AnnotationContext context) { - FieldOrMethod member = context.member; - boolean bridge = (member instanceof Method) - && (member.getAccessFlags() & Const.ACC_BRIDGE) != 0; - if (bridge) { - mStatus.debug("Member is a bridge"); - } - String signature = context.getMemberDescriptor(); - Integer maxTargetSdk = null; - Map<String, String> allValues = new HashMap<String, String>(); - for (ElementValuePair property : annotation.getElementValuePairs()) { - switch (property.getNameString()) { - case EXPECTED_SIGNATURE: - verifyExpectedSignature(context, property, signature, bridge); - break; - case MAX_TARGET_SDK: - maxTargetSdk = verifyAndGetMaxTargetSdk(context, property); - break; - } - allValues.put(property.getNameString(), property.getValue().stringifyValue()); - } - if (mGreylistFilter.test(new GreylistMember(signature, bridge, maxTargetSdk))) { - mGreylistConsumer.greylistEntry(signature, maxTargetSdk, allValues); - } - } - - private void verifyExpectedSignature(AnnotationContext context, ElementValuePair property, - String signature, boolean isBridge) { - String expected = property.getValue().stringifyValue(); - // Don't enforce for bridge methods; they're generated so won't match. - if (!isBridge && !signature.equals(expected)) { - context.reportError("Expected signature does not match generated:\n" - + "Expected: %s\n" - + "Generated: %s", expected, signature); - } - } - - private Integer verifyAndGetMaxTargetSdk(AnnotationContext context, ElementValuePair property) { - if (property.getValue().getElementValueType() != ElementValue.PRIMITIVE_INT) { - context.reportError("Expected property %s to be of type int; got %d", - property.getNameString(), property.getValue().getElementValueType()); - return null; - } - int value = ((SimpleElementValue) property.getValue()).getValueInt(); - if (!mValidMaxTargetSdkValues.test(value)) { - context.reportError("Invalid value for %s: got %d, expected one of [%s]", - property.getNameString(), - value, - mValidMaxTargetSdkValues); - return null; - } - return value; - } - -} diff --git a/tools/class2greylist/src/com/android/class2greylist/GreylistConsumer.java b/tools/class2greylist/src/com/android/class2greylist/GreylistConsumer.java deleted file mode 100644 index afded37e66..0000000000 --- a/tools/class2greylist/src/com/android/class2greylist/GreylistConsumer.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.android.class2greylist; - -import java.util.Map; - -public interface GreylistConsumer { - /** - * Handle a new greylist entry. - * - * @param signature Signature of the member. - * @param maxTargetSdk maxTargetSdk value from the annotation, or null if none set. - */ - void greylistEntry( - String signature, Integer maxTargetSdk, Map<String, String> annotationProperties); - - /** - * Handle a new whitelist entry. - * - * @param signature Signature of the member. - */ - void whitelistEntry(String signature); - - void close(); -} diff --git a/tools/class2greylist/src/com/android/class2greylist/HiddenapiFlagsWriter.java b/tools/class2greylist/src/com/android/class2greylist/HiddenapiFlagsWriter.java new file mode 100644 index 0000000000..54ca17cbc7 --- /dev/null +++ b/tools/class2greylist/src/com/android/class2greylist/HiddenapiFlagsWriter.java @@ -0,0 +1,40 @@ +package com.android.class2greylist; + +import com.google.common.annotations.VisibleForTesting; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class HiddenapiFlagsWriter implements AnnotationConsumer { + + private final PrintStream mOutput; + + public HiddenapiFlagsWriter(String csvFile) throws FileNotFoundException { + mOutput = new PrintStream(new FileOutputStream(new File(csvFile))); + } + + public void consume(String apiSignature, Map<String, String> annotationProperties, + Set<String> parsedFlags) { + if (parsedFlags.size() > 0) { + mOutput.println(apiSignature + "," + String.join(",", asSortedList(parsedFlags))); + } + } + + public void close() { + mOutput.close(); + } + + private static List<String> asSortedList(Set<String> s) { + List<String> list = new ArrayList<>(s); + Collections.sort(list); + return list; + } + +} diff --git a/tools/class2greylist/src/com/android/class2greylist/SystemOutGreylistConsumer.java b/tools/class2greylist/src/com/android/class2greylist/SystemOutGreylistConsumer.java deleted file mode 100644 index f86ac6ec68..0000000000 --- a/tools/class2greylist/src/com/android/class2greylist/SystemOutGreylistConsumer.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.android.class2greylist; - -import java.util.Map; - -public class SystemOutGreylistConsumer implements GreylistConsumer { - @Override - public void greylistEntry( - String signature, Integer maxTargetSdk, Map<String, String> annotationValues) { - System.out.println(signature); - } - - @Override - public void whitelistEntry(String signature) { - // Ignore. This class is only used when no grey/white lists are - // specified, so we have nowhere to write whitelist entries. - } - - @Override - public void close() { - } -} diff --git a/tools/class2greylist/src/com/android/class2greylist/UnsupportedAppUsageAnnotationHandler.java b/tools/class2greylist/src/com/android/class2greylist/UnsupportedAppUsageAnnotationHandler.java new file mode 100644 index 0000000000..d1f3e77091 --- /dev/null +++ b/tools/class2greylist/src/com/android/class2greylist/UnsupportedAppUsageAnnotationHandler.java @@ -0,0 +1,134 @@ +package com.android.class2greylist; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Joiner; +import com.google.common.collect.ImmutableSet; + +import org.apache.bcel.Const; +import org.apache.bcel.classfile.AnnotationEntry; +import org.apache.bcel.classfile.ElementValue; +import org.apache.bcel.classfile.ElementValuePair; +import org.apache.bcel.classfile.FieldOrMethod; +import org.apache.bcel.classfile.Method; +import org.apache.bcel.classfile.SimpleElementValue; + +import java.util.Map; +import java.util.Set; +import java.util.function.Predicate; + +/** + * Processes {@code UnsupportedAppUsage} annotations to generate greylist + * entries. + * + * Any annotations with a {@link #EXPECTED_SIGNATURE} property will have their + * generated signature verified against this, and an error will be reported if + * it does not match. Exclusions are made for bridge methods. + * + * Any {@link #MAX_TARGET_SDK} properties will be validated against the given + * set of valid values, then passed through to the greylist consumer. + */ +public class UnsupportedAppUsageAnnotationHandler extends AnnotationHandler { + + // properties of greylist annotations: + private static final String EXPECTED_SIGNATURE_PROPERTY = "expectedSignature"; + private static final String MAX_TARGET_SDK_PROPERTY = "maxTargetSdk"; + + private final Status mStatus; + private final Predicate<ClassMember> mClassMemberFilter; + private final Map<Integer, String> mSdkVersionToFlagMap; + private final AnnotationConsumer mAnnotationConsumer; + + /** + * Represents a member of a class file (a field or method). + */ + @VisibleForTesting + public static class ClassMember { + + /** + * Signature of this class member. + */ + public final String signature; + + /** + * Indicates if this is a synthetic bridge method. + */ + public final boolean isBridgeMethod; + + public ClassMember(String signature, boolean isBridgeMethod) { + this.signature = signature; + this.isBridgeMethod = isBridgeMethod; + } + } + + public UnsupportedAppUsageAnnotationHandler(Status status, + AnnotationConsumer annotationConsumer, Set<String> publicApis, + Map<Integer, String> sdkVersionToFlagMap) { + this(status, annotationConsumer, + member -> !(member.isBridgeMethod && publicApis.contains(member.signature)), + sdkVersionToFlagMap); + } + + @VisibleForTesting + public UnsupportedAppUsageAnnotationHandler(Status status, + AnnotationConsumer annotationConsumer, Predicate<ClassMember> memberFilter, + Map<Integer, String> sdkVersionToFlagMap) { + mStatus = status; + mAnnotationConsumer = annotationConsumer; + mClassMemberFilter = memberFilter; + mSdkVersionToFlagMap = sdkVersionToFlagMap; + } + + @Override + public void handleAnnotation(AnnotationEntry annotation, AnnotationContext context) { + FieldOrMethod member = context.member; + + boolean isBridgeMethod = (member instanceof Method) && + (member.getAccessFlags() & Const.ACC_BRIDGE) != 0; + if (isBridgeMethod) { + mStatus.debug("Member is a bridge method"); + } + + String signature = context.getMemberDescriptor(); + Integer maxTargetSdk = null; + + for (ElementValuePair property : annotation.getElementValuePairs()) { + switch (property.getNameString()) { + case EXPECTED_SIGNATURE_PROPERTY: + String expected = property.getValue().stringifyValue(); + // Don't enforce for bridge methods; they're generated so won't match. + if (!isBridgeMethod && !signature.equals(expected)) { + context.reportError("Expected signature does not match generated:\n" + + "Expected: %s\n" + + "Generated: %s", expected, signature); + return; + } + break; + case MAX_TARGET_SDK_PROPERTY: + if (property.getValue().getElementValueType() != ElementValue.PRIMITIVE_INT) { + context.reportError("Expected property %s to be of type int; got %d", + property.getNameString(), + property.getValue().getElementValueType()); + return; + } + + maxTargetSdk = ((SimpleElementValue) property.getValue()).getValueInt(); + break; + } + } + + // Verify that maxTargetSdk is valid. + if (!mSdkVersionToFlagMap.containsKey(maxTargetSdk)) { + context.reportError("Invalid value for %s: got %d, expected one of [%s]", + MAX_TARGET_SDK_PROPERTY, + maxTargetSdk, + mSdkVersionToFlagMap.keySet()); + return; + } + + // Consume this annotation if it matches the predicate. + if (mClassMemberFilter.test(new ClassMember(signature, isBridgeMethod))) { + mAnnotationConsumer.consume(signature, stringifyAnnotationProperties(annotation), + ImmutableSet.of(mSdkVersionToFlagMap.get(maxTargetSdk))); + } + } +} diff --git a/tools/class2greylist/test/src/com/android/class2greylist/AnnotationHandlerTestBase.java b/tools/class2greylist/test/src/com/android/class2greylist/AnnotationHandlerTestBase.java index 8f4a76f765..65ebbf0181 100644 --- a/tools/class2greylist/test/src/com/android/class2greylist/AnnotationHandlerTestBase.java +++ b/tools/class2greylist/test/src/com/android/class2greylist/AnnotationHandlerTestBase.java @@ -36,14 +36,14 @@ public class AnnotationHandlerTestBase { public TestName mTestName = new TestName(); protected Javac mJavac; - protected GreylistConsumer mConsumer; + protected AnnotationConsumer mConsumer; protected Status mStatus; @Before public void baseSetup() throws IOException { System.out.println(String.format("\n============== STARTING TEST: %s ==============\n", mTestName.getMethodName())); - mConsumer = mock(GreylistConsumer.class); + mConsumer = mock(AnnotationConsumer.class); mStatus = mock(Status.class, withSettings().verboseLogging()); mJavac = new Javac(); } diff --git a/tools/class2greylist/test/src/com/android/class2greylist/Class2GreylistTest.java b/tools/class2greylist/test/src/com/android/class2greylist/Class2GreylistTest.java deleted file mode 100644 index b87a5b1c3f..0000000000 --- a/tools/class2greylist/test/src/com/android/class2greylist/Class2GreylistTest.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (C) 2018 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. - */ - -package com.android.class2greylist; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; -import org.mockito.Mock; - -import java.io.IOException; -import java.util.Map; - -public class Class2GreylistTest { - - @Mock - Status mStatus; - @Rule - public TestName mTestName = new TestName(); - - @Before - public void setup() throws IOException { - System.out.println(String.format("\n============== STARTING TEST: %s ==============\n", - mTestName.getMethodName())); - initMocks(this); - } - - @Test - public void testReadGreylistMap() throws IOException { - Map<Integer, String> map = Class2Greylist.readGreylistMap(mStatus, - new String[]{"noApi", "1:apiOne", "3:apiThree"}); - verifyZeroInteractions(mStatus); - assertThat(map).containsExactly(null, "noApi", 1, "apiOne", 3, "apiThree"); - } - - @Test - public void testReadGreylistMapNone() throws IOException { - Map<Integer, String> map = Class2Greylist.readGreylistMap(mStatus, - new String[]{"none:noApi"}); - verifyZeroInteractions(mStatus); - assertThat(map).containsExactly(null, "noApi"); - } - - @Test - public void testReadGreylistMapMulti() throws IOException { - Map<Integer, String> map = Class2Greylist.readGreylistMap(mStatus, - new String[]{"1,none:noOr1Api", "3:apiThree"}); - verifyZeroInteractions(mStatus); - assertThat(map).containsExactly(null, "noOr1Api", 1, "noOr1Api", 3, "apiThree"); - } - - @Test - public void testReadGreylistMapMulti2() throws IOException { - Map<Integer, String> map = Class2Greylist.readGreylistMap(mStatus, - new String[]{"1,none,2,3,4:allApi"}); - verifyZeroInteractions(mStatus); - assertThat(map).containsExactly( - null, "allApi", 1, "allApi", 2, "allApi", 3, "allApi", 4, "allApi"); - } - - @Test - public void testReadGreylistMapDuplicate() throws IOException { - Class2Greylist.readGreylistMap(mStatus, - new String[]{"noApi", "1:apiOne", "1:anotherOne"}); - verify(mStatus, atLeastOnce()).error(any(), any()); - } - - @Test - public void testReadGreylistMapDuplicateNoApi() { - Class2Greylist.readGreylistMap(mStatus, - new String[]{"noApi", "anotherNoApi", "1:apiOne"}); - verify(mStatus, atLeastOnce()).error(any(), any()); - } - - @Test - public void testReadGreylistMapInvalidInt() throws IOException { - Class2Greylist.readGreylistMap(mStatus, new String[]{"noApi", "a:apiOne"}); - verify(mStatus, atLeastOnce()).error(any(), any()); - } - - @Test - public void testReadGreylistMapNoFilename() throws IOException { - Class2Greylist.readGreylistMap(mStatus, new String[]{"noApi", "1:"}); - verify(mStatus, atLeastOnce()).error(any(), any()); - } -} - diff --git a/tools/class2greylist/test/src/com/android/class2greylist/CovariantReturnTypeHandlerTest.java b/tools/class2greylist/test/src/com/android/class2greylist/CovariantReturnTypeHandlerTest.java index 10fae9b11c..9d2f014e4e 100644 --- a/tools/class2greylist/test/src/com/android/class2greylist/CovariantReturnTypeHandlerTest.java +++ b/tools/class2greylist/test/src/com/android/class2greylist/CovariantReturnTypeHandlerTest.java @@ -40,6 +40,7 @@ import java.util.Map; public class CovariantReturnTypeHandlerTest extends AnnotationHandlerTestBase { private static final String ANNOTATION = "Lannotation/Annotation;"; + private static final String FLAG = "test-flag"; @Before public void setup() throws IOException { @@ -72,11 +73,13 @@ public class CovariantReturnTypeHandlerTest extends AnnotationHandlerTestBase { ImmutableMap.of(ANNOTATION, new CovariantReturnTypeHandler( mConsumer, - ImmutableSet.of("La/b/Class;->method()Ljava/lang/String;"))); + ImmutableSet.of("La/b/Class;->method()Ljava/lang/String;"), + FLAG)); new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, handlerMap).visit(); assertNoErrors(); - verify(mConsumer, times(1)).whitelistEntry(eq("La/b/Class;->method()Ljava/lang/Integer;")); + verify(mConsumer, times(1)).consume( + eq("La/b/Class;->method()Ljava/lang/Integer;"), any(), eq(ImmutableSet.of(FLAG))); } @Test @@ -94,7 +97,8 @@ public class CovariantReturnTypeHandlerTest extends AnnotationHandlerTestBase { ImmutableMap.of(ANNOTATION, new CovariantReturnTypeHandler( mConsumer, - emptySet())); + emptySet(), + FLAG)); new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, handlerMap).visit(); verify(mStatus, atLeastOnce()).error(any(), any()); @@ -118,7 +122,8 @@ public class CovariantReturnTypeHandlerTest extends AnnotationHandlerTestBase { ImmutableSet.of( "La/b/Class;->method()Ljava/lang/String;", "La/b/Class;->method()Ljava/lang/Integer;" - ))); + ), + FLAG)); new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, handlerMap).visit(); verify(mStatus, atLeastOnce()).error(any(), any()); @@ -139,7 +144,8 @@ public class CovariantReturnTypeHandlerTest extends AnnotationHandlerTestBase { ImmutableMap.of(ANNOTATION, new CovariantReturnTypeHandler( mConsumer, - emptySet())); + emptySet(), + FLAG)); new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, handlerMap).visit(); verify(mStatus, atLeastOnce()).error(any(), any()); diff --git a/tools/class2greylist/test/src/com/android/class2greylist/CovariantReturnTypeMultiHandlerTest.java b/tools/class2greylist/test/src/com/android/class2greylist/CovariantReturnTypeMultiHandlerTest.java index 7f4ce62002..1202564948 100644 --- a/tools/class2greylist/test/src/com/android/class2greylist/CovariantReturnTypeMultiHandlerTest.java +++ b/tools/class2greylist/test/src/com/android/class2greylist/CovariantReturnTypeMultiHandlerTest.java @@ -19,6 +19,7 @@ package com.android.class2greylist; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -38,6 +39,7 @@ import java.util.Map; public class CovariantReturnTypeMultiHandlerTest extends AnnotationHandlerTestBase { + private static final String FLAG = "test-flag"; @Before public void setup() throws IOException { @@ -79,16 +81,17 @@ public class CovariantReturnTypeMultiHandlerTest extends AnnotationHandlerTestBa new CovariantReturnTypeMultiHandler( mConsumer, ImmutableSet.of("La/b/Class;->method()Ljava/lang/String;"), + FLAG, "Lannotation/Annotation;")); new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, handlerMap).visit(); assertNoErrors(); ArgumentCaptor<String> whitelist = ArgumentCaptor.forClass(String.class); - verify(mConsumer, times(2)).whitelistEntry(whitelist.capture()); + verify(mConsumer, times(2)).consume(whitelist.capture(), any(), + eq(ImmutableSet.of(FLAG))); assertThat(whitelist.getAllValues()).containsExactly( "La/b/Class;->method()Ljava/lang/Integer;", - "La/b/Class;->method()Ljava/lang/Long;" - ); + "La/b/Class;->method()Ljava/lang/Long;"); } @Test @@ -108,6 +111,7 @@ public class CovariantReturnTypeMultiHandlerTest extends AnnotationHandlerTestBa new CovariantReturnTypeMultiHandler( mConsumer, emptySet(), + FLAG, "Lannotation/Annotation;")); new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, handlerMap).visit(); diff --git a/tools/class2greylist/test/src/com/android/class2greylist/FileWritingGreylistConsumerTest.java b/tools/class2greylist/test/src/com/android/class2greylist/FileWritingGreylistConsumerTest.java deleted file mode 100644 index 1e1b1df910..0000000000 --- a/tools/class2greylist/test/src/com/android/class2greylist/FileWritingGreylistConsumerTest.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2018 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. - */ - -package com.android.class2greylist; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.MockitoAnnotations.initMocks; - -import com.google.common.collect.ImmutableMap; - -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; -import org.mockito.Mock; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.PrintStream; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; -import java.util.Map; - -public class FileWritingGreylistConsumerTest { - - @Mock - Status mStatus; - @Rule - public TestName mTestName = new TestName(); - private int mFileNameSeq = 0; - private final List<String> mTempFiles = new ArrayList<>(); - - @Before - public void setup() throws IOException { - System.out.println(String.format("\n============== STARTING TEST: %s ==============\n", - mTestName.getMethodName())); - initMocks(this); - } - - @After - public void removeTempFiles() { - for (String name : mTempFiles) { - new File(name).delete(); - } - } - - private String tempFileName() { - String name = String.format(Locale.US, "/tmp/test-%s-%d", - mTestName.getMethodName(), mFileNameSeq++); - mTempFiles.add(name); - return name; - } - - @Test - public void testSimpleMap() throws FileNotFoundException { - Map<Integer, PrintStream> streams = FileWritingGreylistConsumer.openFiles( - ImmutableMap.of(1, tempFileName(), 2, tempFileName())); - assertThat(streams.keySet()).containsExactly(1, 2); - assertThat(streams.get(1)).isNotNull(); - assertThat(streams.get(2)).isNotNull(); - assertThat(streams.get(2)).isNotSameAs(streams.get(1)); - } - - @Test - public void testCommonMappings() throws FileNotFoundException { - String name = tempFileName(); - Map<Integer, PrintStream> streams = FileWritingGreylistConsumer.openFiles( - ImmutableMap.of(1, name, 2, name)); - assertThat(streams.keySet()).containsExactly(1, 2); - assertThat(streams.get(1)).isNotNull(); - assertThat(streams.get(2)).isSameAs(streams.get(1)); - } -} diff --git a/tools/class2greylist/test/src/com/android/class2greylist/GreylistAnnotationHandlerTest.java b/tools/class2greylist/test/src/com/android/class2greylist/UnsupportedAppUsageAnnotationHandlerTest.java index edf2ecd84d..cdf01afe7c 100644 --- a/tools/class2greylist/test/src/com/android/class2greylist/GreylistAnnotationHandlerTest.java +++ b/tools/class2greylist/test/src/com/android/class2greylist/UnsupportedAppUsageAnnotationHandlerTest.java @@ -19,11 +19,12 @@ package com.android.class2greylist; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static java.util.Collections.emptySet; +import static java.util.Collections.emptyMap; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableMap; @@ -35,14 +36,23 @@ import org.junit.Test; import org.mockito.ArgumentCaptor; import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.function.Predicate; -public class GreylistAnnotationHandlerTest extends AnnotationHandlerTestBase { +public class UnsupportedAppUsageAnnotationHandlerTest extends AnnotationHandlerTestBase { private static final String ANNOTATION = "Lannotation/Anno;"; + private static final Map<Integer, String> NULL_SDK_MAP; + static { + Map<Integer, String> map = new HashMap<>(); + map.put(null, "flag-null"); + NULL_SDK_MAP = Collections.unmodifiableMap(map); + } + @Before public void setup() throws IOException { mJavac.addSource("annotation.Anno", Joiner.on('\n').join( @@ -56,11 +66,11 @@ public class GreylistAnnotationHandlerTest extends AnnotationHandlerTestBase { "}")); } - private GreylistAnnotationHandler createGreylistHandler( - Predicate<GreylistAnnotationHandler.GreylistMember> greylistFilter, - Set<Integer> validMaxTargetSdkValues) { - return new GreylistAnnotationHandler( - mStatus, mConsumer, greylistFilter, x -> validMaxTargetSdkValues.contains(x)); + private UnsupportedAppUsageAnnotationHandler createGreylistHandler( + Predicate<UnsupportedAppUsageAnnotationHandler.ClassMember> greylistFilter, + Map<Integer, String> validMaxTargetSdkValues) { + return new UnsupportedAppUsageAnnotationHandler( + mStatus, mConsumer, greylistFilter, validMaxTargetSdkValues); } @Test @@ -75,12 +85,12 @@ public class GreylistAnnotationHandlerTest extends AnnotationHandlerTestBase { assertThat(mJavac.compile()).isTrue(); new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, - ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, emptySet())) + ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, NULL_SDK_MAP)) ).visit(); assertNoErrors(); ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class); - verify(mConsumer, times(1)).greylistEntry(greylist.capture(), any(), any()); + verify(mConsumer, times(1)).consume(greylist.capture(), any(), any()); assertThat(greylist.getValue()).isEqualTo("La/b/Class;->method()V"); } @@ -96,12 +106,12 @@ public class GreylistAnnotationHandlerTest extends AnnotationHandlerTestBase { assertThat(mJavac.compile()).isTrue(); new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, - ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, emptySet())) + ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, NULL_SDK_MAP)) ).visit(); assertNoErrors(); ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class); - verify(mConsumer, times(1)).greylistEntry(greylist.capture(), any(), any()); + verify(mConsumer, times(1)).consume(greylist.capture(), any(), any()); assertThat(greylist.getValue()).isEqualTo("La/b/Class;-><init>()V"); } @@ -117,12 +127,12 @@ public class GreylistAnnotationHandlerTest extends AnnotationHandlerTestBase { assertThat(mJavac.compile()).isTrue(); new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, - ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, emptySet())) + ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, NULL_SDK_MAP)) ).visit(); assertNoErrors(); ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class); - verify(mConsumer, times(1)).greylistEntry(greylist.capture(), any(), any()); + verify(mConsumer, times(1)).consume(greylist.capture(), any(), any()); assertThat(greylist.getValue()).isEqualTo("La/b/Class;->i:I"); } @@ -138,12 +148,12 @@ public class GreylistAnnotationHandlerTest extends AnnotationHandlerTestBase { assertThat(mJavac.compile()).isTrue(); new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, - ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, emptySet())) + ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, NULL_SDK_MAP)) ).visit(); assertNoErrors(); ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class); - verify(mConsumer, times(1)).greylistEntry(greylist.capture(), any(), any()); + verify(mConsumer, times(1)).consume(greylist.capture(), any(), any()); assertThat(greylist.getValue()).isEqualTo("La/b/Class;->method()V"); } @@ -159,7 +169,7 @@ public class GreylistAnnotationHandlerTest extends AnnotationHandlerTestBase { assertThat(mJavac.compile()).isTrue(); new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, - ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, emptySet())) + ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, NULL_SDK_MAP)) ).visit(); verify(mStatus, times(1)).error(any(), any()); @@ -179,12 +189,12 @@ public class GreylistAnnotationHandlerTest extends AnnotationHandlerTestBase { assertThat(mJavac.compile()).isTrue(); new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class$Inner"), mStatus, - ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, emptySet())) + ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, NULL_SDK_MAP)) ).visit(); assertNoErrors(); ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class); - verify(mConsumer, times(1)).greylistEntry(greylist.capture(), any(), any()); + verify(mConsumer, times(1)).consume(greylist.capture(), any(), any()); assertThat(greylist.getValue()).isEqualTo("La/b/Class$Inner;->method()V"); } @@ -198,11 +208,11 @@ public class GreylistAnnotationHandlerTest extends AnnotationHandlerTestBase { assertThat(mJavac.compile()).isTrue(); new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, - ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, emptySet())) + ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, NULL_SDK_MAP)) ).visit(); assertNoErrors(); - verify(mConsumer, never()).greylistEntry(any(String.class), any(), any()); + verify(mConsumer, never()).consume(any(String.class), any(), any()); } @Test @@ -217,12 +227,12 @@ public class GreylistAnnotationHandlerTest extends AnnotationHandlerTestBase { assertThat(mJavac.compile()).isTrue(); new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, - ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, emptySet())) + ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, NULL_SDK_MAP)) ).visit(); assertNoErrors(); ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class); - verify(mConsumer, times(1)).greylistEntry(greylist.capture(), any(), any()); + verify(mConsumer, times(1)).consume(greylist.capture(), any(), any()); assertThat(greylist.getValue()).isEqualTo("La/b/Class;->method(Ljava/lang/String;)V"); } @@ -245,14 +255,14 @@ public class GreylistAnnotationHandlerTest extends AnnotationHandlerTestBase { assertThat(mJavac.compile()).isTrue(); Map<String, AnnotationHandler> handlerMap = - ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, emptySet())); + ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, NULL_SDK_MAP)); new AnnotationVisitor(mJavac.getCompiledClass("a.b.Base"), mStatus, handlerMap).visit(); new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, handlerMap).visit(); assertNoErrors(); ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class); // A bridge method is generated for the above, so we expect 2 greylist entries. - verify(mConsumer, times(2)).greylistEntry(greylist.capture(), any(), any()); + verify(mConsumer, times(2)).consume(greylist.capture(), any(), any()); assertThat(greylist.getAllValues()).containsExactly( "La/b/Class;->method(Ljava/lang/Object;)V", "La/b/Class;->method(Ljava/lang/String;)V"); @@ -277,14 +287,14 @@ public class GreylistAnnotationHandlerTest extends AnnotationHandlerTestBase { assertThat(mJavac.compile()).isTrue(); Map<String, AnnotationHandler> handlerMap = - ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, emptySet())); + ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, NULL_SDK_MAP)); new AnnotationVisitor(mJavac.getCompiledClass("a.b.Base"), mStatus, handlerMap).visit(); new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, handlerMap).visit(); assertNoErrors(); ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class); // A bridge method is generated for the above, so we expect 2 greylist entries. - verify(mConsumer, times(2)).greylistEntry(greylist.capture(), any(), any()); + verify(mConsumer, times(2)).consume(greylist.capture(), any(), any()); assertThat(greylist.getAllValues()).containsExactly( "La/b/Class;->method(Ljava/lang/Object;)V", "La/b/Class;->method(Ljava/lang/String;)V"); @@ -313,7 +323,7 @@ public class GreylistAnnotationHandlerTest extends AnnotationHandlerTestBase { assertThat(mJavac.compile()).isTrue(); Map<String, AnnotationHandler> handlerMap = - ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, emptySet())); + ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, NULL_SDK_MAP)); new AnnotationVisitor(mJavac.getCompiledClass("a.b.Interface"), mStatus, handlerMap) .visit(); new AnnotationVisitor(mJavac.getCompiledClass("a.b.Base"), mStatus, handlerMap).visit(); @@ -322,7 +332,7 @@ public class GreylistAnnotationHandlerTest extends AnnotationHandlerTestBase { assertNoErrors(); ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class); // A bridge method is generated for the above, so we expect 2 greylist entries. - verify(mConsumer, times(2)).greylistEntry(greylist.capture(), any(), any()); + verify(mConsumer, times(2)).consume(greylist.capture(), any(), any()); assertThat(greylist.getAllValues()).containsExactly( "La/b/Class;->method(Ljava/lang/Object;)V", "La/b/Base;->method(Ljava/lang/Object;)V"); @@ -351,18 +361,18 @@ public class GreylistAnnotationHandlerTest extends AnnotationHandlerTestBase { "La/b/Class;->method(Ljava/lang/Object;)V"); Map<String, AnnotationHandler> handlerMap = ImmutableMap.of(ANNOTATION, - new GreylistAnnotationHandler( + new UnsupportedAppUsageAnnotationHandler( mStatus, mConsumer, publicApis, - x -> false)); + NULL_SDK_MAP)); new AnnotationVisitor(mJavac.getCompiledClass("a.b.Base"), mStatus, handlerMap).visit(); new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, handlerMap).visit(); assertNoErrors(); ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class); // The bridge method generated for the above, is a public API so should be excluded - verify(mConsumer, times(1)).greylistEntry(greylist.capture(), any(), any()); + verify(mConsumer, times(1)).consume(greylist.capture(), any(), any()); assertThat(greylist.getValue()).isEqualTo("La/b/Class;->method(Ljava/lang/String;)V"); } @@ -379,12 +389,12 @@ public class GreylistAnnotationHandlerTest extends AnnotationHandlerTestBase { Map<String, AnnotationHandler> handlerMap = ImmutableMap.of(ANNOTATION, createGreylistHandler( - member -> !member.bridge, // exclude bridge methods - emptySet())); + member -> !member.isBridgeMethod, // exclude bridge methods + NULL_SDK_MAP)); new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, handlerMap).visit(); assertNoErrors(); ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class); - verify(mConsumer, times(1)).greylistEntry(greylist.capture(), any(), any()); + verify(mConsumer, times(1)).consume(greylist.capture(), any(), any()); assertThat(greylist.getValue()).isEqualTo("La/b/Class;->field:I"); } @@ -400,7 +410,7 @@ public class GreylistAnnotationHandlerTest extends AnnotationHandlerTestBase { assertThat(mJavac.compile()).isTrue(); Map<String, AnnotationHandler> handlerMap = - ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, emptySet())); + ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, NULL_SDK_MAP)); new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, handlerMap).visit(); verify(mStatus, times(1)).error(any(), any()); } @@ -419,12 +429,10 @@ public class GreylistAnnotationHandlerTest extends AnnotationHandlerTestBase { Map<String, AnnotationHandler> handlerMap = ImmutableMap.of(ANNOTATION, createGreylistHandler( x -> true, - ImmutableSet.of(1))); + ImmutableMap.of(1, "flag1"))); new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, handlerMap).visit(); assertNoErrors(); - ArgumentCaptor<Integer> maxTargetSdk = ArgumentCaptor.forClass(Integer.class); - verify(mConsumer, times(1)).greylistEntry(any(), maxTargetSdk.capture(), any()); - assertThat(maxTargetSdk.getValue()).isEqualTo(1); + verify(mConsumer, times(1)).consume(any(), any(), eq(ImmutableSet.of("flag1"))); } @Test @@ -441,12 +449,10 @@ public class GreylistAnnotationHandlerTest extends AnnotationHandlerTestBase { Map<String, AnnotationHandler> handlerMap = ImmutableMap.of(ANNOTATION, createGreylistHandler( x -> true, - ImmutableSet.of(1))); + NULL_SDK_MAP)); new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, handlerMap).visit(); assertNoErrors(); - ArgumentCaptor<Integer> maxTargetSdk = ArgumentCaptor.forClass(Integer.class); - verify(mConsumer, times(1)).greylistEntry(any(), maxTargetSdk.capture(), any()); - assertThat(maxTargetSdk.getValue()).isEqualTo(null); + verify(mConsumer, times(1)).consume(any(), any(), eq(ImmutableSet.of("flag-null"))); } @Test @@ -463,7 +469,7 @@ public class GreylistAnnotationHandlerTest extends AnnotationHandlerTestBase { Map<String, AnnotationHandler> handlerMap = ImmutableMap.of(ANNOTATION, createGreylistHandler( x -> true, - ImmutableSet.of(1))); + NULL_SDK_MAP)); new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, handlerMap).visit(); verify(mStatus, times(1)).error(any(), any()); } @@ -490,12 +496,12 @@ public class GreylistAnnotationHandlerTest extends AnnotationHandlerTestBase { assertThat(mJavac.compile()).isTrue(); new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, ImmutableMap.of("Lannotation/Anno2;", createGreylistHandler(x -> true, - ImmutableSet.of(2))) + ImmutableMap.of(2, "flag2"))) ).visit(); assertNoErrors(); ArgumentCaptor<Map<String, String>> properties = ArgumentCaptor.forClass(Map.class); - verify(mConsumer, times(1)).greylistEntry(any(), any(), properties.capture()); + verify(mConsumer, times(1)).consume(any(), properties.capture(), any()); assertThat(properties.getValue()).containsExactly( "maxTargetSdk", "2", "trackingBug", "123456789"); diff --git a/tools/hiddenapi/hiddenapi.cc b/tools/hiddenapi/hiddenapi.cc index 7c93a8b283..3e38b97889 100644 --- a/tools/hiddenapi/hiddenapi.cc +++ b/tools/hiddenapi/hiddenapi.cc @@ -73,10 +73,11 @@ NO_RETURN static void Usage(const char* fmt, ...) { UsageError(" --output-dex=<filename>: file to write encoded dex into"); UsageError(" input and output dex files are paired in order of appearance"); UsageError(""); - UsageError(" --light-greylist=<filename>:"); - UsageError(" --dark-greylist=<filename>:"); - UsageError(" --blacklist=<filename>:"); - UsageError(" text files with signatures of methods/fields to be annotated"); + UsageError(" --api-flags=<filename>:"); + UsageError(" CSV file with signatures of methods/fields and their respective flags"); + UsageError(""); + UsageError(" --no-force-assign-all:"); + UsageError(" Disable check that all dex entries have been assigned a flag"); UsageError(""); UsageError(" Command \"list\": dump lists of public and private API"); UsageError(" --boot-dex=<filename>: dex file which belongs to boot class path"); @@ -857,7 +858,7 @@ class DexFileEditor final { class HiddenApi final { public: - HiddenApi() {} + HiddenApi() : force_assign_all_(true) {} void Run(int argc, char** argv) { switch (ParseArgs(argc, argv)) { @@ -890,12 +891,10 @@ class HiddenApi final { 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()); - } else if (option.starts_with("--light-greylist=")) { - light_greylist_path_ = option.substr(strlen("--light-greylist=")).ToString(); - } else if (option.starts_with("--dark-greylist=")) { - dark_greylist_path_ = option.substr(strlen("--dark-greylist=")).ToString(); - } else if (option.starts_with("--blacklist=")) { - blacklist_path_ = option.substr(strlen("--blacklist=")).ToString(); + } else if (option.starts_with("--api-flags=")) { + api_list_path_ = option.substr(strlen("--api-flags=")).ToString(); + } else if (option == "--no-force-assign-all") { + force_assign_all_ = false; } else { Usage("Unknown argument '%s'", option.data()); } @@ -934,10 +933,7 @@ class HiddenApi final { } // Load dex signatures. - std::map<std::string, hiddenapi::ApiList> api_list; - OpenApiFile(light_greylist_path_, api_list, hiddenapi::ApiList::Greylist()); - OpenApiFile(dark_greylist_path_, api_list, hiddenapi::ApiList::GreylistMaxO()); - OpenApiFile(blacklist_path_, api_list, hiddenapi::ApiList::Blacklist()); + std::map<std::string, hiddenapi::ApiList> api_list = OpenApiFile(api_list_path_); // Iterate over input dex files and insert HiddenapiClassData sections. for (size_t i = 0; i < boot_dex_paths_.size(); ++i) { @@ -950,14 +946,18 @@ class HiddenApi final { const DexFile& input_dex = *input_dex_files[0]; HiddenapiClassDataBuilder builder(input_dex); - boot_classpath.ForEachDexClass([&api_list, &builder](const DexClass& boot_class) { + boot_classpath.ForEachDexClass([&](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()) ? hiddenapi::ApiList::Whitelist() : it->second); + bool api_list_found = (it != api_list.end()); + // TODO: Fix ART buildbots and turn this into a CHECK. + if (force_assign_all_ && !api_list_found) { + LOG(WARNING) << "Could not find hiddenapi flags for dex entry: " + << boot_member.GetApiEntry(); + } + builder.WriteFlags(api_list_found ? it->second : hiddenapi::ApiList::Whitelist()); }; auto fn_field = [&](const ClassAccessor::Field& boot_field) { fn_shared(DexMember(boot_class, boot_field)); @@ -976,23 +976,29 @@ class HiddenApi final { } } - void OpenApiFile(const std::string& path, - std::map<std::string, hiddenapi::ApiList>& api_list, - hiddenapi::ApiList membership) { - if (path.empty()) { - return; - } - + std::map<std::string, hiddenapi::ApiList> OpenApiFile(const std::string& path) { + CHECK(!path.empty()); std::ifstream api_file(path, std::ifstream::in); CHECK(!api_file.fail()) << "Unable to open file '" << path << "' " << strerror(errno); + std::map<std::string, hiddenapi::ApiList> api_flag_map; + for (std::string line; std::getline(api_file, line);) { - CHECK(api_list.find(line) == api_list.end()) - << "Duplicate entry: " << line << " (" << api_list.find(line)->second - << " and " << membership << ")"; - api_list.emplace(line, membership); + std::vector<std::string> values = android::base::Split(line, ","); + CHECK_EQ(values.size(), 2u) << "Currently only signature and one flag are supported"; + + const std::string& signature = values[0]; + CHECK(api_flag_map.find(signature) == api_flag_map.end()) << "Duplicate entry: " << signature; + + const std::string& flag_str = values[1]; + hiddenapi::ApiList membership = hiddenapi::ApiList::FromName(flag_str); + CHECK(membership.IsValid()) << "Unknown ApiList name: " << flag_str; + + api_flag_map.emplace(signature, membership); } + api_file.close(); + return api_flag_map; } void ListApi() { @@ -1071,6 +1077,10 @@ class HiddenApi final { file_private.close(); } + // Whether to check that all dex entries have been assigned flags. + // Defaults to true. + bool force_assign_all_; + // Paths to DEX files which should be processed. std::vector<std::string> boot_dex_paths_; @@ -1082,9 +1092,7 @@ class HiddenApi final { std::vector<std::vector<std::string>> stub_classpaths_; // Paths to text files which contain the lists of API members. - std::string light_greylist_path_; - std::string dark_greylist_path_; - std::string blacklist_path_; + std::string api_list_path_; // Paths to text files to which we will output list of all API members. std::string out_public_path_; diff --git a/tools/hiddenapi/hiddenapi_test.cc b/tools/hiddenapi/hiddenapi_test.cc index 66ce2de5c5..f10d3f4e12 100644 --- a/tools/hiddenapi/hiddenapi_test.cc +++ b/tools/hiddenapi/hiddenapi_test.cc @@ -41,9 +41,7 @@ class HiddenApiTest : public CommonRuntimeTest { return file_path; } - std::unique_ptr<const DexFile> RunHiddenApi(const ScratchFile& light_greylist, - const ScratchFile& dark_greylist, - const ScratchFile& blacklist, + std::unique_ptr<const DexFile> RunHiddenApi(const ScratchFile& flags_csv, const std::vector<std::string>& extra_args, ScratchFile* out_dex) { std::string error; @@ -71,9 +69,8 @@ class HiddenApiTest : public CommonRuntimeTest { 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("--light-greylist=" + light_greylist.GetFilename()); - argv_str.push_back("--dark-greylist=" + dark_greylist.GetFilename()); - argv_str.push_back("--blacklist=" + blacklist.GetFilename()); + argv_str.push_back("--api-flags=" + flags_csv.GetFilename()); + argv_str.push_back("--no-force-assign-all"); int return_code = ExecAndReturnCode(argv_str, &error); if (return_code == 0) { return OpenDex(*out_dex); @@ -218,404 +215,428 @@ class HiddenApiTest : public CommonRuntimeTest { }; TEST_F(HiddenApiTest, InstanceFieldNoMatch) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->ifield:LBadType1;" << std::endl; - OpenStream(dark_greylist) << "LMain;->ifield:LBadType2;" << std::endl; - OpenStream(blacklist) << "LMain;->ifield:LBadType3;" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->ifield:LBadType1;,greylist" << std::endl + << "LMain;->ifield:LBadType2;,greylist-max-o" << std::endl + << "LMain;->ifield:LBadType3;,blacklist" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(hiddenapi::ApiList::Whitelist(), GetIFieldHiddenFlags(*dex_file)); } TEST_F(HiddenApiTest, InstanceFieldLightGreylistMatch) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->ifield:I" << std::endl; - OpenStream(dark_greylist) << "LMain;->ifield:LBadType2;" << std::endl; - OpenStream(blacklist) << "LMain;->ifield:LBadType3;" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->ifield:I,greylist" << std::endl + << "LMain;->ifield:LBadType2;,greylist-max-o" << std::endl + << "LMain;->ifield:LBadType3;,blacklist" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(hiddenapi::ApiList::Greylist(), GetIFieldHiddenFlags(*dex_file)); } TEST_F(HiddenApiTest, InstanceFieldDarkGreylistMatch) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->ifield:LBadType1;" << std::endl; - OpenStream(dark_greylist) << "LMain;->ifield:I" << std::endl; - OpenStream(blacklist) << "LMain;->ifield:LBadType3;" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->ifield:LBadType1;,greylist" << std::endl + << "LMain;->ifield:I,greylist-max-o" << std::endl + << "LMain;->ifield:LBadType3;,blacklist" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(hiddenapi::ApiList::GreylistMaxO(), GetIFieldHiddenFlags(*dex_file)); } TEST_F(HiddenApiTest, InstanceFieldBlacklistMatch) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->ifield:LBadType1;" << std::endl; - OpenStream(dark_greylist) << "LMain;->ifield:LBadType2;" << std::endl; - OpenStream(blacklist) << "LMain;->ifield:I" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->ifield:LBadType1;,greylist" << std::endl + << "LMain;->ifield:LBadType2;,greylist-max-o" << std::endl + << "LMain;->ifield:I,blacklist" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(hiddenapi::ApiList::Blacklist(), GetIFieldHiddenFlags(*dex_file)); } TEST_F(HiddenApiTest, InstanceFieldTwoListsMatch1) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->ifield:LBadType1;" << std::endl; - OpenStream(dark_greylist) << "LMain;->ifield:I" << std::endl; - OpenStream(blacklist) << "LMain;->ifield:I" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->ifield:LBadType1;,greylist" << std::endl + << "LMain;->ifield:I,blacklist,greylist-max-o" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_EQ(dex_file.get(), nullptr); } TEST_F(HiddenApiTest, InstanceFieldTwoListsMatch2) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->ifield:I" << std::endl; - OpenStream(dark_greylist) << "LMain;->ifield:LBadType2;" << std::endl; - OpenStream(blacklist) << "LMain;->ifield:I" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->ifield:LBadType2;,greylist-max-o" << std::endl + << "LMain;->ifield:I,blacklist,greylist" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_EQ(dex_file.get(), nullptr); } TEST_F(HiddenApiTest, InstanceFieldTwoListsMatch3) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->ifield:I" << std::endl; - OpenStream(dark_greylist) << "LMain;->ifield:I" << std::endl; - OpenStream(blacklist) << "LMain;->ifield:LBadType3;" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->ifield:I,greylist,greylist-max-o" << std::endl + << "LMain;->ifield:LBadType3;,blacklist" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_EQ(dex_file.get(), nullptr); } TEST_F(HiddenApiTest, StaticFieldNoMatch) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->sfield:LBadType1;" << std::endl; - OpenStream(dark_greylist) << "LMain;->sfield:LBadType2;" << std::endl; - OpenStream(blacklist) << "LMain;->sfield:LBadType3;" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->sfield:LBadType1;,greylist" << std::endl + << "LMain;->sfield:LBadType2;,greylist-max-o" << std::endl + << "LMain;->sfield:LBadType3;,blacklist" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(hiddenapi::ApiList::Whitelist(), GetSFieldHiddenFlags(*dex_file)); } TEST_F(HiddenApiTest, StaticFieldLightGreylistMatch) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->sfield:Ljava/lang/Object;" << std::endl; - OpenStream(dark_greylist) << "LMain;->sfield:LBadType2;" << std::endl; - OpenStream(blacklist) << "LMain;->sfield:LBadType3;" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->sfield:Ljava/lang/Object;,greylist" << std::endl + << "LMain;->sfield:LBadType2;,greylist-max-o" << std::endl + << "LMain;->sfield:LBadType3;,blacklist" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(hiddenapi::ApiList::Greylist(), GetSFieldHiddenFlags(*dex_file)); } TEST_F(HiddenApiTest, StaticFieldDarkGreylistMatch) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->sfield:LBadType1;" << std::endl; - OpenStream(dark_greylist) << "LMain;->sfield:Ljava/lang/Object;" << std::endl; - OpenStream(blacklist) << "LMain;->sfield:LBadType3;" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->sfield:LBadType1;,greylist" << std::endl + << "LMain;->sfield:Ljava/lang/Object;,greylist-max-o" << std::endl + << "LMain;->sfield:LBadType3;,blacklist" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(hiddenapi::ApiList::GreylistMaxO(), GetSFieldHiddenFlags(*dex_file)); } TEST_F(HiddenApiTest, StaticFieldBlacklistMatch) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->sfield:LBadType1;" << std::endl; - OpenStream(dark_greylist) << "LMain;->sfield:LBadType2;" << std::endl; - OpenStream(blacklist) << "LMain;->sfield:Ljava/lang/Object;" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->sfield:LBadType1;,greylist" << std::endl + << "LMain;->sfield:LBadType2;,greylist-max-o" << std::endl + << "LMain;->sfield:Ljava/lang/Object;,blacklist" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(hiddenapi::ApiList::Blacklist(), GetSFieldHiddenFlags(*dex_file)); } TEST_F(HiddenApiTest, StaticFieldTwoListsMatch1) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->sfield:LBadType1;" << std::endl; - OpenStream(dark_greylist) << "LMain;->sfield:Ljava/lang/Object;" << std::endl; - OpenStream(blacklist) << "LMain;->sfield:Ljava/lang/Object;" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->sfield:LBadType1;,greylist" << std::endl + << "LMain;->sfield:Ljava/lang/Object;,blacklist,greylist-max-o" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_EQ(dex_file.get(), nullptr); } TEST_F(HiddenApiTest, StaticFieldTwoListsMatch2) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->sfield:Ljava/lang/Object;" << std::endl; - OpenStream(dark_greylist) << "LMain;->sfield:LBadType2;" << std::endl; - OpenStream(blacklist) << "LMain;->sfield:Ljava/lang/Object;" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->sfield:LBadType2;,greylist-max-o" << std::endl + << "LMain;->sfield:Ljava/lang/Object;,blacklist,greylist" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_EQ(dex_file.get(), nullptr); } TEST_F(HiddenApiTest, StaticFieldTwoListsMatch3) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->sfield:Ljava/lang/Object;" << std::endl; - OpenStream(dark_greylist) << "LMain;->sfield:Ljava/lang/Object;" << std::endl; - OpenStream(blacklist) << "LMain;->sfield:LBadType3;" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->sfield:Ljava/lang/Object;,greylist,greylist-max-o" << std::endl + << "LMain;->sfield:LBadType3;,blacklist" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_EQ(dex_file.get(), nullptr); } TEST_F(HiddenApiTest, InstanceMethodNoMatch) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->imethod(LBadType1;)V" << std::endl; - OpenStream(dark_greylist) << "LMain;->imethod(LBadType2;)V" << std::endl; - OpenStream(blacklist) << "LMain;->imethod(LBadType3;)V" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->imethod(LBadType1;)V,greylist" << std::endl + << "LMain;->imethod(LBadType2;)V,greylist-max-o" << std::endl + << "LMain;->imethod(LBadType3;)V,blacklist" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(hiddenapi::ApiList::Whitelist(), GetIMethodHiddenFlags(*dex_file)); } TEST_F(HiddenApiTest, InstanceMethodLightGreylistMatch) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->imethod(J)V" << std::endl; - OpenStream(dark_greylist) << "LMain;->imethod(LBadType2;)V" << std::endl; - OpenStream(blacklist) << "LMain;->imethod(LBadType3;)V" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->imethod(J)V,greylist" << std::endl + << "LMain;->imethod(LBadType2;)V,greylist-max-o" << std::endl + << "LMain;->imethod(LBadType3;)V,blacklist" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(hiddenapi::ApiList::Greylist(), GetIMethodHiddenFlags(*dex_file)); } TEST_F(HiddenApiTest, InstanceMethodDarkGreylistMatch) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->imethod(LBadType1;)V" << std::endl; - OpenStream(dark_greylist) << "LMain;->imethod(J)V" << std::endl; - OpenStream(blacklist) << "LMain;->imethod(LBadType3;)V" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->imethod(LBadType1;)V,greylist" << std::endl + << "LMain;->imethod(J)V,greylist-max-o" << std::endl + << "LMain;->imethod(LBadType3;)V,blacklist" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(hiddenapi::ApiList::GreylistMaxO(), GetIMethodHiddenFlags(*dex_file)); } TEST_F(HiddenApiTest, InstanceMethodBlacklistMatch) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->imethod(LBadType1;)V" << std::endl; - OpenStream(dark_greylist) << "LMain;->imethod(LBadType2;)V" << std::endl; - OpenStream(blacklist) << "LMain;->imethod(J)V" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->imethod(LBadType1;)V,greylist" << std::endl + << "LMain;->imethod(LBadType2;)V,greylist-max-o" << std::endl + << "LMain;->imethod(J)V,blacklist" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(hiddenapi::ApiList::Blacklist(), GetIMethodHiddenFlags(*dex_file)); } TEST_F(HiddenApiTest, InstanceMethodTwoListsMatch1) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->imethod(LBadType1;)V" << std::endl; - OpenStream(dark_greylist) << "LMain;->imethod(J)V" << std::endl; - OpenStream(blacklist) << "LMain;->imethod(J)V" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->imethod(LBadType1;)V,greylist" << std::endl + << "LMain;->imethod(J)V,blacklist,greylist-max-o" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_EQ(dex_file.get(), nullptr); } TEST_F(HiddenApiTest, InstanceMethodTwoListsMatch2) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->imethod(J)V" << std::endl; - OpenStream(dark_greylist) << "LMain;->imethod(LBadType2;)V" << std::endl; - OpenStream(blacklist) << "LMain;->imethod(J)V" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->imethod(LBadType2;)V,greylist-max-o" << std::endl + << "LMain;->imethod(J)V,blacklist,greylist" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_EQ(dex_file.get(), nullptr); } TEST_F(HiddenApiTest, InstanceMethodTwoListsMatch3) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->imethod(J)V" << std::endl; - OpenStream(dark_greylist) << "LMain;->imethod(J)V" << std::endl; - OpenStream(blacklist) << "LMain;->imethod(LBadType3;)V" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->imethod(J)V,greylist,greylist-max-o" << std::endl + << "LMain;->imethod(LBadType3;)V,blacklist" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_EQ(dex_file.get(), nullptr); } TEST_F(HiddenApiTest, StaticMethodNoMatch) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->smethod(LBadType1;)V" << std::endl; - OpenStream(dark_greylist) << "LMain;->smethod(LBadType2;)V" << std::endl; - OpenStream(blacklist) << "LMain;->smethod(LBadType3;)V" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->smethod(LBadType1;)V,greylist" << std::endl + << "LMain;->smethod(LBadType2;)V,greylist-max-o" << std::endl + << "LMain;->smethod(LBadType3;)V,blacklist" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(hiddenapi::ApiList::Whitelist(), GetSMethodHiddenFlags(*dex_file)); } TEST_F(HiddenApiTest, StaticMethodLightGreylistMatch) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->smethod(Ljava/lang/Object;)V" << std::endl; - OpenStream(dark_greylist) << "LMain;->smethod(LBadType2;)V" << std::endl; - OpenStream(blacklist) << "LMain;->smethod(LBadType3;)V" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->smethod(Ljava/lang/Object;)V,greylist" << std::endl + << "LMain;->smethod(LBadType2;)V,greylist-max-o" << std::endl + << "LMain;->smethod(LBadType3;)V,blacklist" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(hiddenapi::ApiList::Greylist(), GetSMethodHiddenFlags(*dex_file)); } TEST_F(HiddenApiTest, StaticMethodDarkGreylistMatch) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->smethod(LBadType1;)V" << std::endl; - OpenStream(dark_greylist) << "LMain;->smethod(Ljava/lang/Object;)V" << std::endl; - OpenStream(blacklist) << "LMain;->smethod(LBadType3;)V" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->smethod(LBadType1;)V,greylist" << std::endl + << "LMain;->smethod(Ljava/lang/Object;)V,greylist-max-o" << std::endl + << "LMain;->smethod(LBadType3;)V,blacklist" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(hiddenapi::ApiList::GreylistMaxO(), GetSMethodHiddenFlags(*dex_file)); } TEST_F(HiddenApiTest, StaticMethodBlacklistMatch) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->smethod(LBadType1;)V" << std::endl; - OpenStream(dark_greylist) << "LMain;->smethod(LBadType2;)V" << std::endl; - OpenStream(blacklist) << "LMain;->smethod(Ljava/lang/Object;)V" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->smethod(LBadType1;)V,greylist" << std::endl + << "LMain;->smethod(LBadType2;)V,greylist-max-o" << std::endl + << "LMain;->smethod(Ljava/lang/Object;)V,blacklist" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(hiddenapi::ApiList::Blacklist(), GetSMethodHiddenFlags(*dex_file)); } TEST_F(HiddenApiTest, StaticMethodTwoListsMatch1) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->smethod(LBadType1;)V" << std::endl; - OpenStream(dark_greylist) << "LMain;->smethod(Ljava/lang/Object;)V" << std::endl; - OpenStream(blacklist) << "LMain;->smethod(Ljava/lang/Object;)V" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->smethod(LBadType1;)V,greylist" << std::endl + << "LMain;->smethod(Ljava/lang/Object;)V,blacklist,greylist-max-o" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_EQ(dex_file.get(), nullptr); } TEST_F(HiddenApiTest, StaticMethodTwoListsMatch2) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->smethod(Ljava/lang/Object;)V" << std::endl; - OpenStream(dark_greylist) << "LMain;->smethod(LBadType2;)V" << std::endl; - OpenStream(blacklist) << "LMain;->smethod(Ljava/lang/Object;)V" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->smethod(LBadType2;)V,greylist-max-o" << std::endl + << "LMain;->smethod(Ljava/lang/Object;)V,blacklist,greylist" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_EQ(dex_file.get(), nullptr); } TEST_F(HiddenApiTest, StaticMethodTwoListsMatch3) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->smethod(Ljava/lang/Object;)V" << std::endl; - OpenStream(dark_greylist) << "LMain;->smethod(Ljava/lang/Object;)V" << std::endl; - OpenStream(blacklist) << "LMain;->smethod(LBadType3;)V" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->smethod(Ljava/lang/Object;)V,greylist,greylist-max-o" << std::endl + << "LMain;->smethod(LBadType3;)V,blacklist" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_EQ(dex_file.get(), nullptr); } TEST_F(HiddenApiTest, InstanceNativeMethodNoMatch) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->inmethod(LBadType1;)V" << std::endl; - OpenStream(dark_greylist) << "LMain;->inmethod(LBadType2;)V" << std::endl; - OpenStream(blacklist) << "LMain;->inmethod(LBadType3;)V" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->inmethod(LBadType1;)V,greylist" << std::endl + << "LMain;->inmethod(LBadType2;)V,greylist-max-o" << std::endl + << "LMain;->inmethod(LBadType3;)V,blacklist" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(hiddenapi::ApiList::Whitelist(), GetINMethodHiddenFlags(*dex_file)); } TEST_F(HiddenApiTest, InstanceNativeMethodLightGreylistMatch) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->inmethod(C)V" << std::endl; - OpenStream(dark_greylist) << "LMain;->inmethod(LBadType2;)V" << std::endl; - OpenStream(blacklist) << "LMain;->inmethod(LBadType3;)V" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->inmethod(C)V,greylist" << std::endl + << "LMain;->inmethod(LBadType2;)V,greylist-max-o" << std::endl + << "LMain;->inmethod(LBadType3;)V,blacklist" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(hiddenapi::ApiList::Greylist(), GetINMethodHiddenFlags(*dex_file)); } TEST_F(HiddenApiTest, InstanceNativeMethodDarkGreylistMatch) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->inmethod(LBadType1;)V" << std::endl; - OpenStream(dark_greylist) << "LMain;->inmethod(C)V" << std::endl; - OpenStream(blacklist) << "LMain;->inmethod(LBadType3;)V" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->inmethod(LBadType1;)V,greylist" << std::endl + << "LMain;->inmethod(C)V,greylist-max-o" << std::endl + << "LMain;->inmethod(LBadType3;)V,blacklist" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(hiddenapi::ApiList::GreylistMaxO(), GetINMethodHiddenFlags(*dex_file)); } TEST_F(HiddenApiTest, InstanceNativeMethodBlacklistMatch) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->inmethod(LBadType1;)V" << std::endl; - OpenStream(dark_greylist) << "LMain;->inmethod(LBadType2;)V" << std::endl; - OpenStream(blacklist) << "LMain;->inmethod(C)V" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->inmethod(LBadType1;)V,greylist" << std::endl + << "LMain;->inmethod(LBadType2;)V,greylist-max-o" << std::endl + << "LMain;->inmethod(C)V,blacklist" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(hiddenapi::ApiList::Blacklist(), GetINMethodHiddenFlags(*dex_file)); } TEST_F(HiddenApiTest, InstanceNativeMethodTwoListsMatch1) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->inmethod(LBadType1;)V" << std::endl; - OpenStream(dark_greylist) << "LMain;->inmethod(C)V" << std::endl; - OpenStream(blacklist) << "LMain;->inmethod(C)V" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->inmethod(LBadType1;)V,greylist" << std::endl + << "LMain;->inmethod(C)V,blacklist,greylist-max-o" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_EQ(dex_file.get(), nullptr); } TEST_F(HiddenApiTest, InstanceNativeMethodTwoListsMatch2) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->inmethod(C)V" << std::endl; - OpenStream(dark_greylist) << "LMain;->inmethod(LBadType2;)V" << std::endl; - OpenStream(blacklist) << "LMain;->inmethod(C)V" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->inmethod(C)V,blacklist,greylist" << std::endl + << "LMain;->inmethod(LBadType2;)V,greylist-max-o" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_EQ(dex_file.get(), nullptr); } TEST_F(HiddenApiTest, InstanceNativeMethodTwoListsMatch3) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->inmethod(C)V" << std::endl; - OpenStream(dark_greylist) << "LMain;->inmethod(C)V" << std::endl; - OpenStream(blacklist) << "LMain;->inmethod(LBadType3;)V" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->inmethod(C)V,greylist,greylist-max-o" << std::endl + << "LMain;->inmethod(LBadType3;)V,blacklist" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_EQ(dex_file.get(), nullptr); } TEST_F(HiddenApiTest, StaticNativeMethodNoMatch) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->snmethod(LBadType1;)V" << std::endl; - OpenStream(dark_greylist) << "LMain;->snmethod(LBadType2;)V" << std::endl; - OpenStream(blacklist) << "LMain;->snmethod(LBadType3;)V" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->snmethod(LBadType1;)V,greylist" << std::endl + << "LMain;->snmethod(LBadType2;)V,greylist-max-o" << std::endl + << "LMain;->snmethod(LBadType3;)V,blacklist" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(hiddenapi::ApiList::Whitelist(), GetSNMethodHiddenFlags(*dex_file)); } TEST_F(HiddenApiTest, StaticNativeMethodLightGreylistMatch) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->snmethod(Ljava/lang/Integer;)V" << std::endl; - OpenStream(dark_greylist) << "LMain;->snmethod(LBadType2;)V" << std::endl; - OpenStream(blacklist) << "LMain;->snmethod(LBadType3;)V" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->snmethod(Ljava/lang/Integer;)V,greylist" << std::endl + << "LMain;->snmethod(LBadType2;)V,greylist-max-o" << std::endl + << "LMain;->snmethod(LBadType3;)V,blacklist" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(hiddenapi::ApiList::Greylist(), GetSNMethodHiddenFlags(*dex_file)); } TEST_F(HiddenApiTest, StaticNativeMethodDarkGreylistMatch) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->snmethod(LBadType1;)V" << std::endl; - OpenStream(dark_greylist) << "LMain;->snmethod(Ljava/lang/Integer;)V" << std::endl; - OpenStream(blacklist) << "LMain;->snmethod(LBadType3;)V" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->snmethod(LBadType1;)V,greylist" << std::endl + << "LMain;->snmethod(Ljava/lang/Integer;)V,greylist-max-o" << std::endl + << "LMain;->snmethod(LBadType3;)V,blacklist" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(hiddenapi::ApiList::GreylistMaxO(), GetSNMethodHiddenFlags(*dex_file)); } TEST_F(HiddenApiTest, StaticNativeMethodBlacklistMatch) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->snmethod(LBadType1;)V" << std::endl; - OpenStream(dark_greylist) << "LMain;->snmethod(LBadType2;)V" << std::endl; - OpenStream(blacklist) << "LMain;->snmethod(Ljava/lang/Integer;)V" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->snmethod(LBadType1;)V,greylist" << std::endl + << "LMain;->snmethod(LBadType2;)V,greylist-max-o" << std::endl + << "LMain;->snmethod(Ljava/lang/Integer;)V,blacklist" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(hiddenapi::ApiList::Blacklist(), GetSNMethodHiddenFlags(*dex_file)); } TEST_F(HiddenApiTest, StaticNativeMethodTwoListsMatch1) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->snmethod(LBadType1;)V" << std::endl; - OpenStream(dark_greylist) << "LMain;->snmethod(Ljava/lang/Integer;)V" << std::endl; - OpenStream(blacklist) << "LMain;->snmethod(Ljava/lang/Integer;)V" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->snmethod(LBadType1;)V,greylist" << std::endl + << "LMain;->snmethod(Ljava/lang/Integer;)V,blacklist,greylist-max-o" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_EQ(dex_file.get(), nullptr); } TEST_F(HiddenApiTest, StaticNativeMethodTwoListsMatch2) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->snmethod(Ljava/lang/Integer;)V" << std::endl; - OpenStream(dark_greylist) << "LMain;->snmethod(LBadType2;)V" << std::endl; - OpenStream(blacklist) << "LMain;->snmethod(Ljava/lang/Integer;)V" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->snmethod(Ljava/lang/Integer;)V,blacklist,greylist" << std::endl + << "LMain;->snmethod(LBadType2;)V,greylist-max-o" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_EQ(dex_file.get(), nullptr); } TEST_F(HiddenApiTest, StaticNativeMethodTwoListsMatch3) { - ScratchFile dex, light_greylist, dark_greylist, blacklist; - OpenStream(light_greylist) << "LMain;->snmethod(Ljava/lang/Integer;)V" << std::endl; - OpenStream(dark_greylist) << "LMain;->snmethod(Ljava/lang/Integer;)V" << std::endl; - OpenStream(blacklist) << "LMain;->snmethod(LBadType3;)V" << std::endl; - auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ScratchFile dex, flags_csv; + OpenStream(flags_csv) + << "LMain;->snmethod(Ljava/lang/Integer;)V,greylist,greylist-max-o" << std::endl + << "LMain;->snmethod(LBadType3;)V,blacklist" << std::endl; + auto dex_file = RunHiddenApi(flags_csv, {}, &dex); ASSERT_EQ(dex_file.get(), nullptr); } diff --git a/tools/timeout_dumper/timeout_dumper.cc b/tools/timeout_dumper/timeout_dumper.cc index 30e194ceda..96d165c5c7 100644 --- a/tools/timeout_dumper/timeout_dumper.cc +++ b/tools/timeout_dumper/timeout_dumper.cc @@ -432,7 +432,7 @@ void DumpThread(pid_t pid, LOG(ERROR) << prefix << "(failed to create Backtrace for thread " << tid << ")"; return; } - backtrace->SetSkipFrames(0); + backtrace->SetSkipFrames(false); if (!backtrace->Unwind(0, nullptr)) { LOG(ERROR) << prefix << "(backtrace::Unwind failed for thread " << tid << ": " << backtrace->GetErrorString(backtrace->GetError()) << ")"; diff --git a/tools/titrace/instruction_decoder.cc b/tools/titrace/instruction_decoder.cc index 89904b32cd..6f497b3c04 100644 --- a/tools/titrace/instruction_decoder.cc +++ b/tools/titrace/instruction_decoder.cc @@ -456,9 +456,10 @@ class ClassInstructionDecoder : public InstructionDecoder { case kBreakpoint: return "breakpoint"; case kImpdep1: return "impdep1"; case kImpdep2: return "impdep2"; - default: LOG(FATAL) << "Unknown opcode " << op; + default: + LOG(FATAL) << "Unknown opcode " << op; + __builtin_unreachable(); } - return ""; } }; }; @@ -500,7 +501,7 @@ DEX_INSTRUCTION_LIST(MAKE_ENUM_DEFINITION) #undef MAKE_ENUM_DEFINITION default: LOG(FATAL) << "Unknown opcode " << op; } - return ""; + __builtin_unreachable(); } }; }; diff --git a/tools/veridex/Android.mk b/tools/veridex/Android.mk index c0b5ca1189..c510a5174e 100644 --- a/tools/veridex/Android.mk +++ b/tools/veridex/Android.mk @@ -30,15 +30,10 @@ $(oahl_stub_dex): PRIVATE_MIN_SDK_VERSION := 1000 $(oahl_stub_dex): $(call get-prebuilt-sdk-dir,current)/org.apache.http.legacy.jar | $(ZIP2ZIP) $(DX) $(transform-classes.jar-to-dex) -app_compat_lists := \ - $(INTERNAL_PLATFORM_HIDDENAPI_WHITELIST) \ - $(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST) \ - $(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST) \ - $(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST) - # Phony rule to create all dependencies of the appcompat.sh script. .PHONY: appcompat -appcompat: $(system_stub_dex) $(oahl_stub_dex) $(HOST_OUT_EXECUTABLES)/veridex $(app_compat_lists) +appcompat: $(system_stub_dex) $(oahl_stub_dex) $(HOST_OUT_EXECUTABLES)/veridex \ + $(INTERNAL_PLATFORM_HIDDENAPI_FLAGS) VERIDEX_FILES_PATH := \ $(call intermediates-dir-for,PACKAGING,veridex,HOST)/veridex.zip @@ -46,12 +41,12 @@ VERIDEX_FILES_PATH := \ VERIDEX_FILES := $(LOCAL_PATH)/appcompat.sh $(VERIDEX_FILES_PATH): PRIVATE_VERIDEX_FILES := $(VERIDEX_FILES) -$(VERIDEX_FILES_PATH): PRIVATE_APP_COMPAT_LISTS := $(app_compat_lists) $(VERIDEX_FILES_PATH): PRIVATE_SYSTEM_STUBS_DEX_DIR := $(dir $(system_stub_dex)) $(VERIDEX_FILES_PATH): PRIVATE_SYSTEM_STUBS_ZIP := $(dir $(VERIDEX_FILES_PATH))/system-stubs.zip $(VERIDEX_FILES_PATH): PRIVATE_OAHL_STUBS_DEX_DIR := $(dir $(oahl_stub_dex)) $(VERIDEX_FILES_PATH): PRIVATE_OAHL_STUBS_ZIP := $(dir $(VERIDEX_FILES_PATH))/org.apache.http.legacy-stubs.zip -$(VERIDEX_FILES_PATH) : $(SOONG_ZIP) $(VERIDEX_FILES) $(app_compat_lists) $(HOST_OUT_EXECUTABLES)/veridex $(system_stub_dex) $(oahl_stub_dex) +$(VERIDEX_FILES_PATH) : $(SOONG_ZIP) $(VERIDEX_FILES) $(INTERNAL_PLATFORM_HIDDENAPI_FLAGS) \ + $(HOST_OUT_EXECUTABLES)/veridex $(system_stub_dex) $(oahl_stub_dex) rm -rf $(dir $@)/* ls -1 $(PRIVATE_SYSTEM_STUBS_DEX_DIR)/classes*.dex | sort >$(PRIVATE_SYSTEM_STUBS_ZIP).list $(SOONG_ZIP) -o $(PRIVATE_SYSTEM_STUBS_ZIP) -C $(PRIVATE_SYSTEM_STUBS_DEX_DIR) -l $(PRIVATE_SYSTEM_STUBS_ZIP).list @@ -60,10 +55,11 @@ $(VERIDEX_FILES_PATH) : $(SOONG_ZIP) $(VERIDEX_FILES) $(app_compat_lists) $(HOST $(SOONG_ZIP) -o $(PRIVATE_OAHL_STUBS_ZIP) -C $(PRIVATE_OAHL_STUBS_DEX_DIR) -l $(PRIVATE_OAHL_STUBS_ZIP).list rm $(PRIVATE_OAHL_STUBS_ZIP).list $(SOONG_ZIP) -o $@ -C art/tools/veridex -f $(PRIVATE_VERIDEX_FILES) \ - -C $(dir $(lastword $(PRIVATE_APP_COMPAT_LISTS))) $(addprefix -f , $(PRIVATE_APP_COMPAT_LISTS)) \ - -C $(HOST_OUT_EXECUTABLES) -f $(HOST_OUT_EXECUTABLES)/veridex \ - -C $(dir $(PRIVATE_SYSTEM_STUBS_ZIP)) -f $(PRIVATE_SYSTEM_STUBS_ZIP) \ - -C $(dir $(PRIVATE_OAHL_STUBS_ZIP)) -f $(PRIVATE_OAHL_STUBS_ZIP) + -C $(dir $(INTERNAL_PLATFORM_HIDDENAPI_FLAGS)) \ + -f $(INTERNAL_PLATFORM_HIDDENAPI_FLAGS) \ + -C $(HOST_OUT_EXECUTABLES) -f $(HOST_OUT_EXECUTABLES)/veridex \ + -C $(dir $(PRIVATE_SYSTEM_STUBS_ZIP)) -f $(PRIVATE_SYSTEM_STUBS_ZIP) \ + -C $(dir $(PRIVATE_OAHL_STUBS_ZIP)) -f $(PRIVATE_OAHL_STUBS_ZIP) rm -f $(PRIVATE_SYSTEM_STUBS_ZIP) rm -f $(PRIVATE_OAHL_STUBS_ZIP) @@ -71,6 +67,5 @@ $(VERIDEX_FILES_PATH) : $(SOONG_ZIP) $(VERIDEX_FILES) $(app_compat_lists) $(HOST $(call dist-for-goals,sdk,$(VERIDEX_FILES_PATH)) VERIDEX_FILES := -app_compat_lists := system_stub_dex := oahl_stub_dex := diff --git a/tools/veridex/appcompat.sh b/tools/veridex/appcompat.sh index f57c8a4799..46d62db910 100755 --- a/tools/veridex/appcompat.sh +++ b/tools/veridex/appcompat.sh @@ -22,18 +22,12 @@ echo "that do not exist. It can also miss on reflection uses." SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" if [[ -e ${SCRIPT_DIR}/veridex && \ - -e ${SCRIPT_DIR}/hiddenapi-whitelist.txt && \ - -e ${SCRIPT_DIR}/hiddenapi-blacklist.txt && \ - -e ${SCRIPT_DIR}/hiddenapi-light-greylist.txt && \ - -e ${SCRIPT_DIR}/hiddenapi-dark-greylist.txt && \ + -e ${SCRIPT_DIR}/hiddenapi-flags.csv && \ -e ${SCRIPT_DIR}/org.apache.http.legacy-stubs.zip && \ -e ${SCRIPT_DIR}/system-stubs.zip ]]; then exec ${SCRIPT_DIR}/veridex \ --core-stubs=${SCRIPT_DIR}/system-stubs.zip:${SCRIPT_DIR}/org.apache.http.legacy-stubs.zip \ - --whitelist=${SCRIPT_DIR}/hiddenapi-whitelist.txt \ - --blacklist=${SCRIPT_DIR}/hiddenapi-blacklist.txt \ - --light-greylist=${SCRIPT_DIR}/hiddenapi-light-greylist.txt \ - --dark-greylist=${SCRIPT_DIR}/hiddenapi-dark-greylist.txt \ + --api-flags=${SCRIPT_DIR}/hiddenapi-flags.csv \ $@ fi @@ -66,8 +60,5 @@ fi ${ANDROID_HOST_OUT}/bin/veridex \ --core-stubs=${PACKAGING}/core_dex_intermediates/classes.dex:${PACKAGING}/oahl_dex_intermediates/classes.dex \ - --whitelist=${PACKAGING}/hiddenapi-whitelist.txt \ - --blacklist=${PACKAGING}/hiddenapi-blacklist.txt \ - --light-greylist=${PACKAGING}/hiddenapi-light-greylist.txt \ - --dark-greylist=${PACKAGING}/hiddenapi-dark-greylist.txt \ + --api-flags=${PACKAGING}/hiddenapi-flags.csv \ $@ diff --git a/tools/veridex/hidden_api.cc b/tools/veridex/hidden_api.cc index 17fa1b8513..6a04365a3a 100644 --- a/tools/veridex/hidden_api.cc +++ b/tools/veridex/hidden_api.cc @@ -19,10 +19,63 @@ #include <fstream> #include <sstream> +#include "android-base/strings.h" #include "dex/dex_file-inl.h" namespace art { +HiddenApi::HiddenApi(const char* filename, bool sdk_uses_only) { + CHECK(filename != nullptr); + + std::ifstream in(filename); + for (std::string str; std::getline(in, str);) { + std::vector<std::string> values = android::base::Split(str, ","); + CHECK_EQ(values.size(), 2u) << "Currently only signature and one flag are supported"; + + const std::string& signature = values[0]; + const std::string& flag_str = values[1]; + + hiddenapi::ApiList membership = hiddenapi::ApiList::FromName(flag_str); + CHECK(membership.IsValid()) << "Unknown ApiList name: " << flag_str; + + if (sdk_uses_only != (membership == hiddenapi::ApiList::Whitelist())) { + // Either we want only SDK uses and this is not a whitelist entry, + // or we want only non-SDK uses and this is a whitelist entry. + continue; + } + + AddSignatureToApiList(signature, membership); + size_t pos = signature.find("->"); + if (pos != std::string::npos) { + // Add the class name. + AddSignatureToApiList(signature.substr(0, pos), membership); + pos = signature.find('('); + if (pos != std::string::npos) { + // Add the class->method name (so stripping the signature). + AddSignatureToApiList(signature.substr(0, pos), membership); + } + pos = signature.find(':'); + if (pos != std::string::npos) { + // Add the class->field name (so stripping the type). + AddSignatureToApiList(signature.substr(0, pos), membership); + } + } + } +} + +void HiddenApi::AddSignatureToApiList(const std::string& signature, hiddenapi::ApiList membership) { + auto it = api_list_.find(signature); + if (it == api_list_.end()) { + // Does not exist yet. Add it to list. + api_list_.emplace(signature, membership); + } else if (membership.GetMaxAllowedSdkVersion() < it->second.GetMaxAllowedSdkVersion()) { + // Already exist but `membership` is more restrictive. + it->second = membership; + } else { + // Already exists and `membership` is equally or less restrictive. + } +} + std::string HiddenApi::GetApiMethodName(const DexFile& dex_file, uint32_t method_index) { std::stringstream ss; const DexFile::MethodId& method_id = dex_file.GetMethodId(method_index); @@ -44,30 +97,4 @@ std::string HiddenApi::GetApiFieldName(const DexFile& dex_file, uint32_t field_i return ss.str(); } -void HiddenApi::FillList(const char* filename, std::set<std::string>& entries) { - if (filename == nullptr) { - return; - } - std::ifstream in(filename); - std::string str; - while (std::getline(in, str)) { - entries.insert(str); - size_t pos = str.find("->"); - if (pos != std::string::npos) { - // Add the class name. - entries.insert(str.substr(0, pos)); - pos = str.find('('); - if (pos != std::string::npos) { - // Add the class->method name (so stripping the signature). - entries.insert(str.substr(0, pos)); - } - pos = str.find(':'); - if (pos != std::string::npos) { - // Add the class->field name (so stripping the type). - entries.insert(str.substr(0, pos)); - } - } - } -} - } // namespace art diff --git a/tools/veridex/hidden_api.h b/tools/veridex/hidden_api.h index b58332bf52..d6a6438fac 100644 --- a/tools/veridex/hidden_api.h +++ b/tools/veridex/hidden_api.h @@ -20,8 +20,8 @@ #include "base/hiddenapi_flags.h" #include "dex/method_reference.h" +#include <map> #include <ostream> -#include <set> #include <string> namespace art { @@ -33,28 +33,11 @@ class DexFile; */ class HiddenApi { public: - HiddenApi(const char* whitelist, - const char* blacklist, - const char* dark_greylist, - const char* light_greylist) { - FillList(light_greylist, light_greylist_); - FillList(dark_greylist, dark_greylist_); - FillList(blacklist, blacklist_); - FillList(whitelist, whitelist_); - } + HiddenApi(const char* flags_file, bool sdk_uses_only); hiddenapi::ApiList GetApiList(const std::string& name) const { - if (IsInList(name, blacklist_)) { - return hiddenapi::ApiList::Blacklist(); - } else if (IsInList(name, dark_greylist_)) { - return hiddenapi::ApiList::GreylistMaxO(); - } else if (IsInList(name, light_greylist_)) { - return hiddenapi::ApiList::Greylist(); - } else if (IsInList(name, whitelist_)) { - return hiddenapi::ApiList::Whitelist(); - } else { - return hiddenapi::ApiList::Invalid(); - } + auto it = api_list_.find(name); + return (it == api_list_.end()) ? hiddenapi::ApiList::Invalid() : it->second; } bool IsInAnyList(const std::string& name) const { @@ -76,16 +59,9 @@ class HiddenApi { } private: - static bool IsInList(const std::string& name, const std::set<std::string>& list) { - return list.find(name) != list.end(); - } - - static void FillList(const char* filename, std::set<std::string>& entries); + void AddSignatureToApiList(const std::string& signature, hiddenapi::ApiList membership); - std::set<std::string> whitelist_; - std::set<std::string> blacklist_; - std::set<std::string> light_greylist_; - std::set<std::string> dark_greylist_; + std::map<std::string, hiddenapi::ApiList> api_list_; }; struct HiddenApiStats { diff --git a/tools/veridex/veridex.cc b/tools/veridex/veridex.cc index 2787950323..96100b20d4 100644 --- a/tools/veridex/veridex.cc +++ b/tools/veridex/veridex.cc @@ -67,10 +67,7 @@ VeriField VeriClass::sdkInt_ = nullptr; static const char* kDexFileOption = "--dex-file="; static const char* kStubsOption = "--core-stubs="; -static const char* kWhitelistOption = "--whitelist="; -static const char* kBlacklistOption = "--blacklist="; -static const char* kDarkGreylistOption = "--dark-greylist="; -static const char* kLightGreylistOption = "--light-greylist="; +static const char* kFlagsOption = "--api-flags="; static const char* kImprecise = "--imprecise"; static const char* kTargetSdkVersion = "--target-sdk-version="; static const char* kOnlyReportSdkUses = "--only-report-sdk-uses"; @@ -78,10 +75,7 @@ static const char* kOnlyReportSdkUses = "--only-report-sdk-uses"; struct VeridexOptions { const char* dex_file = nullptr; const char* core_stubs = nullptr; - const char* whitelist = nullptr; - const char* blacklist = nullptr; - const char* light_greylist = nullptr; - const char* dark_greylist = nullptr; + const char* flags_file = nullptr; bool precise = true; int target_sdk_version = 28; /* P */ bool only_report_sdk_uses = false; @@ -105,14 +99,8 @@ static void ParseArgs(VeridexOptions* options, int argc, char** argv) { options->dex_file = Substr(argv[i], strlen(kDexFileOption)); } else if (StartsWith(argv[i], kStubsOption)) { options->core_stubs = Substr(argv[i], strlen(kStubsOption)); - } else if (StartsWith(argv[i], kWhitelistOption)) { - options->whitelist = Substr(argv[i], strlen(kWhitelistOption)); - } else if (StartsWith(argv[i], kBlacklistOption)) { - options->blacklist = Substr(argv[i], strlen(kBlacklistOption)); - } else if (StartsWith(argv[i], kDarkGreylistOption)) { - options->dark_greylist = Substr(argv[i], strlen(kDarkGreylistOption)); - } else if (StartsWith(argv[i], kLightGreylistOption)) { - options->light_greylist = Substr(argv[i], strlen(kLightGreylistOption)); + } else if (StartsWith(argv[i], kFlagsOption)) { + options->flags_file = Substr(argv[i], strlen(kFlagsOption)); } else if (strcmp(argv[i], kImprecise) == 0) { options->precise = false; } else if (StartsWith(argv[i], kTargetSdkVersion)) { @@ -229,20 +217,8 @@ class Veridex { std::vector<std::unique_ptr<VeridexResolver>> app_resolvers; Resolve(app_dex_files, resolver_map, type_map, &app_resolvers); - if (options.only_report_sdk_uses) { - // If we only need to report SDK uses, clear out any of the other lists so that - // the analysis don't report them. - options.blacklist = nullptr; - options.dark_greylist = nullptr; - options.light_greylist = nullptr; - } else { - // Otherwise, omit SDK uses. - options.whitelist = nullptr; - } - // Find and log uses of hidden APIs. - HiddenApi hidden_api( - options.whitelist, options.blacklist, options.dark_greylist, options.light_greylist); + HiddenApi hidden_api(options.flags_file, options.only_report_sdk_uses); HiddenApiStats stats; HiddenApiFinder api_finder(hidden_api); @@ -277,12 +253,12 @@ class Veridex { os << stats.count << " hidden API(s) used: " << stats.linking_count << " linked against, " << stats.reflection_count << " through reflection" << std::endl; - os << kPrefix << stats.api_counts[hiddenapi::ApiList::Blacklist().GetIntValue()] - << " in blacklist" << std::endl; - os << kPrefix << stats.api_counts[hiddenapi::ApiList::GreylistMaxO().GetIntValue()] - << " in dark greylist" << std::endl; - os << kPrefix << stats.api_counts[hiddenapi::ApiList::Greylist().GetIntValue()] - << " in light greylist" << std::endl; + for (size_t i = 0; i < hiddenapi::ApiList::kValueCount; ++i) { + hiddenapi::ApiList api_list = hiddenapi::ApiList::FromIntValue(i); + if (api_list != hiddenapi::ApiList::Whitelist()) { + os << kPrefix << stats.api_counts[i] << " in " << api_list << std::endl; + } + } } } |