Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Android/art/art/runtime/   (Android Betriebssystem Version 17©)  Datei vom 26.5.2026 mit Größe 19 kB image not shown  

Quelle  hidden_api.h

  Sprache: C
 

/*
 * 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.
 */


#ifndef ART_RUNTIME_HIDDEN_API_H_
#define ART_RUNTIME_HIDDEN_API_H_

#include <ostream>

#include "art_field.h"
#include "art_method.h"
#include "base/hiddenapi_domain.h"
#include "base/hiddenapi_flags.h"
#include "base/locks.h"
#include "base/macros.h"
#include "dex/class_accessor.h"
#include "intrinsics_enum.h"
#include "jni/jni_internal.h"
#include "mirror/class.h"
#include "mirror/class_loader.h"
#include "reflection.h"
#include "runtime.h"

namespace art HIDDEN {
namespace hiddenapi {

// Hidden API enforcement policy
// This must be kept in sync with ApplicationInfo.ApiEnforcementPolicy in
// frameworks/base/core/java/android/content/pm/ApplicationInfo.java
enum class EnforcementPolicy {
  kDisabled             = 0,
  kJustWarn             = 1,  // keep checks enabled, but allow everything (enables logging)
  kEnabled              = 2,  // ban conditionally blocked & blocklist
  kMax = kEnabled,
};

inline EnforcementPolicy EnforcementPolicyFromInt(int api_policy_int) {
  DCHECK_GE(api_policy_int, 0);
  DCHECK_LE(api_policy_int, static_cast<int>(EnforcementPolicy::kMax));
  return static_cast<EnforcementPolicy>(api_policy_int);
}

// Hidden API access method
// This must be kept in sync with VMRuntime.HiddenApiUsageLogger.ACCESS_METHOD_*
// for the access methods that are logged.
enum class AccessMethod {
  // Internal checks that don't log access warnings or failures. They may be
  // used for checks that don't correspond to an actual access by the running
  // app. They may also be used for a check that, if denied, will be followed by
  // zero or more kCheck or kCheckWithPolicy checks and eventually an
  // AccessMethod that is something else. That last check will then log and
  // apply the policy (if it is denied too).
  //
  // kCheck returns whether the access would be allowed by hiddenapi or not,
  // regardless of the current EnforcementPolicy in the runtime.
  // kCheckWithPolicy does apply the policy and hence may only return a denial
  // if it's kEnabled.
  kCheck = 0,
  kCheckWithPolicy = 4,

  // Checks that log access warnings and failures, depending on the current
  // EnforcementPolicy in the runtime.
  kReflection = 1,
  kJNI = 2,
  kLinking = 3,
};

inline bool IsCheckOnlyMethod(AccessMethod access_method) {
  return access_method == AccessMethod::kCheck || access_method == AccessMethod::kCheckWithPolicy;
}

// Represents the API domain of a caller/callee.
class AccessContext {
 public:
  // Initialize to either the fully-trusted or fully-untrusted domain.
  explicit AccessContext(bool is_trusted)
      : klass_(nullptr),
        dex_file_(nullptr),
        native_caller_addr_(nullptr),
        domain_(ComputeDomain(is_trusted)) {}

  // Initialize from class loader and dex file (via dex cache).
  AccessContext(ObjPtr<mirror::ClassLoader> class_loader, ObjPtr<mirror::DexCache> dex_cache)
      REQUIRES_SHARED(Locks::mutator_lock_)
      : klass_(nullptr),
        dex_file_(GetDexFileFromDexCache(dex_cache)),
        native_caller_addr_(nullptr),
        domain_(ComputeDomain(class_loader, dex_file_)) {}

  // Initialize from class loader and dex file (only used by tests).
  AccessContext(ObjPtr<mirror::ClassLoader> class_loader, const DexFile* dex_file)
      : klass_(nullptr),
        dex_file_(dex_file),
        native_caller_addr_(nullptr),
        domain_(ComputeDomain(class_loader, dex_file_)) {}

  // Initialize from Class.
  explicit AccessContext(ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_)
      : klass_(klass),
        dex_file_(GetDexFileFromDexCache(klass->GetDexCache())),
        native_caller_addr_(nullptr),
        domain_(ComputeDomain(klass, dex_file_)) {}

