Android10 hiddenapi 相關(guān)代碼


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  }

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末隅俘,一起剝皮案震驚了整個濱河市攻谁,隨后出現(xiàn)的幾起案子畦韭,更是在濱河造成了極大的恐慌断盛,老刑警劉巖罗洗,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異钢猛,居然都是意外死亡栖博,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進(jìn)店門厢洞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人典奉,你說我怎么就攤上這事躺翻。” “怎么了卫玖?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵公你,是天一觀的道長。 經(jīng)常有香客問我假瞬,道長陕靠,這世上最難降的妖魔是什么迂尝? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮剪芥,結(jié)果婚禮上垄开,老公的妹妹穿的比我還像新娘。我一直安慰自己税肪,他們只是感情好溉躲,可當(dāng)我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著益兄,像睡著了一般锻梳。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上净捅,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天疑枯,我揣著相機與錄音,去河邊找鬼蛔六。 笑死荆永,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的古今。 我是一名探鬼主播屁魏,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼捉腥!你這毒婦竟也來了氓拼?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤抵碟,失蹤者是張志新(化名)和其女友劉穎桃漾,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拟逮,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡撬统,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了敦迄。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片恋追。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖罚屋,靈堂內(nèi)的尸體忽然破棺而出苦囱,到底是詐尸還是另有隱情,我是刑警寧澤脾猛,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布撕彤,位于F島的核電站,受9級特大地震影響猛拴,放射性物質(zhì)發(fā)生泄漏羹铅。R本人自食惡果不足惜蚀狰,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望职员。 院中可真熱鬧麻蹋,春花似錦、人聲如沸廉邑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蛛蒙。三九已至糙箍,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間牵祟,已是汗流浹背深夯。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留诺苹,地道東北人咕晋。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像收奔,于是被迫代替她去往敵國和親掌呜。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,834評論 2 345

推薦閱讀更多精彩內(nèi)容