summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.mk2
-rw-r--r--cmdline/cmdline.h30
-rw-r--r--compiler/compiled_method.cc4
-rw-r--r--compiler/jni/quick/arm/calling_convention_arm.cc2
-rw-r--r--compiler/jni/quick/arm64/calling_convention_arm64.cc2
-rw-r--r--compiler/jni/quick/mips/calling_convention_mips.cc2
-rw-r--r--compiler/jni/quick/mips64/calling_convention_mips64.cc2
-rw-r--r--compiler/jni/quick/x86/calling_convention_x86.cc2
-rw-r--r--compiler/optimizing/code_generator.cc2
-rw-r--r--compiler/optimizing/code_generator_arm64.cc2
-rw-r--r--compiler/optimizing/code_generator_arm_vixl.cc10
-rw-r--r--compiler/optimizing/code_generator_mips.cc2
-rw-r--r--compiler/optimizing/code_generator_mips64.cc2
-rw-r--r--compiler/optimizing/code_generator_x86.cc4
-rw-r--r--compiler/optimizing/code_generator_x86_64.cc2
-rw-r--r--compiler/optimizing/induction_var_analysis.cc4
-rw-r--r--compiler/optimizing/instruction_simplifier.cc2
-rw-r--r--compiler/optimizing/nodes.cc4
-rw-r--r--dex2oat/dex2oat.cc45
-rw-r--r--dex2oat/linker/image_test.h26
-rw-r--r--dex2oat/linker/image_writer.cc14
-rw-r--r--dex2oat/linker/image_writer.h8
-rw-r--r--dex2oat/linker/oat_writer.cc2
-rw-r--r--dex2oat/linker/oat_writer_test.cc34
-rw-r--r--dexoptanalyzer/dexoptanalyzer.cc18
-rw-r--r--disassembler/disassembler.cc2
-rw-r--r--libartbase/base/file_utils.cc2
-rw-r--r--libartbase/base/hiddenapi_flags.h14
-rw-r--r--libartbase/base/zip_archive.cc5
-rw-r--r--libartbase/base/zip_archive.h3
-rw-r--r--libdexfile/dex/dex_instruction.cc2
-rw-r--r--libprofile/profile/profile_compilation_info.cc3
-rw-r--r--openjdkjvm/OpenjdkJvm.cc23
-rw-r--r--openjdkjvmti/events.cc2
-rw-r--r--runtime/art_method.cc13
-rw-r--r--runtime/common_runtime_test.cc2
-rw-r--r--runtime/common_throws.cc2
-rw-r--r--runtime/debugger.cc8
-rw-r--r--runtime/dex/dex_file_annotations.cc2
-rw-r--r--runtime/entrypoints/quick/quick_jni_entrypoints.cc2
-rw-r--r--runtime/entrypoints/quick/quick_trampoline_entrypoints.cc2
-rw-r--r--runtime/gc/allocator/rosalloc.cc33
-rw-r--r--runtime/gc/heap.cc2
-rw-r--r--runtime/gc/space/image_space.cc6
-rw-r--r--runtime/gc/space/image_space.h6
-rw-r--r--runtime/gc/space/space.cc2
-rw-r--r--runtime/hidden_api.cc6
-rw-r--r--runtime/hprof/hprof.cc2
-rw-r--r--runtime/interpreter/interpreter_common.cc2
-rw-r--r--runtime/interpreter/interpreter_common.h2
-rw-r--r--runtime/interpreter/interpreter_switch_impl-inl.h2
-rw-r--r--runtime/interpreter/mterp/mterp.cc8
-rw-r--r--runtime/jdwp/jdwp_event.cc2
-rw-r--r--runtime/jdwp/jdwp_request.cc2
-rw-r--r--runtime/jit/jit-inl.h69
-rw-r--r--runtime/jit/jit.cc54
-rw-r--r--runtime/jit/jit.h15
-rw-r--r--runtime/jni/check_jni.cc6
-rw-r--r--runtime/mirror/object.cc3
-rw-r--r--runtime/monitor.cc10
-rw-r--r--runtime/oat_file.cc2
-rw-r--r--runtime/quick_exception_handler.cc2
-rw-r--r--runtime/runtime.cc3
-rw-r--r--runtime/thread.cc3
-rw-r--r--runtime/thread_list.cc2
-rw-r--r--runtime/transaction.cc11
-rw-r--r--runtime/well_known_classes.cc4
-rw-r--r--test/674-hiddenapi/api-blacklist.txt27
-rw-r--r--test/674-hiddenapi/api-dark-greylist.txt27
-rw-r--r--test/674-hiddenapi/api-light-greylist.txt27
-rw-r--r--test/674-hiddenapi/hiddenapi-flags.csv81
-rw-r--r--test/999-redefine-hiddenapi/api-blacklist.txt2
-rw-r--r--test/999-redefine-hiddenapi/hiddenapi-flags.csv2
-rwxr-xr-xtest/999-redefine-hiddenapi/src-redefine/gen.sh2
-rwxr-xr-xtest/etc/default-build13
-rw-r--r--test/ti-agent/common_helper.cc3
-rw-r--r--tools/class2greylist/src/com/android/class2greylist/AnnotationConsumer.java18
-rw-r--r--tools/class2greylist/src/com/android/class2greylist/AnnotationHandler.java22
-rw-r--r--tools/class2greylist/src/com/android/class2greylist/AnnotationPropertyWriter.java56
-rw-r--r--tools/class2greylist/src/com/android/class2greylist/Class2Greylist.java116
-rw-r--r--tools/class2greylist/src/com/android/class2greylist/CovariantReturnTypeHandler.java21
-rw-r--r--tools/class2greylist/src/com/android/class2greylist/CovariantReturnTypeMultiHandler.java13
-rw-r--r--tools/class2greylist/src/com/android/class2greylist/CsvGreylistConsumer.java35
-rw-r--r--tools/class2greylist/src/com/android/class2greylist/CsvWriter.java49
-rw-r--r--tools/class2greylist/src/com/android/class2greylist/FileWritingGreylistConsumer.java74
-rw-r--r--tools/class2greylist/src/com/android/class2greylist/GreylistAnnotationHandler.java149
-rw-r--r--tools/class2greylist/src/com/android/class2greylist/GreylistConsumer.java23
-rw-r--r--tools/class2greylist/src/com/android/class2greylist/HiddenapiFlagsWriter.java40
-rw-r--r--tools/class2greylist/src/com/android/class2greylist/SystemOutGreylistConsumer.java21
-rw-r--r--tools/class2greylist/src/com/android/class2greylist/UnsupportedAppUsageAnnotationHandler.java134
-rw-r--r--tools/class2greylist/test/src/com/android/class2greylist/AnnotationHandlerTestBase.java4
-rw-r--r--tools/class2greylist/test/src/com/android/class2greylist/Class2GreylistTest.java109
-rw-r--r--tools/class2greylist/test/src/com/android/class2greylist/CovariantReturnTypeHandlerTest.java16
-rw-r--r--tools/class2greylist/test/src/com/android/class2greylist/CovariantReturnTypeMultiHandlerTest.java10
-rw-r--r--tools/class2greylist/test/src/com/android/class2greylist/FileWritingGreylistConsumerTest.java94
-rw-r--r--tools/class2greylist/test/src/com/android/class2greylist/UnsupportedAppUsageAnnotationHandlerTest.java (renamed from tools/class2greylist/test/src/com/android/class2greylist/GreylistAnnotationHandlerTest.java)98
-rw-r--r--tools/hiddenapi/hiddenapi.cc74
-rw-r--r--tools/hiddenapi/hiddenapi_test.cc453
-rw-r--r--tools/timeout_dumper/timeout_dumper.cc2
-rw-r--r--tools/titrace/instruction_decoder.cc7
-rw-r--r--tools/veridex/Android.mk23
-rwxr-xr-xtools/veridex/appcompat.sh15
-rw-r--r--tools/veridex/hidden_api.cc79
-rw-r--r--tools/veridex/hidden_api.h36
-rw-r--r--tools/veridex/veridex.cc46
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;
+ }
+ }
}
}