diff options
Diffstat (limited to 'runtime/hidden_api.cc')
| -rw-r--r-- | runtime/hidden_api.cc | 93 | 
1 files changed, 74 insertions, 19 deletions
diff --git a/runtime/hidden_api.cc b/runtime/hidden_api.cc index 388ed33dfa..a0dc0d2120 100644 --- a/runtime/hidden_api.cc +++ b/runtime/hidden_api.cc @@ -34,6 +34,12 @@  namespace art {  namespace hiddenapi { +// Should be the same as dalvik.system.VMRuntime.HIDE_MAXTARGETSDK_P_HIDDEN_APIS and +// dalvik.system.VMRuntime.HIDE_MAXTARGETSDK_Q_HIDDEN_APIS. +// Corresponds to bug ids. +static constexpr uint64_t kHideMaxtargetsdkPHiddenApis = 149997251; +static constexpr uint64_t kHideMaxtargetsdkQHiddenApis = 149994052; +  // Set to true if we should always print a warning in logcat for all hidden API accesses, not just  // dark grey and black. This can be set to true for developer preview / beta builds, but should be  // false for public release builds. @@ -42,6 +48,14 @@ namespace hiddenapi {  // list.  static constexpr bool kLogAllAccesses = false; +// Exemptions for logcat warning. Following signatures do not produce a warning as app developers +// should not be alerted on the usage of these greylised APIs. See b/154851649. +static const std::vector<std::string> kWarningExemptions = { +    "Ljava/nio/Buffer;", +    "Llibcore/io/Memory;", +    "Lsun/misc/Unsafe;", +}; +  static inline std::ostream& operator<<(std::ostream& os, AccessMethod value) {    switch (value) {      case AccessMethod::kNone: @@ -76,10 +90,10 @@ static inline std::ostream& operator<<(std::ostream& os, const AccessContext& va  static Domain DetermineDomainFromLocation(const std::string& dex_location,                                            ObjPtr<mirror::ClassLoader> class_loader) {    // If running with APEX, check `path` against known APEX locations. -  // These checks will be skipped on target buildbots where ANDROID_RUNTIME_ROOT +  // These checks will be skipped on target buildbots where ANDROID_ART_ROOT    // is set to "/system". -  if (RuntimeModuleRootDistinctFromAndroidRoot()) { -    if (LocationIsOnRuntimeModule(dex_location.c_str()) || +  if (ArtModuleRootDistinctFromAndroidRoot()) { +    if (LocationIsOnArtModule(dex_location.c_str()) ||          LocationIsOnConscryptModule(dex_location.c_str())) {        return Domain::kCorePlatform;      } @@ -112,6 +126,28 @@ void InitializeDexFileDomain(const DexFile& dex_file, ObjPtr<mirror::ClassLoader    }  } +void InitializeCorePlatformApiPrivateFields() { +  // The following fields in WellKnownClasses correspond to private fields in the Core Platform +  // API that cannot be otherwise expressed and propagated through tooling (b/144502743). +  jfieldID private_core_platform_api_fields[] = { +    WellKnownClasses::java_io_FileDescriptor_descriptor, +    WellKnownClasses::java_io_FileDescriptor_ownerId, +    WellKnownClasses::java_nio_Buffer_address, +    WellKnownClasses::java_nio_Buffer_elementSizeShift, +    WellKnownClasses::java_nio_Buffer_limit, +    WellKnownClasses::java_nio_Buffer_position, +  }; + +  ScopedObjectAccess soa(Thread::Current()); +  for (const auto private_core_platform_api_field : private_core_platform_api_fields) { +    ArtField* field = jni::DecodeArtField(private_core_platform_api_field); +    const uint32_t access_flags = field->GetAccessFlags(); +    uint32_t new_access_flags = access_flags | kAccCorePlatformApi; +    DCHECK(new_access_flags != access_flags); +    field->SetAccessFlags(new_access_flags); +  } +} +  namespace detail {  // Do not change the values of items in this enum, as they are written to the @@ -181,7 +217,7 @@ bool MemberSignature::DoesPrefixMatch(const std::string& prefix) const {    return pos == prefix.length();  } -bool MemberSignature::IsExempted(const std::vector<std::string>& exemptions) { +bool MemberSignature::DoesPrefixMatchAny(const std::vector<std::string>& exemptions) {    for (const std::string& exemption : exemptions) {      if (DoesPrefixMatch(exemption)) {        return true; @@ -435,19 +471,14 @@ bool ShouldDenyAccessToMemberImpl(T* member, ApiList api_list, AccessMethod acce    DCHECK(member != nullptr);    Runtime* runtime = Runtime::Current(); -  EnforcementPolicy policy = runtime->GetHiddenApiEnforcementPolicy(); -  DCHECK(policy != EnforcementPolicy::kDisabled) +  EnforcementPolicy hiddenApiPolicy = runtime->GetHiddenApiEnforcementPolicy(); +  DCHECK(hiddenApiPolicy != EnforcementPolicy::kDisabled)        << "Should never enter this function when access checks are completely disabled"; -  const bool deny_access = -      (policy == EnforcementPolicy::kEnabled) && -      IsSdkVersionSetAndMoreThan(runtime->GetTargetSdkVersion(), -                                 api_list.GetMaxAllowedSdkVersion()); -    MemberSignature member_signature(member);    // Check for an exemption first. Exempted APIs are treated as white list. -  if (member_signature.IsExempted(runtime->GetHiddenApiExemptions())) { +  if (member_signature.DoesPrefixMatchAny(runtime->GetHiddenApiExemptions())) {      // Avoid re-examining the exemption list next time.      // Note this results in no warning for the member, which seems like what one would expect.      // Exemptions effectively adds new members to the whitelist. @@ -455,15 +486,39 @@ bool ShouldDenyAccessToMemberImpl(T* member, ApiList api_list, AccessMethod acce      return false;    } -  if (access_method != AccessMethod::kNone) { -    // 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); +  EnforcementPolicy testApiPolicy = runtime->GetTestApiEnforcementPolicy(); + +  bool deny_access = false; +  if (hiddenApiPolicy == EnforcementPolicy::kEnabled) { +    if (testApiPolicy == EnforcementPolicy::kDisabled && api_list.IsTestApi()) { +      deny_access = false; +    } else { +      switch (api_list.GetMaxAllowedSdkVersion()) { +        case SdkVersion::kP: +          deny_access = runtime->isChangeEnabled(kHideMaxtargetsdkPHiddenApis); +          break; +        case SdkVersion::kQ: +          deny_access = runtime->isChangeEnabled(kHideMaxtargetsdkQHiddenApis); +          break; +        default: +          deny_access = IsSdkVersionSetAndMoreThan(runtime->GetTargetSdkVersion(), +                                                         api_list.GetMaxAllowedSdkVersion()); +      }      } +  } -    // If there is a StrictMode listener, notify it about this violation. -    member_signature.NotifyHiddenApiListener(access_method); +  if (access_method != AccessMethod::kNone) { +    // Warn if non-greylisted signature is being accessed or it is not exempted. +    if (deny_access || !member_signature.DoesPrefixMatchAny(kWarningExemptions)) { +      // 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); +      } + +      // If there is a StrictMode listener, notify it about this violation. +      member_signature.NotifyHiddenApiListener(access_method); +    }      // If event log sampling is enabled, report this violation.      if (kIsTargetBuild && !kIsTargetLinux) {  |