summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dexdump/dexdump.cc2
-rw-r--r--libartbase/base/hiddenapi_flags.h241
-rw-r--r--libdexfile/dex/class_accessor-inl.h4
-rw-r--r--libdexfile/dex/dex_file_verifier.cc2
-rw-r--r--runtime/hidden_api.cc15
-rw-r--r--runtime/hidden_api.h2
-rw-r--r--runtime/hidden_api_test.cc51
-rw-r--r--runtime/mirror/class.cc3
-rw-r--r--tools/hiddenapi/hiddenapi.cc6
-rw-r--r--tools/hiddenapi/hiddenapi_test.cc14
-rw-r--r--tools/veridex/api_list_filter.h7
-rw-r--r--tools/veridex/hidden_api.cc2
-rw-r--r--tools/veridex/hidden_api.h2
-rw-r--r--tools/veridex/veridex.cc4
14 files changed, 199 insertions, 156 deletions
diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc
index 43ed224b01..dd90d90cf2 100644
--- a/dexdump/dexdump.cc
+++ b/dexdump/dexdump.cc
@@ -1341,7 +1341,7 @@ static void dumpCode(const DexFile* pDexFile, u4 idx, u4 flags,
static std::string GetHiddenapiFlagStr(uint32_t hiddenapi_flags) {
std::stringstream ss;
- hiddenapi::ApiList api_list(hiddenapi_flags);
+ hiddenapi::ApiList api_list = hiddenapi::ApiList::FromDexFlags(hiddenapi_flags);
api_list.Dump(ss);
std::string str_api_list = ss.str();
std::transform(str_api_list.begin(), str_api_list.end(), str_api_list.begin(), ::toupper);
diff --git a/libartbase/base/hiddenapi_flags.h b/libartbase/base/hiddenapi_flags.h
index 0d7938aca1..9ab8c759c3 100644
--- a/libartbase/base/hiddenapi_flags.h
+++ b/libartbase/base/hiddenapi_flags.h
@@ -17,15 +17,15 @@
#ifndef ART_LIBARTBASE_BASE_HIDDENAPI_FLAGS_H_
#define ART_LIBARTBASE_BASE_HIDDENAPI_FLAGS_H_
-#include "sdk_version.h"
+#include <android-base/logging.h>
#include <vector>
-#include "android-base/logging.h"
#include "base/bit_utils.h"
#include "base/dumpable.h"
-#include "base/macros.h"
#include "base/hiddenapi_stubs.h"
+#include "base/macros.h"
+#include "sdk_version.h"
namespace art {
namespace hiddenapi {
@@ -80,15 +80,20 @@ namespace helper {
*/
class ApiList {
private:
+ // The representation in dex_flags_ is a combination of a Value in the lowest
+ // kValueBitSize bits, and bit flags corresponding to DomainApi in bits above
+ // that.
+ uint32_t dex_flags_;
+
// Number of bits reserved for Value in dex flags, and the corresponding bit mask.
static constexpr uint32_t kValueBitSize = 4;
static constexpr uint32_t kValueBitMask = helper::BitMask(kValueBitSize);
enum class Value : uint32_t {
// Values independent of target SDK version of app
- kSdk = 0,
- kUnsupported = 1,
- kBlocked = 2,
+ kSdk = 0,
+ kUnsupported = 1, // @UnsupportedAppUsage
+ kBlocked = 2,
// Values dependent on target SDK version of app. Put these last as
// their list will be extended in future releases.
@@ -100,21 +105,24 @@ class ApiList {
kMaxTargetR = 6,
kMaxTargetS = 7,
- // Special values
- kInvalid = (static_cast<uint32_t>(-1) & kValueBitMask),
- kMin = kSdk,
- kMax = kMaxTargetS,
+ // Invalid value. Does not imply the DomainApi is invalid.
+ kInvalid = (static_cast<uint32_t>(-1) & kValueBitMask),
+
+ kMin = kSdk,
+ kMax = kMaxTargetS,
+ kFuture = kMax + 1, // Only for testing
};
- // Additional bit flags after the first kValueBitSize bits in dex flags.
- // These are used for domain-specific API.
+ // Additional bit flags after the first kValueBitSize bits in dex flags. These
+ // are used for domain-specific APIs. The app domain is the default when no
+ // bits are set.
enum class DomainApi : uint32_t {
kCorePlatformApi = kValueBitSize,
kTestApi = kValueBitSize + 1,
// Special values
- kMin = kCorePlatformApi,
- kMax = kTestApi,
+ kMin = kCorePlatformApi,
+ kMax = kTestApi,
};
// Bit mask of all domain API flags.
@@ -124,12 +132,22 @@ class ApiList {
static_assert(kValueBitSize >= MinimumBitsToStore(helper::ToUint(Value::kMax)),
"Not enough bits to store all ApiList values");
- // Checks that all Values are covered by kValueBitMask.
+ // Check that all Values are covered by kValueBitMask.
static_assert(helper::MatchesBitMask(Value::kMin, kValueBitMask));
static_assert(helper::MatchesBitMask(Value::kMax, kValueBitMask));
+ static_assert(helper::MatchesBitMask(Value::kFuture, kValueBitMask));
+ static_assert(helper::MatchesBitMask(Value::kInvalid, kValueBitMask));
+
+ // Check that there's no offset between Values and the corresponding uint32
+ // dex flags, so they can be converted between each other without any change.
+ static_assert(helper::ToUint(Value::kMin) == 0);
- // Assert that Value::kInvalid is larger than the maximum Value.
- static_assert(helper::ToUint(Value::kMax) < helper::ToUint(Value::kInvalid));
+ // Check that Value::kInvalid is larger than kFuture (which is larger than kMax).
+ static_assert(helper::ToUint(Value::kFuture) < helper::ToUint(Value::kInvalid));
+
+ // Check that no DomainApi bit flag is covered by kValueBitMask.
+ static_assert((helper::ToBit(DomainApi::kMin) & kValueBitMask) == 0);
+ static_assert((helper::ToBit(DomainApi::kMax) & kValueBitMask) == 0);
// Names corresponding to Values.
static constexpr const char* kValueNames[] = {
@@ -165,13 +183,32 @@ class ApiList {
/* max-target-s */ SdkVersion::kS,
};
- explicit ApiList(Value val, uint32_t domain_apis = 0u)
- : dex_flags_(helper::ToUint(val) | domain_apis) {
- DCHECK(GetValue() == val);
- DCHECK_EQ(GetDomainApis(), domain_apis);
+ explicit ApiList(uint32_t dex_flags) : dex_flags_(dex_flags) {
+ DCHECK_EQ(dex_flags_, (dex_flags_ & kValueBitMask) | (dex_flags_ & kDomainApiBitMask));
}
- explicit ApiList(DomainApi val) : ApiList(Value::kInvalid, helper::ToBit(val)) {}
+ static ApiList FromValue(Value val) {
+ ApiList api_list(helper::ToUint(val));
+ DCHECK(api_list.GetValue() == val);
+ DCHECK_EQ(api_list.GetDomainApis(), 0u);
+ return api_list;
+ }
+
+ // Returns an ApiList with only a DomainApi bit set - the Value is invalid. It
+ // can be Combine'd with another ApiList with a Value to produce a valid combination.
+ static ApiList FromDomainApi(DomainApi domain_api) {
+ ApiList api_list(helper::ToUint(Value::kInvalid) | helper::ToBit(domain_api));
+ DCHECK(api_list.GetValue() == Value::kInvalid);
+ DCHECK_EQ(api_list.GetDomainApis(), helper::ToBit(domain_api));
+ return api_list;
+ }
+
+ static ApiList FromValueAndDomainApis(Value val, uint32_t domain_apis) {
+ ApiList api_list(helper::ToUint(val) | domain_apis);
+ DCHECK(api_list.GetValue() == val);
+ DCHECK_EQ(api_list.GetDomainApis(), domain_apis);
+ return api_list;
+ }
Value GetValue() const {
uint32_t value = (dex_flags_ & kValueBitMask);
@@ -190,47 +227,80 @@ class ApiList {
uint32_t GetDomainApis() const { return (dex_flags_ & kDomainApiBitMask); }
- uint32_t dex_flags_;
-
- public:
- ApiList() : ApiList(Value::kInvalid) {}
+ // In order to correctly handle flagged changes from Unsupported to the Sdk, where both will be
+ // set when the flag is enabled, consider Sdk to take precedence over any form of unsupported.
+ // Note, this is not necessary in the inverse direction, because API flagging does not currently
+ // support API removal. Moving from the blocklist to unsupported is also a case we don't have to
+ // consider.
+ // If this is true, the conflict resolves to Value::kSdk.
+ static bool IsConflictingFlagsAcceptable(Value x, Value y) {
+ const auto predicate_non_symmetric = [](auto l, auto r) {
+ if (l != Value::kSdk) {
+ return false;
+ }
+ switch (r) {
+ case Value::kSdk:
+ case Value::kUnsupported:
+ case Value::kMaxTargetO:
+ case Value::kMaxTargetP:
+ case Value::kMaxTargetQ:
+ case Value::kMaxTargetR:
+ case Value::kMaxTargetS:
+ return true;
+ default:
+ return false;
+ }
+ };
+ return predicate_non_symmetric(x, y) || predicate_non_symmetric(y, x);
+ }
- explicit ApiList(uint32_t dex_flags) : dex_flags_(dex_flags) {
- DCHECK_EQ(dex_flags_, (dex_flags_ & kValueBitMask) | (dex_flags_ & kDomainApiBitMask));
+ // Returns true if combining this ApiList with `other` will succeed.
+ bool CanCombineWith(const ApiList& other) const {
+ const Value val1 = GetValue();
+ const Value val2 = other.GetValue();
+ return (val1 == val2) || (val1 == Value::kInvalid) || (val2 == Value::kInvalid) ||
+ IsConflictingFlagsAcceptable(val1, val2);
}
+ public:
// Helpers for conveniently constructing ApiList instances.
- static ApiList Sdk() { return ApiList(Value::kSdk); }
- static ApiList Unsupported() { return ApiList(Value::kUnsupported); }
- static ApiList Blocked() { return ApiList(Value::kBlocked); }
- static ApiList MaxTargetO() { return ApiList(Value::kMaxTargetO); }
- static ApiList MaxTargetP() { return ApiList(Value::kMaxTargetP); }
- static ApiList MaxTargetQ() { return ApiList(Value::kMaxTargetQ); }
- static ApiList MaxTargetR() { return ApiList(Value::kMaxTargetR); }
- static ApiList MaxTargetS() { return ApiList(Value::kMaxTargetS); }
- static ApiList CorePlatformApi() { return ApiList(DomainApi::kCorePlatformApi); }
- static ApiList TestApi() { return ApiList(DomainApi::kTestApi); }
+ static ApiList Sdk() { return FromValue(Value::kSdk); }
+ static ApiList Unsupported() { return FromValue(Value::kUnsupported); }
+ static ApiList Blocked() { return FromValue(Value::kBlocked); }
+ static ApiList MaxTargetO() { return FromValue(Value::kMaxTargetO); }
+ static ApiList MaxTargetP() { return FromValue(Value::kMaxTargetP); }
+ static ApiList MaxTargetQ() { return FromValue(Value::kMaxTargetQ); }
+ static ApiList MaxTargetR() { return FromValue(Value::kMaxTargetR); }
+ static ApiList MaxTargetS() { return FromValue(Value::kMaxTargetS); }
+ static ApiList Invalid() { return FromValue(Value::kInvalid); }
+ static ApiList CorePlatformApi() { return FromDomainApi(DomainApi::kCorePlatformApi); }
+ static ApiList TestApi() { return FromDomainApi(DomainApi::kTestApi); }
uint32_t GetDexFlags() const { return dex_flags_; }
- uint32_t GetIntValue() const { return helper::ToUint(GetValue()) - helper::ToUint(Value::kMin); }
+ uint32_t GetIntValue() const { return helper::ToUint(GetValue()); }
+
+ static ApiList FromDexFlags(uint32_t dex_flags) { return ApiList(dex_flags); }
+
+ static ApiList FromIntValue(uint32_t int_val) {
+ return FromValue(helper::GetEnumAt<Value>(int_val));
+ }
// Returns the ApiList with a flag of a given name, or an empty ApiList if not matched.
static ApiList FromName(const std::string& str) {
for (uint32_t i = 0; i < kValueCount; ++i) {
if (str == kValueNames[i]) {
- return ApiList(helper::GetEnumAt<Value>(i));
+ return FromIntValue(i);
}
}
for (uint32_t i = 0; i < kDomainApiCount; ++i) {
if (str == kDomainApiNames[i]) {
- return ApiList(helper::GetEnumAt<DomainApi>(i));
+ return FromDomainApi(helper::GetEnumAt<DomainApi>(i));
}
}
if (str == kFutureValueName) {
- static_assert(helper::ToUint(Value::kMax) + 1 < helper::ToUint(Value::kInvalid));
- return ApiList(helper::ToUint(Value::kMax) + 1);
+ return FromValue(Value::kFuture);
}
- return ApiList();
+ return Invalid();
}
// Parses a vector of flag names into a single ApiList value. If successful,
@@ -238,7 +308,7 @@ class ApiList {
static bool FromNames(std::vector<std::string>::iterator begin,
std::vector<std::string>::iterator end,
/* out */ ApiList* out_api_list) {
- ApiList api_list;
+ ApiList api_list = Invalid();
for (std::vector<std::string>::iterator it = begin; it != end; it++) {
ApiList current = FromName(*it);
if (current.IsEmpty() || !api_list.CanCombineWith(current)) {
@@ -250,7 +320,7 @@ class ApiList {
}
return false;
}
- api_list |= current;
+ api_list = Combine(api_list, current);
}
if (out_api_list != nullptr) {
*out_api_list = api_list;
@@ -260,71 +330,36 @@ class ApiList {
bool operator==(const ApiList& other) const { return dex_flags_ == other.dex_flags_; }
bool operator!=(const ApiList& other) const { return !(*this == other); }
- bool operator<(const ApiList& other) const { return dex_flags_ < other.dex_flags_; }
- bool operator>(const ApiList& other) const { return dex_flags_ > other.dex_flags_; }
- // In order to correctly handle flagged changes from Unsupported to the Sdk, where both will be
- // set when the flag is enabled, consider Sdk to take precedence over any form of unsupported.
- // Note, this is not necessary in the inverse direction, because API flagging does not currently
- // support API removal. Moving from the blocklist to unsupported is also a case we don't have to
- // consider.
- // If this is true, the conflict resolves to Value::kSdk.
- static bool is_conflicting_flags_acceptable(Value x, Value y) {
- const auto predicate_non_symmetric = [] (auto l, auto r) {
- if (l != Value::kSdk) return false;
- switch (r) {
- case Value::kSdk:
- case Value::kUnsupported:
- case Value::kMaxTargetO:
- case Value::kMaxTargetP:
- case Value::kMaxTargetQ:
- case Value::kMaxTargetR:
- case Value::kMaxTargetS:
- return true;
- default:
- return false;
- }
- };
- return predicate_non_symmetric(x, y) || predicate_non_symmetric(y, x);
- }
-
- // Returns true if combining this ApiList with `other` will succeed.
- bool CanCombineWith(const ApiList& other) const {
- const Value val1 = GetValue();
- const Value val2 = other.GetValue();
- return (val1 == val2) || (val1 == Value::kInvalid) || (val2 == Value::kInvalid) ||
- is_conflicting_flags_acceptable(val1, val2);
- }
+ // The order doesn't have any significance - only for ordering in containers.
+ bool operator<(const ApiList& other) const { return dex_flags_ < other.dex_flags_; }
- // Combine two ApiList instances.
- ApiList operator|(const ApiList& other) {
+ // Combine two ApiList instances. The returned value has the union of the API
+ // domains. Values are mutually exclusive, so they either have to be identical
+ // or one of them can be safely ignored, which includes being kInvalid.
+ static ApiList Combine(const ApiList& api1, const ApiList& api2) {
// DomainApis are not mutually exclusive. Simply OR them.
- const uint32_t domain_apis = GetDomainApis() | other.GetDomainApis();
+ // TODO: This is suspect since the app domain doesn't have any bit and hence
+ // implicitly disappears if OR'ed with any other domain.
+ const uint32_t domain_apis = api1.GetDomainApis() | api2.GetDomainApis();
- // Values are mutually exclusive. Check if `this` and `other` have the same Value
- // or if at most one is set.
- const Value val1 = GetValue();
- const Value val2 = other.GetValue();
+ const Value val1 = api1.GetValue();
+ const Value val2 = api2.GetValue();
if (val1 == val2) {
- return ApiList(val1, domain_apis);
+ return FromValueAndDomainApis(val1, domain_apis);
} else if (val1 == Value::kInvalid) {
- return ApiList(val2, domain_apis);
+ return FromValueAndDomainApis(val2, domain_apis);
} else if (val2 == Value::kInvalid) {
- return ApiList(val1, domain_apis);
- } else if (is_conflicting_flags_acceptable(val1, val2)) {
- return ApiList(Value::kSdk, domain_apis);
+ return FromValueAndDomainApis(val1, domain_apis);
+ } else if (IsConflictingFlagsAcceptable(val1, val2)) {
+ return FromValueAndDomainApis(Value::kSdk, domain_apis);
} else {
- LOG(FATAL) << "Invalid combination of values " << Dumpable(ApiList(val1))
- << " and " << Dumpable(ApiList(val2));
+ LOG(FATAL) << "Invalid combination of values " << Dumpable(FromValue(val1)) << " and "
+ << Dumpable(FromValue(val2));
UNREACHABLE();
}
}
- const ApiList& operator|=(const ApiList& other) {
- (*this) = (*this) | other;
- return *this;
- }
-
// Returns true if all flags set in `other` are also set in `this`.
bool Contains(const ApiList& other) const {
return ((other.GetValue() == Value::kInvalid) || (GetValue() == other.GetValue())) &&
@@ -338,13 +373,9 @@ class ApiList {
bool IsEmpty() const { return (GetValue() == Value::kInvalid) && (GetDomainApis() == 0); }
// Returns true if the ApiList is on blocklist.
- bool IsBlocked() const {
- return GetValue() == Value::kBlocked;
- }
+ bool IsBlocked() const { return GetValue() == Value::kBlocked; }
- bool IsSdkApi() const {
- return GetValue() == Value::kSdk;
- }
+ bool IsSdkApi() const { return GetValue() == Value::kSdk; }
// Returns true if the ApiList is a test API.
bool IsTestApi() const {
diff --git a/libdexfile/dex/class_accessor-inl.h b/libdexfile/dex/class_accessor-inl.h
index 5979f86e8d..663b75cf86 100644
--- a/libdexfile/dex/class_accessor-inl.h
+++ b/libdexfile/dex/class_accessor-inl.h
@@ -69,7 +69,7 @@ inline void ClassAccessor::Method::Read() {
code_off_ = DecodeUnsignedLeb128(&ptr_pos_);
if (hiddenapi_ptr_pos_ != nullptr) {
hiddenapi_flags_ = DecodeUnsignedLeb128(&hiddenapi_ptr_pos_);
- DCHECK(hiddenapi::ApiList(hiddenapi_flags_).IsValid());
+ DCHECK(hiddenapi::ApiList::FromDexFlags(hiddenapi_flags_).IsValid());
}
}
@@ -83,7 +83,7 @@ inline void ClassAccessor::Field::Read() {
access_flags_ = DecodeUnsignedLeb128(&ptr_pos_);
if (hiddenapi_ptr_pos_ != nullptr) {
hiddenapi_flags_ = DecodeUnsignedLeb128(&hiddenapi_ptr_pos_);
- DCHECK(hiddenapi::ApiList(hiddenapi_flags_).IsValid());
+ DCHECK(hiddenapi::ApiList::FromDexFlags(hiddenapi_flags_).IsValid());
}
}
diff --git a/libdexfile/dex/dex_file_verifier.cc b/libdexfile/dex/dex_file_verifier.cc
index f0fe14fb4d..3f2fd627db 100644
--- a/libdexfile/dex/dex_file_verifier.cc
+++ b/libdexfile/dex/dex_file_verifier.cc
@@ -2683,7 +2683,7 @@ bool DexFileVerifier::CheckInterHiddenapiClassData() {
failure = true;
return;
}
- if (!hiddenapi::ApiList(decoded_flags).IsValid()) {
+ if (!hiddenapi::ApiList::FromDexFlags(decoded_flags).IsValid()) {
ErrorStringPrintf("Hiddenapi class data flags invalid (%u) for %s %i",
decoded_flags, member_type, member.GetIndex());
failure = true;
diff --git a/runtime/hidden_api.cc b/runtime/hidden_api.cc
index c7fb3ef7ff..0dc0b352f9 100644
--- a/runtime/hidden_api.cc
+++ b/runtime/hidden_api.cc
@@ -354,7 +354,7 @@ void MemberSignature::Dump(std::ostream& os) const {
}
void MemberSignature::LogAccessToLogcat(AccessMethod access_method,
- hiddenapi::ApiList list,
+ ApiList api_list,
bool access_denied,
uint32_t runtime_flags,
const AccessContext& caller_context,
@@ -368,10 +368,10 @@ void MemberSignature::LogAccessToLogcat(AccessMethod access_method,
<< "hiddenapi: Accessing hidden " << (type_ == kField ? "field " : "method ")
<< Dumpable<MemberSignature>(*this)
<< " (runtime_flags=" << FormatHiddenApiRuntimeFlags(runtime_flags)
- << ", domain=" << callee_context.GetDomain() << ", api=" << list << ") from "
+ << ", domain=" << callee_context.GetDomain() << ", api=" << api_list << ") from "
<< caller_context << " (domain=" << caller_context.GetDomain() << ") using " << access_method
<< (access_denied ? ": denied" : ": allowed");
- if (access_denied && list.IsTestApi()) {
+ if (access_denied && api_list.IsTestApi()) {
// see b/177047045 for more details about test api access getting denied
LOG(WARNING) << "hiddenapi: If this is a platform test consider enabling "
<< "VMRuntime.ALLOW_TEST_API_ACCESS change id for this package.";
@@ -533,8 +533,7 @@ uint32_t GetDexFlags(T* member) REQUIRES_SHARED(Locks::mutator_lock_) {
ObjPtr<mirror::Class> declaring_class = member->GetDeclaringClass();
DCHECK(!declaring_class.IsNull()) << "Attempting to access a runtime method";
- ApiList flags;
- DCHECK(!flags.IsValid());
+ ApiList flags = ApiList::Invalid();
// Check if the declaring class has ClassExt allocated. If it does, check if
// the pre-JVMTI redefine dex file has been set to determine if the declaring
@@ -556,7 +555,7 @@ uint32_t GetDexFlags(T* member) REQUIRES_SHARED(Locks::mutator_lock_) {
uint32_t member_index = GetMemberDexIndex(member);
auto fn_visit = [&](const AccessorType& dex_member) {
if (dex_member.GetIndex() == member_index) {
- flags = ApiList(dex_member.GetHiddenapiFlags());
+ flags = ApiList::FromDexFlags(dex_member.GetHiddenapiFlags());
}
};
VisitMembers(declaring_class->GetDexFile(), *class_def, fn_visit);
@@ -576,7 +575,7 @@ uint32_t GetDexFlags(T* member) REQUIRES_SHARED(Locks::mutator_lock_) {
MemberSignature cur_signature(dex_member);
if (member_signature.MemberNameAndTypeMatch(cur_signature)) {
DCHECK(member_signature.Equals(cur_signature));
- flags = ApiList(dex_member.GetHiddenapiFlags());
+ flags = ApiList::FromDexFlags(dex_member.GetHiddenapiFlags());
}
};
VisitMembers(*original_dex, original_class_def, fn_visit);
@@ -811,7 +810,7 @@ bool ShouldDenyAccessToMember(T* member,
// Decode hidden API access flags from the dex file.
// This is an O(N) operation scaling with the number of fields/methods
// in the class. Only do this on slow path and only do it once.
- ApiList api_list(detail::GetDexFlags(member));
+ ApiList api_list = ApiList::FromDexFlags(detail::GetDexFlags(member));
DCHECK(api_list.IsValid());
// Member is hidden and caller is not exempted. Enter slow path.
diff --git a/runtime/hidden_api.h b/runtime/hidden_api.h
index d2a6cdcbd3..7d7bd75fc4 100644
--- a/runtime/hidden_api.h
+++ b/runtime/hidden_api.h
@@ -266,7 +266,7 @@ inline ArtMethod* GetInterfaceMemberIfProxy(ArtMethod* method)
ALWAYS_INLINE inline uint32_t CreateRuntimeFlags_Impl(uint32_t dex_flags) {
uint32_t runtime_flags = 0u;
- ApiList api_list(dex_flags);
+ ApiList api_list = ApiList::FromDexFlags(dex_flags);
DCHECK(api_list.IsValid());
if (api_list.Contains(ApiList::Sdk())) {
diff --git a/runtime/hidden_api_test.cc b/runtime/hidden_api_test.cc
index 5a2ee55723..39cca7cce6 100644
--- a/runtime/hidden_api_test.cc
+++ b/runtime/hidden_api_test.cc
@@ -202,6 +202,11 @@ class HiddenApiTest : public CommonRuntimeTest {
hiddenapi::AccessMethod::kCheck);
}
+ bool ShouldDenyAccess(hiddenapi::ApiList list1, hiddenapi::ApiList list2)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ return ShouldDenyAccess(hiddenapi::ApiList::Combine(list1, list2));
+ }
+
void TestLocation(const std::string& location, hiddenapi::Domain expected_domain) {
// Create a temp file with a unique name based on `location` to isolate tests
// that may run in parallel. b/238730923
@@ -382,59 +387,63 @@ TEST_F(HiddenApiTest, CheckTestApiEnforcement) {
runtime_->SetTargetSdkVersion(
static_cast<uint32_t>(hiddenapi::ApiList::MaxTargetR().GetMaxAllowedSdkVersion()) + 1);
+ // clang-format off
+
// Default case where all TestApis are treated like non-TestApi.
runtime_->SetTestApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kEnabled);
SetChangeIdState(kAllowTestApiAccess, false);
ASSERT_EQ(
- ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::Sdk()), false);
+ ShouldDenyAccess(hiddenapi::ApiList::TestApi(), hiddenapi::ApiList::Sdk()), false);
ASSERT_EQ(
- ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::Unsupported()), false);
+ ShouldDenyAccess(hiddenapi::ApiList::TestApi(), hiddenapi::ApiList::Unsupported()), false);
ASSERT_EQ(
- ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::MaxTargetR()), true);
+ ShouldDenyAccess(hiddenapi::ApiList::TestApi(), hiddenapi::ApiList::MaxTargetR()), true);
ASSERT_EQ(
- ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::MaxTargetQ()), true);
+ ShouldDenyAccess(hiddenapi::ApiList::TestApi(), hiddenapi::ApiList::MaxTargetQ()), true);
ASSERT_EQ(
- ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::MaxTargetP()), true);
+ ShouldDenyAccess(hiddenapi::ApiList::TestApi(), hiddenapi::ApiList::MaxTargetP()), true);
ASSERT_EQ(
- ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::MaxTargetO()), true);
+ ShouldDenyAccess(hiddenapi::ApiList::TestApi(), hiddenapi::ApiList::MaxTargetO()), true);
ASSERT_EQ(
- ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::Blocked()), true);
+ ShouldDenyAccess(hiddenapi::ApiList::TestApi(), hiddenapi::ApiList::Blocked()), true);
// A case where we want to allow access to TestApis.
runtime_->SetTestApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kDisabled);
SetChangeIdState(kAllowTestApiAccess, false);
ASSERT_EQ(
- ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::Sdk()), false);
+ ShouldDenyAccess(hiddenapi::ApiList::TestApi(), hiddenapi::ApiList::Sdk()), false);
ASSERT_EQ(
- ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::Unsupported()), false);
+ ShouldDenyAccess(hiddenapi::ApiList::TestApi(), hiddenapi::ApiList::Unsupported()), false);
ASSERT_EQ(
- ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::MaxTargetR()), false);
+ ShouldDenyAccess(hiddenapi::ApiList::TestApi(), hiddenapi::ApiList::MaxTargetR()), false);
ASSERT_EQ(
- ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::MaxTargetQ()), false);
+ ShouldDenyAccess(hiddenapi::ApiList::TestApi(), hiddenapi::ApiList::MaxTargetQ()), false);
ASSERT_EQ(
- ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::MaxTargetP()), false);
+ ShouldDenyAccess(hiddenapi::ApiList::TestApi(), hiddenapi::ApiList::MaxTargetP()), false);
ASSERT_EQ(
- ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::MaxTargetO()), false);
+ ShouldDenyAccess(hiddenapi::ApiList::TestApi(), hiddenapi::ApiList::MaxTargetO()), false);
ASSERT_EQ(
- ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::Blocked()), false);
+ ShouldDenyAccess(hiddenapi::ApiList::TestApi(), hiddenapi::ApiList::Blocked()), false);
// A second case where we want to allow access to TestApis.
runtime_->SetTestApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kEnabled);
SetChangeIdState(kAllowTestApiAccess, true);
ASSERT_EQ(
- ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::Sdk()), false);
+ ShouldDenyAccess(hiddenapi::ApiList::TestApi(), hiddenapi::ApiList::Sdk()), false);
ASSERT_EQ(
- ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::Unsupported()), false);
+ ShouldDenyAccess(hiddenapi::ApiList::TestApi(), hiddenapi::ApiList::Unsupported()), false);
ASSERT_EQ(
- ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::MaxTargetR()), false);
+ ShouldDenyAccess(hiddenapi::ApiList::TestApi(), hiddenapi::ApiList::MaxTargetR()), false);
ASSERT_EQ(
- ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::MaxTargetQ()), false);
+ ShouldDenyAccess(hiddenapi::ApiList::TestApi(), hiddenapi::ApiList::MaxTargetQ()), false);
ASSERT_EQ(
- ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::MaxTargetP()), false);
+ ShouldDenyAccess(hiddenapi::ApiList::TestApi(), hiddenapi::ApiList::MaxTargetP()), false);
ASSERT_EQ(
- ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::MaxTargetO()), false);
+ ShouldDenyAccess(hiddenapi::ApiList::TestApi(), hiddenapi::ApiList::MaxTargetO()), false);
ASSERT_EQ(
- ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::Blocked()), false);
+ ShouldDenyAccess(hiddenapi::ApiList::TestApi(), hiddenapi::ApiList::Blocked()), false);
+
+ // clang-format on
}
TEST_F(HiddenApiTest, CheckMembersRead) {
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index 7bc0826424..fe923cbaa6 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -2298,7 +2298,8 @@ static bool IsInterfaceMethodAccessible(ArtMethod* interface_method)
REQUIRES_SHARED(Locks::mutator_lock_) {
// If the interface method is part of the public SDK, return it.
if ((hiddenapi::GetRuntimeFlags(interface_method) & kAccPublicApi) != 0) {
- hiddenapi::ApiList api_list(hiddenapi::detail::GetDexFlags(interface_method));
+ hiddenapi::ApiList api_list =
+ hiddenapi::ApiList::FromDexFlags(hiddenapi::detail::GetDexFlags(interface_method));
// The kAccPublicApi flag is also used as an optimization to avoid
// other hiddenapi checks to always go on the slow path. Therefore, we
// need to check here if the method is in the SDK list.
diff --git a/tools/hiddenapi/hiddenapi.cc b/tools/hiddenapi/hiddenapi.cc
index f5a8d58374..f5d59b9f39 100644
--- a/tools/hiddenapi/hiddenapi.cc
+++ b/tools/hiddenapi/hiddenapi.cc
@@ -898,7 +898,7 @@ class HiddenApi final {
CHECK(!force_assign_all_ || api_list_found)
<< "Could not find hiddenapi flags for dex entry: " << signature;
if (api_list_found && it->second.GetIntValue() > max_hiddenapi_level_.GetIntValue()) {
- ApiList without_domain(it->second.GetIntValue());
+ ApiList without_domain = ApiList::FromDexFlags(it->second.GetIntValue());
LOG(ERROR) << "Hidden api flag " << without_domain << " for member " << signature
<< " in " << input_path << " exceeds maximum allowable flag "
<< max_hiddenapi_level_;
@@ -956,7 +956,7 @@ class HiddenApi final {
CHECK(api_flag_map.find(signature) == api_flag_map.end()) << path << ":" << line_number
<< ": Duplicate entry: " << signature << kErrorHelp;
- ApiList membership;
+ ApiList membership = ApiList::Invalid();
std::vector<std::string>::iterator apiListBegin = values.begin() + 1;
std::vector<std::string>::iterator apiListEnd = values.end();
@@ -1098,7 +1098,7 @@ class HiddenApi final {
//
// By default this returns a GetIntValue() that is guaranteed to be bigger than
// any valid value returned by GetIntValue().
- ApiList max_hiddenapi_level_;
+ ApiList max_hiddenapi_level_ = ApiList::Invalid();
// Whether the input is only a fragment of the whole bootclasspath and may
// not include a complete set of classes. That requires the tool to ignore missing
diff --git a/tools/hiddenapi/hiddenapi_test.cc b/tools/hiddenapi/hiddenapi_test.cc
index 3236dddfd3..940a2630d9 100644
--- a/tools/hiddenapi/hiddenapi_test.cc
+++ b/tools/hiddenapi/hiddenapi_test.cc
@@ -190,7 +190,7 @@ class HiddenApiTest : public CommonRuntimeTest {
const uint32_t actual_visibility = field.GetAccessFlags() & kAccVisibilityFlags;
CHECK_EQ(actual_visibility, expected_visibility)
<< "Field " << name << " in class " << accessor.GetDescriptorView();
- return hiddenapi::ApiList(field.GetHiddenapiFlags());
+ return hiddenapi::ApiList::FromDexFlags(field.GetHiddenapiFlags());
}
}
@@ -219,7 +219,7 @@ class HiddenApiTest : public CommonRuntimeTest {
const uint32_t actual_visibility = method.GetAccessFlags() & kAccVisibilityFlags;
CHECK_EQ(actual_visibility, expected_visibility)
<< "Method " << name << " in class " << accessor.GetDescriptorView();
- return hiddenapi::ApiList(method.GetHiddenapiFlags());
+ return hiddenapi::ApiList::FromDexFlags(method.GetHiddenapiFlags());
}
}
@@ -700,8 +700,9 @@ TEST_F(HiddenApiTest, InstanceFieldCorePlatformApiMatch) {
<< "LMain;->ifield:I,unsupported,core-platform-api" << std::endl;
auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_NE(dex_file.get(), nullptr);
- ASSERT_EQ(hiddenapi::ApiList::CorePlatformApi() |
- hiddenapi::ApiList::Unsupported(), GetIFieldHiddenFlags(*dex_file));
+ ASSERT_EQ(hiddenapi::ApiList::Combine(hiddenapi::ApiList::CorePlatformApi(),
+ hiddenapi::ApiList::Unsupported()),
+ GetIFieldHiddenFlags(*dex_file));
}
TEST_F(HiddenApiTest, InstanceFieldTestApiMatch) {
@@ -712,8 +713,9 @@ TEST_F(HiddenApiTest, InstanceFieldTestApiMatch) {
<< "LMain;->ifield:I,unsupported,test-api" << std::endl;
auto dex_file = RunHiddenapiEncode(flags_csv, {}, dex);
ASSERT_NE(dex_file.get(), nullptr);
- ASSERT_EQ(hiddenapi::ApiList::TestApi()
- | hiddenapi::ApiList::Unsupported(), GetIFieldHiddenFlags(*dex_file));
+ ASSERT_EQ(
+ hiddenapi::ApiList::Combine(hiddenapi::ApiList::TestApi(), hiddenapi::ApiList::Unsupported()),
+ GetIFieldHiddenFlags(*dex_file));
}
TEST_F(HiddenApiTest, InstanceFieldUnknownFlagMatch) {
diff --git a/tools/veridex/api_list_filter.h b/tools/veridex/api_list_filter.h
index 58065db2b2..c8e6aaa378 100644
--- a/tools/veridex/api_list_filter.h
+++ b/tools/veridex/api_list_filter.h
@@ -17,9 +17,10 @@
#ifndef ART_TOOLS_VERIDEX_API_LIST_FILTER_H_
#define ART_TOOLS_VERIDEX_API_LIST_FILTER_H_
-#include <algorithm>
#include <android-base/strings.h>
+#include <set>
+
#include "base/hiddenapi_flags.h"
namespace art {
@@ -46,10 +47,10 @@ class ApiListFilter {
}
if (include_invalid_list) {
- lists_.push_back(hiddenapi::ApiList());
+ lists_.push_back(hiddenapi::ApiList::Invalid());
}
for (size_t i = 0; i < hiddenapi::ApiList::kValueCount; ++i) {
- hiddenapi::ApiList list = hiddenapi::ApiList(i);
+ hiddenapi::ApiList list = hiddenapi::ApiList::FromIntValue(i);
if (exclude_set.find(list) == exclude_set.end()) {
lists_.push_back(list);
}
diff --git a/tools/veridex/hidden_api.cc b/tools/veridex/hidden_api.cc
index 4156aa954b..1e0e303c57 100644
--- a/tools/veridex/hidden_api.cc
+++ b/tools/veridex/hidden_api.cc
@@ -34,7 +34,7 @@ HiddenApi::HiddenApi(const char* filename, const ApiListFilter& api_list_filter)
std::vector<std::string> values = android::base::Split(str, ",");
const std::string& signature = values[0];
- hiddenapi::ApiList membership;
+ hiddenapi::ApiList membership = hiddenapi::ApiList::Invalid();
bool success = hiddenapi::ApiList::FromNames(values.begin() + 1, values.end(), &membership);
if (!success) {
LOG(ERROR) << "Unknown ApiList flag: " << str;
diff --git a/tools/veridex/hidden_api.h b/tools/veridex/hidden_api.h
index a8301743aa..12082c3c70 100644
--- a/tools/veridex/hidden_api.h
+++ b/tools/veridex/hidden_api.h
@@ -45,7 +45,7 @@ class HiddenApi {
hiddenapi::ApiList GetApiList(const std::string& name) const {
auto it = api_list_.find(name);
- return (it == api_list_.end()) ? hiddenapi::ApiList() : it->second;
+ return (it == api_list_.end()) ? hiddenapi::ApiList::Invalid() : it->second;
}
bool ShouldReport(const std::string& signature) const {
diff --git a/tools/veridex/veridex.cc b/tools/veridex/veridex.cc
index 9c7bd78cff..ec2e96168d 100644
--- a/tools/veridex/veridex.cc
+++ b/tools/veridex/veridex.cc
@@ -270,9 +270,9 @@ class Veridex {
os << stats.count << " hidden API(s) used: "
<< stats.linking_count << " linked against, "
<< stats.reflection_count << " through reflection" << std::endl;
- DumpApiListStats(os, stats, hiddenapi::ApiList(), api_list_filter);
+ DumpApiListStats(os, stats, hiddenapi::ApiList::Invalid(), api_list_filter);
for (size_t i = 0; i < hiddenapi::ApiList::kValueCount; ++i) {
- DumpApiListStats(os, stats, hiddenapi::ApiList(i), api_list_filter);
+ DumpApiListStats(os, stats, hiddenapi::ApiList::FromIntValue(i), api_list_filter);
}
}