  ObjPtr<mirror::Class> GetClass() const { return klass_; }
  const DexFile* GetDexFile() const { return dex_file_; }
  void* GetNativeCallerAddr() const { return native_caller_addr_; }
  Domain GetDomain() const { return domain_; }
  bool IsApplicationDomain() const { return domain_ == Domain::kApplication; }

  // Returns true if this domain is always allowed to access the domain of `callee`.
  bool CanAlwaysAccess(const AccessContext& callee) const {
    return IsDomainAtLeastAsTrustedAs(domain_, callee.domain_);
  }

  // Returns an AccessContext based on the return address to a native (non-OAT)
  // caller. If the DSO (dynamic shared object) of the caller can't be
  // determined then returns a fully-untrusted context for which
  // GetNativeCallerAddr returns nullptr.
  static AccessContext FromNativeCaller(void* native_caller_addr);

 private:
  explicit AccessContext(ObjPtr<mirror::Class> klass,
                         const DexFile* dex_file,
                         void* native_caller_addr,
                         Domain domain)
      : klass_(klass),
        dex_file_(dex_file),
        native_caller_addr_(native_caller_addr),
        domain_(domain) {}

  static const DexFile* GetDexFileFromDexCache(ObjPtr<mirror::DexCache> dex_cache)
      REQUIRES_SHARED(Locks::mutator_lock_) {
    return dex_cache.IsNull() ? nullptr : dex_cache->GetDexFile();
  }

  static Domain ComputeDomain(bool is_trusted) {
    return is_trusted ? Domain::kCorePlatform : Domain::kApplication;
  }

  static Domain ComputeDomain(ObjPtr<mirror::ClassLoader> class_loader, const DexFile* dex_file) {
    if (dex_file == nullptr) {
      return ComputeDomain(/* is_trusted= */ class_loader.IsNull());
    }

    return dex_file->GetHiddenapiDomain();
  }

  static Domain ComputeDomain(ObjPtr<mirror::Class> klass, const DexFile* dex_file)
      REQUIRES_SHARED(Locks::mutator_lock_) {
    // Check other aspects of the context.
    Domain domain = ComputeDomain(klass->GetClassLoader(), dex_file);

    if (domain == Domain::kApplication &&
        klass->ShouldSkipHiddenApiChecks() &&
        Runtime::Current()->IsJavaDebuggableAtInit()) {
      // Class is known, it is marked trusted and we are in debuggable mode.
      domain = ComputeDomain(/* is_trusted= */ true);
    }

    return domain;
  }

  // Pointer to declaring class of the caller/callee (null if not provided).
  // This is not safe across GC but we're only using this class for passing
  // information about the caller to the access check logic and never retain
  // the AccessContext instance beyond that.
  const ObjPtr<mirror::Class> klass_;

  // DexFile of the caller/callee (null if not provided).
  const DexFile* const dex_file_;

  // The return address for a native (non-OAT) caller.
  void* native_caller_addr_;

  // Computed domain of the caller/callee.
  const Domain domain_;
};

std::ostream& operator<<(std::ostream&, EnforcementPolicy);
std::ostream& operator<<(std::ostream&, AccessMethod);
std::ostream& operator<<(std::ostream&, Domain);
std::ostream& operator<<(std::ostream&, const AccessContext&);

class ScopedHiddenApiEnforcementPolicySetting {
 public:
  explicit ScopedHiddenApiEnforcementPolicySetting(EnforcementPolicy new_policy)
      : initial_policy_(Runtime::Current()->GetHiddenApiEnforcementPolicy()) {
    Runtime::Current()->SetHiddenApiEnforcementPolicy(new_policy);
  }

  ~ScopedHiddenApiEnforcementPolicySetting() {
    Runtime::Current()->SetHiddenApiEnforcementPolicy(initial_policy_);
  }

 private:
  const EnforcementPolicy initial_policy_;
  DISALLOW_COPY_AND_ASSIGN(ScopedHiddenApiEnforcementPolicySetting);
};

void InitializeCorePlatformApiPrivateFields() REQUIRES(!Locks::mutator_lock_);

// TODO(b/377676642): Replace this with an inline android_get_device_api_level()
// >= 37 check once the flag is fully ramped.
bool EnableHiddenapiPlatformEnforcement();

template <typename T>
bool ShouldDenyJniAccessToMember(T* member,
                                 Thread* self,
                                 AccessMethod access_kind,
                                 void* native_caller_addr) REQUIRES_SHARED(Locks::mutator_lock_);

// Walks the stack, finds the caller of this reflective call and returns
// a hiddenapi AccessContext formed from its declaring class.
AccessContext GetReflectionCallerAccessContext(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_);

// Implementation details. DO NOT ACCESS DIRECTLY.
namespace detail {

// Class to encapsulate the signature of a member (ArtField or ArtMethod). This
// is used as a helper when matching prefixes, and when logging the signature.
class MemberSignature {
 private:
  enum MemberType {
    kField,
    kMethod,
  };

