Android10 hiddenapi 相关代码


art/runtime/native/java_lang_Class.cc
static jobject Class_getDeclaredMethodInternal(JNIEnv* env, jobject javaThis,
                                               jstring name, jobjectArray args) {
  ScopedFastNativeObjectAccess soa(env);
  StackHandleScope<1> hs(soa.Self());
  DCHECK_EQ(Runtime::Current()->GetClassLinker()->GetImagePointerSize(), kRuntimePointerSize);
  DCHECK(!Runtime::Current()->IsActiveTransaction());
  Handle<mirror::Method> result = hs.NewHandle(
      mirror::Class::GetDeclaredMethodInternal<kRuntimePointerSize, false>(
          soa.Self(),
          DecodeClass(soa, javaThis),
          soa.Decode<mirror::String>(name),
          soa.Decode<mirror::ObjectArray<mirror::Class>>(args),
          GetHiddenapiAccessContextFunction(soa.Self())));
  if (result == nullptr || ShouldDenyAccessToMember(result->GetArtMethod(), soa.Self())) {
    return nullptr;
  }
  return soa.AddLocalReference<jobject>(result.Get());
}



xref: /art/libdexfile/dex/hidden_api_access_flags.h
16  
17  #ifndef ART_LIBDEXFILE_DEX_HIDDEN_API_ACCESS_FLAGS_H_
18  #define ART_LIBDEXFILE_DEX_HIDDEN_API_ACCESS_FLAGS_H_
19  
20  #include "base/bit_utils.h"
21  #include "base/macros.h"
22  #include "dex/modifiers.h"
23  
24  namespace art {
25  
26  /* This class is used for encoding and decoding access flags of class members
27   * from the boot class path. These access flags might contain additional two bits
28   * of information on whether the given class member should be hidden from apps
29   * and under what circumstances.
30   *
31   * The encoding is different inside DexFile, where we are concerned with size,
32   * and at runtime where we want to optimize for speed of access. The class
33   * provides helper functions to decode/encode both of them.
34   *
35   * Encoding in DexFile
36   * ===================
37   *
38   * First bit is encoded as inversion of visibility flags (public/private/protected).
39   * At most one can be set for any given class member. If two or three are set,
40   * this is interpreted as the first bit being set and actual visibility flags
41   * being the complement of the encoded flags.
42   *
43   * Second bit is either encoded as bit 5 for fields and non-native methods, where
44   * it carries no other meaning. If a method is native (bit 8 set), bit 9 is used.
45   *
46   * Bits were selected so that they never increase the length of unsigned LEB-128
47   * encoding of the access flags.
48   *
49   * Encoding at runtime
50   * ===================
51   *
52   * Two bits are set aside in the uint32_t access flags in the intrinsics ordinal
53   * space (thus intrinsics need to be special-cased). These are two consecutive
54   * bits and they are directly used to store the integer value of the ApiList
55   * enum values.
56   *
57   */
58  class HiddenApiAccessFlags {
59   public:
60    enum ApiList {
61      kWhitelist = 0,
62      kLightGreylist,
63      kDarkGreylist,
64      kBlacklist,
65    };
66  
67    static ALWAYS_INLINE ApiList DecodeFromDex(uint32_t dex_access_flags) {
68      DexHiddenAccessFlags flags(dex_access_flags);
69      uint32_t int_value = (flags.IsFirstBitSet() ? 1 : 0) + (flags.IsSecondBitSet() ? 2 : 0);
70      return static_cast<ApiList>(int_value);
71    }
72  
73    static ALWAYS_INLINE uint32_t RemoveFromDex(uint32_t dex_access_flags) {
74      DexHiddenAccessFlags flags(dex_access_flags);
75      flags.SetFirstBit(false);
76      flags.SetSecondBit(false);
77      return flags.GetEncoding();
78    }
79  
80    static ALWAYS_INLINE uint32_t EncodeForDex(uint32_t dex_access_flags, ApiList value) {
81      DexHiddenAccessFlags flags(RemoveFromDex(dex_access_flags));
82      uint32_t int_value = static_cast<uint32_t>(value);
83      flags.SetFirstBit((int_value & 1) != 0);
84      flags.SetSecondBit((int_value & 2) != 0);
85      return flags.GetEncoding();
86    }
87  
88    static ALWAYS_INLINE ApiList DecodeFromRuntime(uint32_t runtime_access_flags) {
89      // This is used in the fast path, only DCHECK here.
90      DCHECK_EQ(runtime_access_flags & kAccIntrinsic, 0u);
91      uint32_t int_value = (runtime_access_flags & kAccHiddenApiBits) >> kAccFlagsShift;
92      return static_cast<ApiList>(int_value);
93    }
94  
95    static ALWAYS_INLINE uint32_t EncodeForRuntime(uint32_t runtime_access_flags, ApiList value) {
96      CHECK_EQ(runtime_access_flags & kAccIntrinsic, 0u);
97  
98      uint32_t hidden_api_flags = static_cast<uint32_t>(value) << kAccFlagsShift;
99      CHECK_EQ(hidden_api_flags & ~kAccHiddenApiBits, 0u);
100  
101      runtime_access_flags &= ~kAccHiddenApiBits;
102      return runtime_access_flags | hidden_api_flags;
103    }
104  
105   private:
106    static const int kAccFlagsShift = CTZ(kAccHiddenApiBits);
107    static_assert(IsPowerOfTwo((kAccHiddenApiBits >> kAccFlagsShift) + 1),
108                  "kAccHiddenApiBits are not continuous");
109  
110    struct DexHiddenAccessFlags {
111      explicit DexHiddenAccessFlags(uint32_t access_flags) : access_flags_(access_flags) {}
112  
113      ALWAYS_INLINE uint32_t GetSecondFlag() {
114        return ((access_flags_ & kAccNative) != 0) ? kAccDexHiddenBitNative : kAccDexHiddenBit;
115      }
116  
117      ALWAYS_INLINE bool IsFirstBitSet() {
118        static_assert(IsPowerOfTwo(0u), "Following statement checks if *at most* one bit is set");
119        return !IsPowerOfTwo(access_flags_ & kAccVisibilityFlags);
120      }
121  
122      ALWAYS_INLINE void SetFirstBit(bool value) {
123        if (IsFirstBitSet() != value) {
124          access_flags_ ^= kAccVisibilityFlags;
125        }
126      }
127  
128      ALWAYS_INLINE bool IsSecondBitSet() {
129        return (access_flags_ & GetSecondFlag()) != 0;
130      }
131  
132      ALWAYS_INLINE void SetSecondBit(bool value) {
133        if (value) {
134          access_flags_ |= GetSecondFlag();
135        } else {
136          access_flags_ &= ~GetSecondFlag();
137        }
138      }
139  
140      ALWAYS_INLINE uint32_t GetEncoding() const {
141        return access_flags_;
142      }
143  
144      uint32_t access_flags_;
145    };
146  };
147  
148  inline std::ostream& operator<<(std::ostream& os, HiddenApiAccessFlags::ApiList value) {
149    switch (value) {
150      case HiddenApiAccessFlags::kWhitelist:
151        os << "whitelist";
152        break;
153      case HiddenApiAccessFlags::kLightGreylist:
154        os << "light greylist";
155        break;
156      case HiddenApiAccessFlags::kDarkGreylist:
157        os << "dark greylist";
158        break;
159      case HiddenApiAccessFlags::kBlacklist:
160        os << "blacklist";
161        break;
162    }
163    return os;
164  }
165  
166  }  // namespace art
167  
168  
169  #endif  // ART_LIBDEXFILE_DEX_HIDDEN_API_ACCESS_FLAGS_H_
170  




