diff options
| -rw-r--r-- | Android.mk | 2 | ||||
| -rw-r--r-- | compiler/optimizing/control_flow_simplifier.cc | 3 | ||||
| -rw-r--r-- | compiler/optimizing/optimizing_compiler_stats.h | 8 | ||||
| -rw-r--r-- | runtime/hidden_api.cc | 40 | ||||
| -rw-r--r-- | runtime/hidden_api.h | 14 | ||||
| -rw-r--r-- | runtime/verifier/method_verifier.cc | 311 | ||||
| -rw-r--r-- | tools/ahat/Android.bp | 38 | ||||
| -rw-r--r-- | tools/ahat/Android.mk | 62 | ||||
| -rw-r--r-- | tools/ahat/ahat-tests.xml | 23 | ||||
| -rw-r--r-- | tools/ahat/etc/Android.bp | 30 |
10 files changed, 321 insertions, 210 deletions
diff --git a/Android.mk b/Android.mk index f83c13cdf9..1405aa79ff 100644 --- a/Android.mk +++ b/Android.mk @@ -28,8 +28,6 @@ include $(art_path)/build/Android.cpplint.mk ######################################################################## # product rules -include $(art_path)/tools/ahat/Android.mk - ART_HOST_DEPENDENCIES := \ $(ART_HOST_EXECUTABLES) \ $(ART_HOST_DEX_DEPENDENCIES) \ diff --git a/compiler/optimizing/control_flow_simplifier.cc b/compiler/optimizing/control_flow_simplifier.cc index 3e1c0ac0fc..35efed59da 100644 --- a/compiler/optimizing/control_flow_simplifier.cc +++ b/compiler/optimizing/control_flow_simplifier.cc @@ -198,7 +198,8 @@ bool HControlFlowSimplifier::TryGenerateSelectSimpleDiamondPattern( block->MergeWith(merge_block); } - MaybeRecordStat(stats_, MethodCompilationStat::kSelectGenerated); + MaybeRecordStat(stats_, select != nullptr ? MethodCompilationStat::kControlFlowSelectGenerated + : MethodCompilationStat::kControlFlowDiamondRemoved); // Very simple way of finding common subexpressions in the generated HSelect statements // (since this runs after GVN). Lookup by condition, and reuse latest one if possible diff --git a/compiler/optimizing/optimizing_compiler_stats.h b/compiler/optimizing/optimizing_compiler_stats.h index 22c43fc7ad..e6c7cefb16 100644 --- a/compiler/optimizing/optimizing_compiler_stats.h +++ b/compiler/optimizing/optimizing_compiler_stats.h @@ -58,7 +58,6 @@ enum class MethodCompilationStat { kNotCompiledThrowCatchLoop, kNotCompiledAmbiguousArrayOp, kNotCompiledHugeMethod, - kNotCompiledLargeMethodNoBranches, kNotCompiledMalformedOpcode, kNotCompiledNoCodegen, kNotCompiledPathological, @@ -79,13 +78,14 @@ enum class MethodCompilationStat { kLoopInvariantMoved, kLoopVectorized, kLoopVectorizedIdiom, - kSelectGenerated, kRemovedInstanceOf, kPropagatedIfValue, kInlinedInvokeVirtualOrInterface, kInlinedLastInvokeVirtualOrInterface, kImplicitNullCheckGenerated, kExplicitNullCheckGenerated, + kControlFlowSelectGenerated, + kControlFlowDiamondRemoved, kSimplifyIf, kSimplifyIfAddedPhi, kSimplifyThrowingInvoke, @@ -131,10 +131,6 @@ enum class MethodCompilationStat { kJitOutOfMemoryForCommit, kFullLSEAllocationRemoved, kFullLSEPossible, - kNonPartialLoadRemoved, - kPartialLSEPossible, - kPartialStoreRemoved, - kPartialAllocationMoved, kDevirtualized, kLastStat }; diff --git a/runtime/hidden_api.cc b/runtime/hidden_api.cc index 6e4a12d3cc..c7fb3ef7ff 100644 --- a/runtime/hidden_api.cc +++ b/runtime/hidden_api.cc @@ -46,7 +46,7 @@ static constexpr uint64_t kHideMaxtargetsdkPHiddenApis = 149997251; static constexpr uint64_t kHideMaxtargetsdkQHiddenApis = 149994052; static constexpr uint64_t kAllowTestApiAccess = 166236554; -static constexpr uint64_t kMaxLogWarnings = 100; +static constexpr uint64_t kMaxLogAccessesToLogcat = 100; // Should be the same as dalvik.system.VMRuntime.PREVENT_META_REFLECTION_BLOCKLIST_ACCESS. // Corresponds to a bug id. @@ -353,15 +353,15 @@ void MemberSignature::Dump(std::ostream& os) const { } } -void MemberSignature::WarnAboutAccess(AccessMethod access_method, - hiddenapi::ApiList list, - bool access_denied, - uint32_t runtime_flags, - const AccessContext& caller_context, - const AccessContext& callee_context, - EnforcementPolicy policy) { - static std::atomic<uint64_t> log_warning_count_ = 0; - if (log_warning_count_ > kMaxLogWarnings) { +void MemberSignature::LogAccessToLogcat(AccessMethod access_method, + hiddenapi::ApiList list, + bool access_denied, + uint32_t runtime_flags, + const AccessContext& caller_context, + const AccessContext& callee_context, + EnforcementPolicy policy) { + static std::atomic<uint64_t> logged_access_count_ = 0; + if (logged_access_count_ > kMaxLogAccessesToLogcat) { return; } LOG(access_denied ? (policy == EnforcementPolicy::kEnabled ? ERROR : WARNING) : INFO) @@ -376,10 +376,10 @@ void MemberSignature::WarnAboutAccess(AccessMethod access_method, LOG(WARNING) << "hiddenapi: If this is a platform test consider enabling " << "VMRuntime.ALLOW_TEST_API_ACCESS change id for this package."; } - if (log_warning_count_ >= kMaxLogWarnings) { - LOG(WARNING) << "hiddenapi: Reached maximum number of hidden api access warnings."; + if (logged_access_count_ >= kMaxLogAccessesToLogcat) { + LOG(WARNING) << "hiddenapi: Reached maximum number of hidden api access messages."; } - ++log_warning_count_; + ++logged_access_count_; } bool MemberSignature::Equals(const MemberSignature& other) { @@ -678,13 +678,13 @@ bool ShouldDenyAccessToMemberImpl(T* member, // Print a log message with information about this class member access. // We do this if we're about to deny access, or the app is debuggable. if (kLogAllAccesses || deny_access || runtime->IsJavaDebuggable()) { - member_signature.WarnAboutAccess(access_method, - api_list, - deny_access, - runtime_flags, - caller_context, - callee_context, - hiddenApiPolicy); + member_signature.LogAccessToLogcat(access_method, + api_list, + deny_access, + runtime_flags, + caller_context, + callee_context, + hiddenApiPolicy); } // If there is a StrictMode listener, notify it about this violation. diff --git a/runtime/hidden_api.h b/runtime/hidden_api.h index 2480e21e50..d2a6cdcbd3 100644 --- a/runtime/hidden_api.h +++ b/runtime/hidden_api.h @@ -215,13 +215,13 @@ class MemberSignature { bool DoesPrefixMatchAny(const std::vector<std::string>& exemptions); - void WarnAboutAccess(AccessMethod access_method, - ApiList list, - bool access_denied, - uint32_t runtime_flags, - const AccessContext& caller_context, - const AccessContext& callee_context, - EnforcementPolicy policy) REQUIRES_SHARED(Locks::mutator_lock_); + void LogAccessToLogcat(AccessMethod access_method, + ApiList list, + bool access_denied, + uint32_t runtime_flags, + const AccessContext& caller_context, + const AccessContext& callee_context, + EnforcementPolicy policy) REQUIRES_SHARED(Locks::mutator_lock_); void LogAccessToEventLog(uint32_t sampled_value, AccessMethod access_method, bool access_denied); diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index 06b95428cc..05fb9b39b6 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -957,18 +957,21 @@ class MethodVerifierImpl : public ::art::verifier::MethodVerifier { * "dst_type" is stored into vA, and "src_type" is verified against vB. */ ALWAYS_INLINE - void CheckUnaryOp(const Instruction* inst, + bool CheckUnaryOp(const Instruction* inst, uint16_t inst_data, RegType::Kind dst_kind, RegType::Kind src_kind) REQUIRES_SHARED(Locks::mutator_lock_) { if (VerifyRegisterType(inst->VRegB_12x(inst_data), src_kind)) { work_line_->SetRegisterType(inst->VRegA_12x(inst_data), dst_kind); + return true; + } else { + return false; } } ALWAYS_INLINE - void CheckUnaryOpWide(const Instruction* inst, + bool CheckUnaryOpWide(const Instruction* inst, uint16_t inst_data, RegType::Kind dst_kind, RegType::Kind src_kind) @@ -976,11 +979,14 @@ class MethodVerifierImpl : public ::art::verifier::MethodVerifier { if (VerifyRegisterTypeWide(inst->VRegB_12x(inst_data), src_kind)) { work_line_->SetRegisterTypeWide( inst->VRegA_12x(inst_data), dst_kind, RegType::ToHighHalf(dst_kind)); + return true; + } else { + return false; } } ALWAYS_INLINE - void CheckUnaryOpToWide(const Instruction* inst, + bool CheckUnaryOpToWide(const Instruction* inst, uint16_t inst_data, RegType::Kind dst_kind, RegType::Kind src_kind) @@ -988,17 +994,23 @@ class MethodVerifierImpl : public ::art::verifier::MethodVerifier { if (VerifyRegisterType(inst->VRegB_12x(inst_data), src_kind)) { work_line_->SetRegisterTypeWide( inst->VRegA_12x(inst_data), dst_kind, RegType::ToHighHalf(dst_kind)); + return true; + } else { + return false; } } ALWAYS_INLINE - void CheckUnaryOpFromWide(const Instruction* inst, + bool CheckUnaryOpFromWide(const Instruction* inst, uint16_t inst_data, RegType::Kind dst_kind, RegType::Kind src_kind) REQUIRES_SHARED(Locks::mutator_lock_) { if (VerifyRegisterTypeWide(inst->VRegB_12x(inst_data), src_kind)) { work_line_->SetRegisterType(inst->VRegA_12x(inst_data), dst_kind); + return true; + } else { + return false; } } @@ -1008,7 +1020,7 @@ class MethodVerifierImpl : public ::art::verifier::MethodVerifier { * against vB/vC. */ ALWAYS_INLINE - void CheckBinaryOp(const Instruction* inst, + bool CheckBinaryOp(const Instruction* inst, uint16_t inst_data, RegType::Kind dst_kind, RegType::Kind src_kind1, @@ -1026,16 +1038,18 @@ class MethodVerifierImpl : public ::art::verifier::MethodVerifier { RegTypeCache::RegKindForId(work_line_->GetRegisterTypeId(vregB))) && RegType::IsBooleanTypes( RegTypeCache::RegKindForId(work_line_->GetRegisterTypeId(vregC)))) { - work_line_->SetRegisterType(vregA, RegType::Kind::kBoolean); - return; + dst_kind = RegType::Kind::kBoolean; } } work_line_->SetRegisterType(vregA, dst_kind); + return true; + } else { + return false; } } ALWAYS_INLINE - void CheckBinaryOpWide(const Instruction* inst, + bool CheckBinaryOpWide(const Instruction* inst, uint16_t inst_data, RegType::Kind dst_kind, RegType::Kind src_kind1, @@ -1045,11 +1059,14 @@ class MethodVerifierImpl : public ::art::verifier::MethodVerifier { VerifyRegisterTypeWide(inst->VRegC_23x(), src_kind2)) { work_line_->SetRegisterTypeWide( inst->VRegA_23x(inst_data), dst_kind, RegType::ToHighHalf(dst_kind)); + return true; + } else { + return false; } } ALWAYS_INLINE - void CheckBinaryOpWideCmp(const Instruction* inst, + bool CheckBinaryOpWideCmp(const Instruction* inst, uint16_t inst_data, RegType::Kind dst_kind, RegType::Kind src_kind1, @@ -1058,11 +1075,14 @@ class MethodVerifierImpl : public ::art::verifier::MethodVerifier { if (VerifyRegisterTypeWide(inst->VRegB_23x(), src_kind1) && VerifyRegisterTypeWide(inst->VRegC_23x(), src_kind2)) { work_line_->SetRegisterType(inst->VRegA_23x(inst_data), dst_kind); + return true; + } else { + return false; } } ALWAYS_INLINE - void CheckBinaryOpWideShift(const Instruction* inst, + bool CheckBinaryOpWideShift(const Instruction* inst, uint16_t inst_data, RegType::Kind long_lo_kind, RegType::Kind int_kind) @@ -1071,6 +1091,9 @@ class MethodVerifierImpl : public ::art::verifier::MethodVerifier { VerifyRegisterType(inst->VRegC_23x(), int_kind)) { RegType::Kind long_hi_kind = RegType::ToHighHalf(long_lo_kind); work_line_->SetRegisterTypeWide(inst->VRegA_23x(inst_data), long_lo_kind, long_hi_kind); + return true; + } else { + return false; } } @@ -1079,7 +1102,7 @@ class MethodVerifierImpl : public ::art::verifier::MethodVerifier { * are verified against vA/vB, then "dst_type" is stored into vA. */ ALWAYS_INLINE - void CheckBinaryOp2addr(const Instruction* inst, + bool CheckBinaryOp2addr(const Instruction* inst, uint16_t inst_data, RegType::Kind dst_kind, RegType::Kind src_kind1, @@ -1096,16 +1119,18 @@ class MethodVerifierImpl : public ::art::verifier::MethodVerifier { RegTypeCache::RegKindForId(work_line_->GetRegisterTypeId(vregA))) && RegType::IsBooleanTypes( RegTypeCache::RegKindForId(work_line_->GetRegisterTypeId(vregB)))) { - work_line_->SetRegisterType(vregA, RegType::Kind::kBoolean); - return; + dst_kind = RegType::Kind::kBoolean; } } work_line_->SetRegisterType(vregA, dst_kind); + return true; + } else { + return false; } } ALWAYS_INLINE - void CheckBinaryOp2addrWide(const Instruction* inst, + bool CheckBinaryOp2addrWide(const Instruction* inst, uint16_t inst_data, RegType::Kind dst_kind, RegType::Kind src_kind1, @@ -1116,11 +1141,14 @@ class MethodVerifierImpl : public ::art::verifier::MethodVerifier { if (VerifyRegisterTypeWide(vregA, src_kind1) && VerifyRegisterTypeWide(vregB, src_kind2)) { work_line_->SetRegisterTypeWide(vregA, dst_kind, RegType::ToHighHalf(dst_kind)); + return true; + } else { + return false; } } ALWAYS_INLINE - void CheckBinaryOp2addrWideShift(const Instruction* inst, + bool CheckBinaryOp2addrWideShift(const Instruction* inst, uint16_t inst_data, RegType::Kind long_lo_kind, RegType::Kind int_kind) @@ -1131,6 +1159,9 @@ class MethodVerifierImpl : public ::art::verifier::MethodVerifier { VerifyRegisterType(vregB, int_kind)) { RegType::Kind long_hi_kind = RegType::ToHighHalf(long_lo_kind); work_line_->SetRegisterTypeWide(vregA, long_lo_kind, long_hi_kind); + return true; + } else { + return false; } } @@ -1140,27 +1171,29 @@ class MethodVerifierImpl : public ::art::verifier::MethodVerifier { * * If "check_boolean_op" is set, we use the constant value in vC. */ + template <bool kIsLit16> ALWAYS_INLINE - void CheckLiteralOp(const Instruction* inst, + bool CheckLiteralOp(const Instruction* inst, uint16_t inst_data, RegType::Kind dst_kind, RegType::Kind src_kind, - bool check_boolean_op, - bool is_lit16) + bool check_boolean_op) REQUIRES_SHARED(Locks::mutator_lock_) { - const uint32_t vregA = is_lit16 ? inst->VRegA_22s(inst_data) : inst->VRegA_22b(inst_data); - const uint32_t vregB = is_lit16 ? inst->VRegB_22s(inst_data) : inst->VRegB_22b(); + const uint32_t vregA = kIsLit16 ? inst->VRegA_22s(inst_data) : inst->VRegA_22b(inst_data); + const uint32_t vregB = kIsLit16 ? inst->VRegB_22s(inst_data) : inst->VRegB_22b(); if (VerifyRegisterType(vregB, src_kind)) { if (check_boolean_op) { DCHECK_EQ(dst_kind, RegType::Kind::kInteger); /* check vB with the call, then check the constant manually */ - const uint32_t val = is_lit16 ? inst->VRegC_22s() : inst->VRegC_22b(); + const uint32_t val = kIsLit16 ? inst->VRegC_22s() : inst->VRegC_22b(); if (work_line_->GetRegisterType(this, vregB).IsBooleanTypes() && (val == 0 || val == 1)) { - work_line_->SetRegisterType(vregA, RegType::Kind::kBoolean); - return; + dst_kind = RegType::Kind::kBoolean; } } work_line_->SetRegisterType(vregA, dst_kind); + return true; + } else { + return false; } } @@ -2626,6 +2659,7 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g */ if (inst->VRegA_10x(inst_data) != 0) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "encountered data table in instruction stream"; + return false; } break; @@ -2699,6 +2733,7 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g if (!IsInstanceConstructor() || work_line_->CheckConstructorReturn(this)) { if (!GetMethodReturnType().IsConflict()) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "return-void not expected"; + return false; } } break; @@ -2709,6 +2744,7 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g if (!return_type.IsCategory1Types()) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unexpected non-category 1 return type " << return_type; + return false; } else { // Compilers may generate synthetic functions that write byte values into boolean fields. // Also, it may use integer values for boolean, byte, short, and character return types. @@ -2732,6 +2768,7 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g const RegType& return_type = GetMethodReturnType(); if (!return_type.IsCategory2Types()) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "return-wide not expected"; + return false; } else { /* check the register contents */ const uint32_t vregA = inst->VRegA_11x(inst_data); @@ -2747,6 +2784,7 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g const RegType& return_type = GetMethodReturnType(); if (!return_type.IsReferenceTypes()) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "return-object not expected"; + return false; } else { /* return_type is the *expected* return type, not register value */ DCHECK(!return_type.IsZeroOrNull()); @@ -2757,15 +2795,19 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g // reference in vAA is an instance of the "return_type." if (reg_type.IsUndefined()) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "returning undefined register"; + return false; } else if (reg_type.IsConflict()) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "returning register with conflict"; + return false; } else if (reg_type.IsUninitializedTypes()) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "returning uninitialized object '" << reg_type << "'"; + return false; } else if (!reg_type.IsReferenceTypes()) { // We really do expect a reference here. Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "return-object returns a non-reference type " << reg_type; + return false; } else if (!IsAssignableFrom(return_type, reg_type)) { if (reg_type.IsUnresolvedTypes() || return_type.IsUnresolvedTypes()) { Fail(VERIFY_ERROR_UNRESOLVED_TYPE_CHECK) @@ -2773,6 +2815,7 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g } else { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "returning '" << reg_type << "', but expected from declaration '" << return_type << "'"; + return false; } } } @@ -2951,7 +2994,7 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "using primitive type " << dex_file_->GetTypeDescriptorView(type_idx) << " in instanceof in " << GetDeclaringClass(); - break; + return false; } DCHECK_NE(failures_.size(), 0U); @@ -2966,11 +3009,14 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g const RegType& orig_type = work_line_->GetRegisterType(this, orig_type_reg); if (!res_type.IsNonZeroReferenceTypes()) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << opcode << " on unexpected class " << res_type; + return false; } else if (!orig_type.IsReferenceTypes()) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << opcode << " on non-reference in v" << orig_type_reg; + return false; } else if (orig_type.IsUninitializedTypes()) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << opcode << " on uninitialized reference in v" << orig_type_reg; + return false; } else { if (is_checkcast) { work_line_->SetRegisterType<LockOp::kKeep>(inst->VRegA_21c(inst_data), res_type); @@ -2986,11 +3032,13 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g if (!res_type.IsArrayTypes() && !res_type.IsZeroOrNull()) { // ie not an array or null Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "array-length on non-array " << res_type; + return false; } else { work_line_->SetRegisterType(inst->VRegA_12x(inst_data), kInteger); } } else { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "array-length on non-array " << res_type; + return false; } break; } @@ -3029,26 +3077,37 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g break; case Instruction::CMPL_FLOAT: case Instruction::CMPG_FLOAT: - CheckBinaryOp(inst, inst_data, kInteger, kFloat, kFloat, /*check_boolean_op=*/ false); + if (!CheckBinaryOp(inst, inst_data, kInteger, kFloat, kFloat, /*check_boolean_op=*/ false)) { + return false; + } break; case Instruction::CMPL_DOUBLE: case Instruction::CMPG_DOUBLE: - CheckBinaryOpWideCmp(inst, inst_data, kInteger, kDoubleLo, kDoubleLo); + if (!CheckBinaryOpWideCmp(inst, inst_data, kInteger, kDoubleLo, kDoubleLo)) { + return false; + } break; case Instruction::CMP_LONG: - CheckBinaryOpWideCmp(inst, inst_data, kInteger, kLongLo, kLongLo); + if (!CheckBinaryOpWideCmp(inst, inst_data, kInteger, kLongLo, kLongLo)) { + return false; + } break; case Instruction::THROW: { const RegType& res_type = work_line_->GetRegisterType(this, inst->VRegA_11x(inst_data)); if (!IsAssignableFrom(reg_types_.JavaLangThrowable(), res_type)) { if (res_type.IsUninitializedTypes()) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "thrown exception not initialized"; + return false; } else if (!res_type.IsReferenceTypes()) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "thrown value of non-reference type " << res_type; + return false; } else { - Fail(res_type.IsUnresolvedTypes() - ? VERIFY_ERROR_UNRESOLVED_TYPE_CHECK : VERIFY_ERROR_BAD_CLASS_HARD) + bool unresolved = res_type.IsUnresolvedTypes(); + Fail(unresolved ? VERIFY_ERROR_UNRESOLVED_TYPE_CHECK : VERIFY_ERROR_BAD_CLASS_HARD) << "thrown class " << res_type << " not instanceof Throwable"; + if (!unresolved) { + return false; + } } } break; @@ -3073,16 +3132,19 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g if (!array_type.IsArrayTypes()) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid fill-array-data with array type " << array_type; + return false; } else if (array_type.IsUnresolvedTypes()) { // If it's an unresolved array type, it must be non-primitive. Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid fill-array-data for array of type " << array_type; + return false; } else { const RegType& component_type = reg_types_.GetComponentType(array_type); DCHECK(!component_type.IsConflict()); if (component_type.IsNonZeroReferenceTypes()) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid fill-array-data with component type " << component_type; + return false; } else { // Now verify if the element width in the table matches the element width declared in // the array. The signature has been verified by `CheckArrayData()`. @@ -3095,6 +3157,7 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g if (array_data[1] != elem_width) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "array-data size mismatch (" << array_data[1] << " vs " << elem_width << ")"; + return false; } } } @@ -3116,6 +3179,7 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g if (mismatch) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "args to if-eq/if-ne (" << reg_type1 << "," << reg_type2 << ") must both be references or integral"; + return false; } break; } @@ -3128,6 +3192,7 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g if (!reg_type1.IsIntegralTypes() || !reg_type2.IsIntegralTypes()) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "args to 'if' (" << reg_type1 << "," << reg_type2 << ") must be integral"; + return false; } break; } @@ -3137,6 +3202,7 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g if (!reg_type.IsReferenceTypes() && !reg_type.IsIntegralTypes()) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "type " << reg_type << " unexpected as arg to if-eqz/if-nez"; + return false; } // Find previous instruction - its existence is a precondition to peephole optimization. @@ -3247,6 +3313,7 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g if (!reg_type.IsIntegralTypes()) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "type " << reg_type << " unexpected as arg to if-ltz/if-gez/if-gtz/if-lez"; + return false; } break; } @@ -3429,20 +3496,21 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g * this method (which implies that we're in a constructor ourselves). */ const RegType& this_type = GetInvocationThis(inst); - if (this_type.IsConflict()) // failure. - break; + if (this_type.IsConflict()) { // failure. + return false; + } /* no null refs allowed (?) */ if (this_type.IsZeroOrNull()) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unable to initialize null ref"; - break; + return false; } /* arg must be an uninitialized reference */ if (!this_type.IsUninitializedTypes()) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Expected initialization on uninitialized reference " << this_type; - break; + return false; } // Note: According to JLS, constructors are never inherited. Therefore the target @@ -3511,7 +3579,7 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g if (this_type.IsUninitializedTypes()) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interface call on uninitialized object " << this_type; - break; + return false; } // In the past we have tried to assert that "called_interface" is assignable // from "this_type.GetClass()", however, as we do an imprecise Join @@ -3546,13 +3614,12 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g ArtMethod* called_method = VerifyInvocationArgs(inst, METHOD_POLYMORPHIC, is_range); if (called_method == nullptr) { // Convert potential soft failures in VerifyInvocationArgs() to hard errors. - if (failures_.size() > 0) { - std::string_view message = failures_.back().message.view(); - Fail(VERIFY_ERROR_BAD_CLASS_HARD) << message; - } else { - Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invoke-polymorphic verification failure."; - } - break; + std::string_view message = failures_.empty() ? "invoke-polymorphic verification failure." + : failures_.back().message.view(); + // Note: Adding another failure to `failures_` does not invalidate the view of + // the previous message (if any) - the list node holding it is not even moved. + Fail(VERIFY_ERROR_BAD_CLASS_HARD) << message; + return false; } if (!CheckSignaturePolymorphicMethod(called_method) || !CheckSignaturePolymorphicReceiver(inst)) { @@ -3603,62 +3670,100 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g } case Instruction::NEG_INT: case Instruction::NOT_INT: - CheckUnaryOp(inst, inst_data, kInteger, kInteger); + if (!CheckUnaryOp(inst, inst_data, kInteger, kInteger)) { + return false; + } break; case Instruction::NEG_LONG: case Instruction::NOT_LONG: - CheckUnaryOpWide(inst, inst_data, kLongLo, kLongLo); + if (!CheckUnaryOpWide(inst, inst_data, kLongLo, kLongLo)) { + return false; + } break; case Instruction::NEG_FLOAT: - CheckUnaryOp(inst, inst_data, kFloat, kFloat); + if (!CheckUnaryOp(inst, inst_data, kFloat, kFloat)) { + return false; + } break; case Instruction::NEG_DOUBLE: - CheckUnaryOpWide(inst, inst_data, kDoubleLo, kDoubleLo); + if (!CheckUnaryOpWide(inst, inst_data, kDoubleLo, kDoubleLo)) { + return false; + } break; case Instruction::INT_TO_LONG: - CheckUnaryOpToWide(inst, inst_data, kLongLo, kInteger); + if (!CheckUnaryOpToWide(inst, inst_data, kLongLo, kInteger)) { + return false; + } break; case Instruction::INT_TO_FLOAT: - CheckUnaryOp(inst, inst_data, kFloat, kInteger); + if (!CheckUnaryOp(inst, inst_data, kFloat, kInteger)) { + return false; + } break; case Instruction::INT_TO_DOUBLE: - CheckUnaryOpToWide(inst, inst_data, kDoubleLo, kInteger); + if (!CheckUnaryOpToWide(inst, inst_data, kDoubleLo, kInteger)) { + return false; + } break; case Instruction::LONG_TO_INT: - CheckUnaryOpFromWide(inst, inst_data, kInteger, kLongLo); + if (!CheckUnaryOpFromWide(inst, inst_data, kInteger, kLongLo)) { + return false; + } break; case Instruction::LONG_TO_FLOAT: - CheckUnaryOpFromWide(inst, inst_data, kFloat, kLongLo); + if (!CheckUnaryOpFromWide(inst, inst_data, kFloat, kLongLo)) { + return false; + } break; case Instruction::LONG_TO_DOUBLE: - CheckUnaryOpWide(inst, inst_data, kDoubleLo, kLongLo); + if (!CheckUnaryOpWide(inst, inst_data, kDoubleLo, kLongLo)) { + return false; + } break; case Instruction::FLOAT_TO_INT: - CheckUnaryOp(inst, inst_data, kInteger, kFloat); + if (!CheckUnaryOp(inst, inst_data, kInteger, kFloat)) { + return false; + } break; case Instruction::FLOAT_TO_LONG: - CheckUnaryOpToWide(inst, inst_data, kLongLo, kFloat); + if (!CheckUnaryOpToWide(inst, inst_data, kLongLo, kFloat)) { + return false; + } break; case Instruction::FLOAT_TO_DOUBLE: - CheckUnaryOpToWide(inst, inst_data, kDoubleLo, kFloat); + if (!CheckUnaryOpToWide(inst, inst_data, kDoubleLo, kFloat)) { + return false; + } break; case Instruction::DOUBLE_TO_INT: - CheckUnaryOpFromWide(inst, inst_data, kInteger, kDoubleLo); + if (!CheckUnaryOpFromWide(inst, inst_data, kInteger, kDoubleLo)) { + return false; + } break; case Instruction::DOUBLE_TO_LONG: - CheckUnaryOpWide(inst, inst_data, kLongLo, kDoubleLo); + if (!CheckUnaryOpWide(inst, inst_data, kLongLo, kDoubleLo)) { + return false; + } break; case Instruction::DOUBLE_TO_FLOAT: - CheckUnaryOpFromWide(inst, inst_data, kFloat, kDoubleLo); + if (!CheckUnaryOpFromWide(inst, inst_data, kFloat, kDoubleLo)) { + return false; + } break; case Instruction::INT_TO_BYTE: - CheckUnaryOp(inst, inst_data, kByte, kInteger); + if (!CheckUnaryOp(inst, inst_data, kByte, kInteger)) { + return false; + } break; case Instruction::INT_TO_CHAR: - CheckUnaryOp(inst, inst_data, kChar, kInteger); + if (!CheckUnaryOp(inst, inst_data, kChar, kInteger)) { + return false; + } break; case Instruction::INT_TO_SHORT: - CheckUnaryOp(inst, inst_data, kShort, kInteger); + if (!CheckUnaryOp(inst, inst_data, kShort, kInteger)) { + return false; + } break; case Instruction::ADD_INT: @@ -3669,12 +3774,18 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g case Instruction::SHL_INT: case Instruction::SHR_INT: case Instruction::USHR_INT: - CheckBinaryOp(inst, inst_data, kInteger, kInteger, kInteger, /*check_boolean_op=*/ false); + if (!CheckBinaryOp( + inst, inst_data, kInteger, kInteger, kInteger, /*check_boolean_op=*/ false)) { + return false; + } break; case Instruction::AND_INT: case Instruction::OR_INT: case Instruction::XOR_INT: - CheckBinaryOp(inst, inst_data, kInteger, kInteger, kInteger, /*check_boolean_op=*/ true); + if (!CheckBinaryOp( + inst, inst_data, kInteger, kInteger, kInteger, /*check_boolean_op=*/ true)) { + return false; + } break; case Instruction::ADD_LONG: case Instruction::SUB_LONG: @@ -3684,27 +3795,35 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g case Instruction::AND_LONG: case Instruction::OR_LONG: case Instruction::XOR_LONG: - CheckBinaryOpWide(inst, inst_data, kLongLo, kLongLo, kLongLo); + if (!CheckBinaryOpWide(inst, inst_data, kLongLo, kLongLo, kLongLo)) { + return false; + } break; case Instruction::SHL_LONG: case Instruction::SHR_LONG: case Instruction::USHR_LONG: /* shift distance is Int, making these different from other binary operations */ - CheckBinaryOpWideShift(inst, inst_data, kLongLo, kInteger); + if (!CheckBinaryOpWideShift(inst, inst_data, kLongLo, kInteger)) { + return false; + } break; case Instruction::ADD_FLOAT: case Instruction::SUB_FLOAT: case Instruction::MUL_FLOAT: case Instruction::DIV_FLOAT: case Instruction::REM_FLOAT: - CheckBinaryOp(inst, inst_data, kFloat, kFloat, kFloat, /*check_boolean_op=*/ false); + if (!CheckBinaryOp(inst, inst_data, kFloat, kFloat, kFloat, /*check_boolean_op=*/ false)) { + return false; + } break; case Instruction::ADD_DOUBLE: case Instruction::SUB_DOUBLE: case Instruction::MUL_DOUBLE: case Instruction::DIV_DOUBLE: case Instruction::REM_DOUBLE: - CheckBinaryOpWide(inst, inst_data, kDoubleLo, kDoubleLo, kDoubleLo); + if (!CheckBinaryOpWide(inst, inst_data, kDoubleLo, kDoubleLo, kDoubleLo)) { + return false; + } break; case Instruction::ADD_INT_2ADDR: case Instruction::SUB_INT_2ADDR: @@ -3713,17 +3832,24 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g case Instruction::SHL_INT_2ADDR: case Instruction::SHR_INT_2ADDR: case Instruction::USHR_INT_2ADDR: - CheckBinaryOp2addr( - inst, inst_data, kInteger, kInteger, kInteger, /*check_boolean_op=*/ false); + if (!CheckBinaryOp2addr( + inst, inst_data, kInteger, kInteger, kInteger, /*check_boolean_op=*/ false)) { + return false; + } break; case Instruction::AND_INT_2ADDR: case Instruction::OR_INT_2ADDR: case Instruction::XOR_INT_2ADDR: - CheckBinaryOp2addr(inst, inst_data, kInteger, kInteger, kInteger, /*check_boolean_op=*/ true); + if (!CheckBinaryOp2addr( + inst, inst_data, kInteger, kInteger, kInteger, /*check_boolean_op=*/ true)) { + return false; + } break; case Instruction::DIV_INT_2ADDR: - CheckBinaryOp2addr( - inst, inst_data, kInteger, kInteger, kInteger, /*check_boolean_op=*/ false); + if (!CheckBinaryOp2addr( + inst, inst_data, kInteger, kInteger, kInteger, /*check_boolean_op=*/ false)) { + return false; + } break; case Instruction::ADD_LONG_2ADDR: case Instruction::SUB_LONG_2ADDR: @@ -3733,40 +3859,53 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g case Instruction::AND_LONG_2ADDR: case Instruction::OR_LONG_2ADDR: case Instruction::XOR_LONG_2ADDR: - CheckBinaryOp2addrWide(inst, inst_data, kLongLo, kLongLo, kLongLo); + if (!CheckBinaryOp2addrWide(inst, inst_data, kLongLo, kLongLo, kLongLo)) { + return false; + } break; case Instruction::SHL_LONG_2ADDR: case Instruction::SHR_LONG_2ADDR: case Instruction::USHR_LONG_2ADDR: - CheckBinaryOp2addrWideShift(inst, inst_data, kLongLo, kInteger); + if (!CheckBinaryOp2addrWideShift(inst, inst_data, kLongLo, kInteger)) { + return false; + } break; case Instruction::ADD_FLOAT_2ADDR: case Instruction::SUB_FLOAT_2ADDR: case Instruction::MUL_FLOAT_2ADDR: case Instruction::DIV_FLOAT_2ADDR: case Instruction::REM_FLOAT_2ADDR: - CheckBinaryOp2addr(inst, inst_data, kFloat, kFloat, kFloat, /*check_boolean_op=*/ false); + if (!CheckBinaryOp2addr( + inst, inst_data, kFloat, kFloat, kFloat, /*check_boolean_op=*/ false)) { + return false; + } break; case Instruction::ADD_DOUBLE_2ADDR: case Instruction::SUB_DOUBLE_2ADDR: case Instruction::MUL_DOUBLE_2ADDR: case Instruction::DIV_DOUBLE_2ADDR: case Instruction::REM_DOUBLE_2ADDR: - CheckBinaryOp2addrWide(inst, inst_data, kDoubleLo, kDoubleLo, kDoubleLo); + if (!CheckBinaryOp2addrWide(inst, inst_data, kDoubleLo, kDoubleLo, kDoubleLo)) { + return false; + } break; case Instruction::ADD_INT_LIT16: case Instruction::RSUB_INT_LIT16: case Instruction::MUL_INT_LIT16: case Instruction::DIV_INT_LIT16: case Instruction::REM_INT_LIT16: - CheckLiteralOp( - inst, inst_data, kInteger, kInteger, /*check_boolean_op=*/ false, /*is_lit16=*/ true); + if (!CheckLiteralOp</*kIsLit16=*/ true>( + inst, inst_data, kInteger, kInteger, /*check_boolean_op=*/ false)) { + return false; + } break; case Instruction::AND_INT_LIT16: case Instruction::OR_INT_LIT16: case Instruction::XOR_INT_LIT16: - CheckLiteralOp( - inst, inst_data, kInteger, kInteger, /*check_boolean_op=*/ true, /*is_lit16=*/ true); + if (!CheckLiteralOp</*kIsLit16=*/ true>( + inst, inst_data, kInteger, kInteger, /*check_boolean_op=*/ true)) { + return false; + } break; case Instruction::ADD_INT_LIT8: case Instruction::RSUB_INT_LIT8: @@ -3776,14 +3915,18 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g case Instruction::SHL_INT_LIT8: case Instruction::SHR_INT_LIT8: case Instruction::USHR_INT_LIT8: - CheckLiteralOp( - inst, inst_data, kInteger, kInteger, /*check_boolean_op=*/ false, /*is_lit16=*/ false); + if (!CheckLiteralOp</*kIsLit16=*/ false>( + inst, inst_data, kInteger, kInteger, /*check_boolean_op=*/ false)) { + return false; + } break; case Instruction::AND_INT_LIT8: case Instruction::OR_INT_LIT8: case Instruction::XOR_INT_LIT8: - CheckLiteralOp( - inst, inst_data, kInteger, kInteger, /*check_boolean_op=*/ true, /*is_lit16=*/ false); + if (!CheckLiteralOp</*kIsLit16=*/ false>( + inst, inst_data, kInteger, kInteger, /*check_boolean_op=*/ true)) { + return false; + } break; /* These should never appear during verification. */ @@ -3793,7 +3936,7 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g case Instruction::UNUSED_79: case Instruction::UNUSED_7A: Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Unexpected opcode " << inst->DumpString(dex_file_); - break; + return false; /* * DO NOT add a "default" clause here. Without it the compiler will diff --git a/tools/ahat/Android.bp b/tools/ahat/Android.bp index 57d239cc54..29fc18f5e4 100644 --- a/tools/ahat/Android.bp +++ b/tools/ahat/Android.bp @@ -13,11 +13,6 @@ // limitations under the License. package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "art_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 default_applicable_licenses: ["art_license"], } @@ -56,6 +51,12 @@ java_test_helper_library { srcs: ["src/ri-test-dump/**/*.java"], } +java_binary_host { + name: "ahat-ri-test-dump-bin", + static_libs: ["ahat-ri-test-dump"], + main_class: "Main", +} + cc_library_shared { name: "libahat-test-jni", srcs: ["src/test/jni/**/*.cpp"], @@ -72,3 +73,30 @@ java_genrule { out: ["ahat-test-dump-gen.sh"], cmd: "sed -e s=@AHAT_TEST_DUMP_JAR@=$(location :ahat-test-dump)= $(location ahat-test-dump-gen.sh.in) > $(out)", } + +// Run ahat-ri-test-dump to generate ri-test-dump.hprof +genrule { + name: "ahat_ri_test_dump_hprof", + out: ["ri-test-dump.hprof"], + tools: ["ahat-ri-test-dump-bin"], + cmd: "$(location ahat-ri-test-dump-bin) $(out)", +} + +// To run these tests, use: atest ahat-tests --host +java_test_host { + name: "ahat-tests", + srcs: ["src/test/**/*.java"], + manifest: "etc/ahat-tests.mf", + java_resources: [ + ":ahat_ri_test_dump_hprof", + ":ahat-tests-res", + ], + static_libs: [ + "ahat", + "junit-host", + ], + test_options: { + unit_test: true, + }, + test_suites: ["general-tests"], +} diff --git a/tools/ahat/Android.mk b/tools/ahat/Android.mk deleted file mode 100644 index 8a1ab87303..0000000000 --- a/tools/ahat/Android.mk +++ /dev/null @@ -1,62 +0,0 @@ -# -# Copyright (C) 2015 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. -# - -LOCAL_PATH := $(call my-dir) - -include art/build/Android.common_path.mk - -# Determine the location of the ri-test-dump.jar and ri-test-dump.hprof. -AHAT_RI_TEST_DUMP_JAR := $(call intermediates-dir-for,JAVA_LIBRARIES,ahat-ri-test-dump,HOST)/javalib.jar -AHAT_RI_TEST_DUMP_COMMON := $(call intermediates-dir-for,JAVA_LIBRARIES,ahat-ri-test-dump,HOST,COMMON) -AHAT_RI_TEST_DUMP_HPROF := $(AHAT_RI_TEST_DUMP_COMMON)/ri-test-dump.hprof - -# Run ahat-ri-test-dump.jar to generate ri-test-dump.hprof -$(AHAT_RI_TEST_DUMP_HPROF): PRIVATE_AHAT_RI_TEST_DUMP_JAR := $(AHAT_RI_TEST_DUMP_JAR) -$(AHAT_RI_TEST_DUMP_HPROF): $(AHAT_RI_TEST_DUMP_JAR) - rm -rf $@ - java -cp $(PRIVATE_AHAT_RI_TEST_DUMP_JAR) Main $@ - -# --- ahat-tests.jar -------------- -# To run these tests, use: atest ahat-tests --host -include $(CLEAR_VARS) -LOCAL_SRC_FILES := $(call all-java-files-under, src/test) -LOCAL_JAR_MANIFEST := etc/ahat-tests.mf -LOCAL_JAVA_RESOURCE_FILES := \ - $(LOCAL_PATH)/etc/test-dump.hprof \ - $(LOCAL_PATH)/etc/test-dump-base.hprof \ - $(LOCAL_PATH)/etc/test-dump.map \ - $(AHAT_RI_TEST_DUMP_HPROF) \ - $(LOCAL_PATH)/etc/L.hprof \ - $(LOCAL_PATH)/etc/O.hprof \ - $(LOCAL_PATH)/etc/RI.hprof -LOCAL_STATIC_JAVA_LIBRARIES := ahat junit-host -LOCAL_IS_HOST_MODULE := true -LOCAL_MODULE_TAGS := tests -LOCAL_MODULE := ahat-tests -LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 -LOCAL_LICENSE_CONDITIONS := notice -LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE -LOCAL_TEST_CONFIG := ahat-tests.xml -LOCAL_COMPATIBILITY_SUITE := general-tests -include $(BUILD_HOST_JAVA_LIBRARY) -AHAT_TEST_JAR := $(LOCAL_BUILT_MODULE) - -# Clean up local variables. -AHAT_TEST_JAR := - -AHAT_RI_TEST_DUMP_JAR := -AHAT_RI_TEST_DUMP_COMMON := -AHAT_RI_TEST_DUMP_HPROF := diff --git a/tools/ahat/ahat-tests.xml b/tools/ahat/ahat-tests.xml deleted file mode 100644 index b07905a9a7..0000000000 --- a/tools/ahat/ahat-tests.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- 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. ---> -<configuration description="Runs the ahat unit tests"> - <option name="test-suite-tag" value="ahat" /> - <option name="test-suite-tag" value="art-tools" /> - <option name="null-device" value="true" /> - <test class="com.android.tradefed.testtype.HostTest" > - <option name="class" value="com.android.ahat.AhatTestSuite" /> - </test> -</configuration> diff --git a/tools/ahat/etc/Android.bp b/tools/ahat/etc/Android.bp new file mode 100644 index 0000000000..dd38518a36 --- /dev/null +++ b/tools/ahat/etc/Android.bp @@ -0,0 +1,30 @@ +// +// Copyright (C) 2025 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 { + default_applicable_licenses: ["art_license"], +} + +filegroup { + name: "ahat-tests-res", + srcs: [ + "test-dump.hprof", + "test-dump-base.hprof", + "test-dump.map", + "L.hprof", + "O.hprof", + "RI.hprof", + ], +} |