  std::string class_name_;
  std::string member_name_;
  std::string type_signature_;
  std::string tmp_;
  MemberType type_;

  inline std::vector<const char*> GetSignatureParts() const;

 public:
  explicit MemberSignature(ArtField* field) REQUIRES_SHARED(Locks::mutator_lock_);
  explicit MemberSignature(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_);
  explicit MemberSignature(const ClassAccessor::Field& field);
  explicit MemberSignature(const ClassAccessor::Method& method);

  void Dump(std::ostream& os) const;

  bool Equals(const MemberSignature& other);
  bool MemberNameAndTypeMatch(const MemberSignature& other);

  // Performs prefix match on this member. Since the full member signature is
  // composed of several parts, we match each part in turn (rather than
  // building the entire thing in memory and performing a simple prefix match)
  bool DoesPrefixMatch(const std::string& prefix) const;

  bool DoesPrefixMatchAny(const std::vector<std::string>& exemptions);

  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);

  // Calls back into managed code to notify VMRuntime.nonSdkApiUsageConsumer that
  // |member| was accessed. This is usually called when an API is unsupported,
  // conditionally or unconditionally blocked. Given that the callback can execute arbitrary
  // code, a call to this method can result in thread suspension.
  void NotifyHiddenApiListener(AccessMethod access_method);
};

// Locates hiddenapi flags for `member` in the corresponding dex file.
// NB: This is an O(N) operation, linear with the number of members in the class def.
template<typename T>
uint32_t GetDexFlags(T* member) REQUIRES_SHARED(Locks::mutator_lock_);

// Handler of detected core platform API violations. Returns true if access to
// `member` should be denied.
template <typename T>
bool HandleCorePlatformApiViolation(T* member,
                                    ApiList api_list,
                                    uint32_t runtime_flags,
                                    const AccessContext& caller_context,
                                    const AccessContext& callee_context,
                                    AccessMethod access_method,
                                    EnforcementPolicy policy) REQUIRES_SHARED(Locks::mutator_lock_);

template <typename T>
bool ShouldDenyAccessToMemberImpl(T* member,
                                  ApiList api_list,
                                  uint32_t runtime_flags,
                                  const AccessContext& caller_context,
                                  const AccessContext& callee_context,
                                  AccessMethod access_method) REQUIRES_SHARED(Locks::mutator_lock_);

inline ArtField* GetInterfaceMemberIfProxy(ArtField* field) { return field; }

inline ArtMethod* GetInterfaceMemberIfProxy(ArtMethod* method)
    REQUIRES_SHARED(Locks::mutator_lock_) {
  return method->GetInterfaceMethodIfProxy(kRuntimePointerSize);
}

// Returns access flags for the runtime representation of a class member (ArtField/ArtMember).
ALWAYS_INLINE inline uint32_t CreateRuntimeFlags_Impl(uint32_t dex_flags) {
  uint32_t runtime_flags = 0u;

  ApiList api_list = ApiList::FromDexFlags(dex_flags);
  DCHECK(api_list.IsValid());

  if (api_list.Contains(ApiList::Sdk())) {
    runtime_flags |= kAccPublicApi;
  } else {
    // Only add domain-specific flags for non-public API members.
    // This simplifies hardcoded values for intrinsics.
    if (api_list.Contains(ApiList::CorePlatformApi())) {
      runtime_flags |= kAccCorePlatformApi;
    }
  }

  DCHECK_EQ(runtime_flags & kAccHiddenapiBits, runtime_flags)
      << "Runtime flags not in reserved access flags bits";
  return runtime_flags;
}

}  // namespace detail

// Returns access flags for the runtime representation of a class member (ArtField/ArtMember).
ALWAYS_INLINE inline uint32_t CreateRuntimeFlags(const ClassAccessor::BaseItem& member) {
  return detail::CreateRuntimeFlags_Impl(member.GetHiddenapiFlags());
}

// Returns access flags for the runtime representation of a class member (ArtField/ArtMember).
template<typename T>
ALWAYS_INLINE inline uint32_t CreateRuntimeFlags(T* member) REQUIRES_SHARED(Locks::mutator_lock_) {
  return detail::CreateRuntimeFlags_Impl(detail::GetDexFlags(member));
}

// Extracts hiddenapi runtime flags from access flags of ArtField.
ALWAYS_INLINE inline uint32_t GetRuntimeFlags(ArtField* field)
    REQUIRES_SHARED(Locks::mutator_lock_) {
  return field->GetAccessFlags() & kAccHiddenapiBits;
}

// Extracts hiddenapi runtime flags from access flags of ArtMethod.
// Uses hardcoded values for intrinsics.
ALWAYS_INLINE inline uint32_t GetRuntimeFlags(ArtMethod* method)
    REQUIRES_SHARED(Locks::mutator_lock_) {
  if (UNLIKELY(method->IsIntrinsic())) {
    switch (method->GetIntrinsic()) {
      case Intrinsics::kSystemArrayCopyChar:
      case Intrinsics::kSystemArrayCopyByte:
      case Intrinsics::kSystemArrayCopyInt:
      case Intrinsics::kStringGetCharsNoCheck:
      case Intrinsics::kReferenceGetReferent:
      case Intrinsics::kMemoryPeekByte:
      case Intrinsics::kMemoryPokeByte:
      case Intrinsics::kCRC32Update:
      case Intrinsics::kCRC32UpdateBytes:
      case Intrinsics::kCRC32UpdateByteBuffer:
      case Intrinsics::kStringNewStringFromBytes:
      case Intrinsics::kStringNewStringFromChars:
      case Intrinsics::kStringNewStringFromString:
      case Intrinsics::kMemoryPeekIntNative:
      case Intrinsics::kMemoryPeekLongNative:
      case Intrinsics::kMemoryPeekShortNative:
      case Intrinsics::kMemoryPokeIntNative:
      case Intrinsics::kMemoryPokeLongNative:
      case Intrinsics::kMemoryPokeShortNative:
      case Intrinsics::kUnsafeCASInt:
      case Intrinsics::kUnsafeCASLong:
      case Intrinsics::kUnsafeCASObject:
      case Intrinsics::kUnsafeGetAndAddInt:
      case Intrinsics::kUnsafeGetAndAddLong:
      case Intrinsics::kUnsafeGetAndSetInt:
      case Intrinsics::kUnsafeGetAndSetLong:
      case Intrinsics::kUnsafeGetAndSetObject:
      case Intrinsics::kUnsafeGetLongVolatile:
      case Intrinsics::kUnsafeGetObjectVolatile:
      case Intrinsics::kUnsafeGetVolatile:
      case Intrinsics::kUnsafePutLongOrdered:
      case Intrinsics::kUnsafePutLongVolatile:
      case Intrinsics::kUnsafePutObjectVolatile:
      case Intrinsics::kUnsafePutOrderedInt:
      case Intrinsics::kUnsafePutOrderedObject:
      case Intrinsics::kUnsafePutVolatile:
      case Intrinsics::kUnsafeLoadFence:
      case Intrinsics::kUnsafeStoreFence:
      case Intrinsics::kUnsafeFullFence:
      case Intrinsics::kJdkUnsafeArrayBaseOffset:
      case Intrinsics::kJdkUnsafeCompareAndSetInt:
      case Intrinsics::kJdkUnsafeCompareAndSetLong:
      case Intrinsics::kJdkUnsafeCompareAndSetReference:
      case Intrinsics::kJdkUnsafeGetAndAddInt:
      case Intrinsics::kJdkUnsafeGetAndAddLong:
      case Intrinsics::kJdkUnsafeGetAndSetInt:
      case Intrinsics::kJdkUnsafeGetAndSetLong:
      case Intrinsics::kJdkUnsafeGetAndSetReference:
      case Intrinsics::kJdkUnsafeGetLongVolatile:
      case Intrinsics::kJdkUnsafeGetLongAcquire:
      case Intrinsics::kJdkUnsafeGetReferenceVolatile:
      case Intrinsics::kJdkUnsafeGetReferenceAcquire:
      case Intrinsics::kJdkUnsafeGetVolatile:
      case Intrinsics::kJdkUnsafeGetAcquire:
      case Intrinsics::kJdkUnsafePutLongVolatile:
      case Intrinsics::kJdkUnsafePutLongRelease:
      case Intrinsics::kJdkUnsafePutReferenceVolatile:
      case Intrinsics::kJdkUnsafePutReferenceRelease:
      case Intrinsics::kJdkUnsafePutVolatile:
      case Intrinsics::kJdkUnsafePutRelease:
      case Intrinsics::kJdkUnsafeLoadFence:
      case Intrinsics::kJdkUnsafeStoreFence:
      case Intrinsics::kJdkUnsafeFullFence:
      case Intrinsics::kJdkUnsafeGet:
      case Intrinsics::kJdkUnsafeGetAbsolute:
      case Intrinsics::kJdkUnsafeGetLong:
      case Intrinsics::kJdkUnsafeGetByte:
      case Intrinsics::kJdkUnsafeGetReference:
      case Intrinsics::kJdkUnsafePutLong:
      case Intrinsics::kJdkUnsafePut:
      case Intrinsics::kJdkUnsafePutAbsolute:
      case Intrinsics::kJdkUnsafePutReference:
      case Intrinsics::kJdkUnsafePutByte:
        return 0u;
      case Intrinsics::kFP16Ceil:
      case Intrinsics::kFP16Compare:
      case Intrinsics::kFP16Floor:
      case Intrinsics::kFP16Greater:
      case Intrinsics::kFP16GreaterEquals:
      case Intrinsics::kFP16Less:
      case Intrinsics::kFP16LessEquals:
      case Intrinsics::kFP16Min:
      case Intrinsics::kFP16Max:
      case Intrinsics::kFP16ToFloat:
      case Intrinsics::kFP16ToHalf:
      case Intrinsics::kFP16Rint:
      case Intrinsics::kUnsafeArrayBaseOffset:
      case Intrinsics::kUnsafeGet:
      case Intrinsics::kUnsafeGetAbsolute:
      case Intrinsics::kUnsafeGetLong:
      case Intrinsics::kUnsafeGetByte:
      case Intrinsics::kUnsafeGetObject:
      case Intrinsics::kUnsafePutLong:
      case Intrinsics::kUnsafePut:
      case Intrinsics::kUnsafePutAbsolute:
      case Intrinsics::kUnsafePutObject:
      case Intrinsics::kUnsafePutByte:
        return kAccCorePlatformApi;
      default:
        // Remaining intrinsics are public API. We DCHECK that in SetIntrinsic().
        return kAccPublicApi;
    }
  } else {
    return method->GetAccessFlags() & kAccHiddenapiBits;
  }
}

// Called by class linker when a new dex file has been registered. Assigns
// the AccessContext domain to the newly-registered dex file based on its
// location and class loader.
void InitializeDexFileDomain(const DexFile& dex_file, ObjPtr<mirror::ClassLoader> class_loader);

// Returns true if access to `member` should be denied in the given context.
// The decision is based on whether the caller is in a trusted context or not.
// Because determining the access context can be expensive, a lambda function
// "fn_get_access_context" is lazily invoked after other criteria have been
// considered.
// This function might print warnings into the log if the member is hidden.
template<typename T>
bool ShouldDenyAccessToMember(T* member,
                              const std::function<AccessContext()>& fn_get_access_context,
                              AccessMethod access_method)
    REQUIRES_SHARED(Locks::mutator_lock_);

// Helper method for callers where access context can be determined beforehand.
// Wraps AccessContext in a lambda and passes it to the real ShouldDenyAccessToMember.
template<typename T>
inline bool ShouldDenyAccessToMember(T* member,
                                     const AccessContext& access_context,
                                     AccessMethod access_method)
    REQUIRES_SHARED(Locks::mutator_lock_) {
  access_context.GetClass().AssertValid();
  return ShouldDenyAccessToMember(member, [&]() { return access_context; }, access_method);
}

}  // namespace hiddenapi
}  // namespace art

#endif  // ART_RUNTIME_HIDDEN_API_H_

Messung V0.5 in Prozent
C=90 H=94 G=91

¤ Dauer der Verarbeitung: 0.14 Sekunden  (vorverarbeitet am  2026-06-29) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.