art/runtime/hidden_api.h
template<typename T>
inline bool ShouldDenyAccessToMember(T* member,
                                     const std::function<AccessContext()>& fn_get_access_context,
                                     AccessMethod access_method)
    REQUIRES_SHARED(Locks::mutator_lock_) {
  DCHECK(member != nullptr);

  // Get the runtime flags encoded in member's access flags.
  // Note: this works for proxy methods because they inherit access flags from their
  // respective interface methods.
  const uint32_t runtime_flags = GetRuntimeFlags(member);

  // Exit early if member is public API. This flag is also set for non-boot class
  // path fields/methods.
  if ((runtime_flags & kAccPublicApi) != 0) {
    return false;
  }

  // Determine which domain the caller and callee belong to.
  // This can be *very* expensive. This is why ShouldDenyAccessToMember
  // should not be called on every individual access.
  const AccessContext caller_context = fn_get_access_context();
  const AccessContext callee_context(member->GetDeclaringClass());

  // Non-boot classpath callers should have exited early.
  DCHECK(!callee_context.IsApplicationDomain());

  // Check if the caller is always allowed to access members in the callee context.
  if (caller_context.CanAlwaysAccess(callee_context)) {
    return false;
  }

  // Check if this is platform accessing core platform. We may warn if `member` is
  // not part of core platform API.
  switch (caller_context.GetDomain()) {
    case Domain::kApplication: {
      DCHECK(!callee_context.IsApplicationDomain());

      // Exit early if access checks are completely disabled.
      EnforcementPolicy policy = Runtime::Current()->GetHiddenApiEnforcementPolicy();
      if (policy == EnforcementPolicy::kDisabled) {
        return false;
      }

      // If this is a proxy method, look at the interface method instead.
      member = detail::GetInterfaceMemberIfProxy(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));
      DCHECK(api_list.IsValid());

      // Member is hidden and caller is not exempted. Enter slow path.
      return detail::ShouldDenyAccessToMemberImpl(member, api_list, access_method);
    }

    case Domain::kPlatform: {
      DCHECK(callee_context.GetDomain() == Domain::kCorePlatform);

      // Member is part of core platform API. Accessing it is allowed.
      if ((runtime_flags & kAccCorePlatformApi) != 0) {
        return false;
      }

      // Allow access if access checks are disabled.
      EnforcementPolicy policy = Runtime::Current()->GetCorePlatformApiEnforcementPolicy();
      if (policy == EnforcementPolicy::kDisabled) {
        return false;
      }

      // If this is a proxy method, look at the interface method instead.
      member = detail::GetInterfaceMemberIfProxy(member);

      // Access checks are not disabled, report the violation.
      // This may also add kAccCorePlatformApi to the access flags of `member`
      // so as to not warn again on next access.
      return detail::HandleCorePlatformApiViolation(member,
                                                    caller_context,
                                                    access_method,
                                                    policy);
    }

    case Domain::kCorePlatform: {
      LOG(FATAL) << "CorePlatform domain should be allowed to access all domains";
      UNREACHABLE();
    }
  }
}


/art/runtime/hidden_api.cc
template<typename T>
bool ShouldDenyAccessToMemberImpl(T* member, ApiList api_list, AccessMethod access_method) {
  DCHECK(member != nullptr);
  Runtime* runtime = Runtime::Current();

  EnforcementPolicy policy = runtime->GetHiddenApiEnforcementPolicy();
  DCHECK(policy != 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())) {
    // 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.
    MaybeUpdateAccessFlags(runtime, member, kAccPublicApi);
    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);
    }

    // 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) {
      uint32_t eventLogSampleRate = runtime->GetHiddenApiEventLogSampleRate();
      // Assert that RAND_MAX is big enough, to ensure sampling below works as expected.
      static_assert(RAND_MAX >= 0xffff, "RAND_MAX too small");
      if (eventLogSampleRate != 0) {
        const uint32_t sampled_value = static_cast<uint32_t>(std::rand()) & 0xffff;
        if (sampled_value < eventLogSampleRate) {
          member_signature.LogAccessToEventLog(sampled_value, access_method, deny_access);
        }
      }
    }

    // If this access was not denied, move the member into whitelist and skip
    // the warning the next time the member is accessed.
    if (!deny_access) {
      MaybeUpdateAccessFlags(runtime, member, kAccPublicApi);
    }
  }

  return deny_access;
}


78  MemberSignature::MemberSignature(ArtField* field) {
79    class_name_ = field->GetDeclaringClass()->GetDescriptor(&tmp_);
80    member_name_ = field->GetName();
81    type_signature_ = field->GetTypeDescriptor();
82    type_ = kField;
83  }
84  
85  MemberSignature::MemberSignature(ArtMethod* method) {
86    // If this is a proxy method, print the signature of the interface method.
87    method = method->GetInterfaceMethodIfProxy(
88        Runtime::Current()->GetClassLinker()->GetImagePointerSize());
89  
90    class_name_ = method->GetDeclaringClass()->GetDescriptor(&tmp_);
91    member_name_ = method->GetName();
92    type_signature_ = method->GetSignature().ToString();
93    type_ = kMethod;
94  }
95  
96  inline std::vector<const char*> MemberSignature::GetSignatureParts() const {
97    if (type_ == kField) {
98      return { class_name_.c_str(), "->", member_name_.c_str(), ":", type_signature_.c_str() };
99    } else {
100      DCHECK_EQ(type_, kMethod);
101      return { class_name_.c_str(), "->", member_name_.c_str(), type_signature_.c_str() };
102    }
103  }
104  
105  bool MemberSignature::DoesPrefixMatch(const std::string& prefix) const {
106    size_t pos = 0;
107    for (const char* part : GetSignatureParts()) {
108      size_t count = std::min(prefix.length() - pos, strlen(part));
109      if (prefix.compare(pos, count, part, 0, count) == 0) {
110        pos += count;
111      } else {
112        return false;
113      }
114    }
115    // We have a complete match if all parts match (we exit the loop without
116    // returning) AND we've matched the whole prefix.
117    return pos == prefix.length();
118  }

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容