blob: 05e68e66dd4db8a0f3fdec90112c12b5c33a71ac [file] [log] [blame]
David Brazdil5a61bb72018-01-19 16:59:46 +00001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef ART_RUNTIME_HIDDEN_API_H_
18#define ART_RUNTIME_HIDDEN_API_H_
19
20#include "hidden_api_access_flags.h"
21#include "reflection.h"
22#include "runtime.h"
23
24namespace art {
25namespace hiddenapi {
26
David Brazdila02cb112018-01-31 11:36:39 +000027enum Action {
28 kAllow,
29 kAllowButWarn,
David Brazdil92265222018-02-02 11:21:40 +000030 kAllowButWarnAndToast,
David Brazdila02cb112018-01-31 11:36:39 +000031 kDeny
32};
David Brazdil5a61bb72018-01-19 16:59:46 +000033
David Brazdila02cb112018-01-31 11:36:39 +000034inline Action GetMemberAction(uint32_t access_flags) {
David Brazdil5a61bb72018-01-19 16:59:46 +000035 switch (HiddenApiAccessFlags::DecodeFromRuntime(access_flags)) {
36 case HiddenApiAccessFlags::kWhitelist:
David Brazdila02cb112018-01-31 11:36:39 +000037 return kAllow;
David Brazdil5a61bb72018-01-19 16:59:46 +000038 case HiddenApiAccessFlags::kLightGreylist:
David Brazdila02cb112018-01-31 11:36:39 +000039 return kAllowButWarn;
David Brazdil92265222018-02-02 11:21:40 +000040 case HiddenApiAccessFlags::kDarkGreylist:
41 return kAllowButWarnAndToast;
David Brazdil5a61bb72018-01-19 16:59:46 +000042 case HiddenApiAccessFlags::kBlacklist:
David Brazdila02cb112018-01-31 11:36:39 +000043 return kDeny;
David Brazdil5a61bb72018-01-19 16:59:46 +000044 }
45}
46
David Brazdilee7d2fd2018-01-20 17:25:23 +000047// Issue a warning about field access.
48inline void WarnAboutMemberAccess(ArtField* field) REQUIRES_SHARED(Locks::mutator_lock_) {
David Brazdil1077bbc2018-01-31 14:33:08 +000049 std::string tmp;
50 LOG(WARNING) << "Accessing hidden field "
51 << field->GetDeclaringClass()->GetDescriptor(&tmp) << "->"
52 << field->GetName() << ":" << field->GetTypeDescriptor();
David Brazdilee7d2fd2018-01-20 17:25:23 +000053}
54
55// Issue a warning about method access.
56inline void WarnAboutMemberAccess(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) {
David Brazdil1077bbc2018-01-31 14:33:08 +000057 std::string tmp;
58 LOG(WARNING) << "Accessing hidden method "
59 << method->GetDeclaringClass()->GetDescriptor(&tmp) << "->"
60 << method->GetName() << method->GetSignature().ToString();
David Brazdilee7d2fd2018-01-20 17:25:23 +000061}
62
David Brazdila02cb112018-01-31 11:36:39 +000063// Returns true if access to `member` should be denied to the caller of the
64// reflective query. The decision is based on whether the caller is in boot
65// class path or not. Because different users of this function determine this
66// in a different way, `fn_caller_in_boot(self)` is called and should return
67// true if the caller is in boot class path.
68// This function might print warnings into the log if the member is greylisted.
David Brazdilee7d2fd2018-01-20 17:25:23 +000069template<typename T>
David Brazdila02cb112018-01-31 11:36:39 +000070inline bool ShouldBlockAccessToMember(T* member,
71 Thread* self,
72 std::function<bool(Thread*)> fn_caller_in_boot)
David Brazdilee7d2fd2018-01-20 17:25:23 +000073 REQUIRES_SHARED(Locks::mutator_lock_) {
74 DCHECK(member != nullptr);
David Brazdil92265222018-02-02 11:21:40 +000075 Runtime* runtime = Runtime::Current();
David Brazdila02cb112018-01-31 11:36:39 +000076
David Brazdil92265222018-02-02 11:21:40 +000077 if (!runtime->AreHiddenApiChecksEnabled()) {
David Brazdila02cb112018-01-31 11:36:39 +000078 // Exit early. Nothing to enforce.
79 return false;
David Brazdilee7d2fd2018-01-20 17:25:23 +000080 }
81
David Brazdila02cb112018-01-31 11:36:39 +000082 Action action = GetMemberAction(member->GetAccessFlags());
83 if (action == kAllow) {
84 // Nothing to do.
85 return false;
86 }
87
88 // Member is hidden. Walk the stack to find the caller.
89 // This can be *very* expensive. Save it for last.
90 if (fn_caller_in_boot(self)) {
91 // Caller in boot class path. Exit.
92 return false;
93 }
94
95 // Member is hidden and we are not in the boot class path. Act accordingly.
David Brazdil92265222018-02-02 11:21:40 +000096 if (action == kDeny) {
97 return true;
98 } else {
99 DCHECK(action == kAllowButWarn || action == kAllowButWarnAndToast);
100
David Brazdila02cb112018-01-31 11:36:39 +0000101 // Allow access to this member but print a warning. Depending on a runtime
102 // flag, we might move the member into whitelist and skip the warning the
103 // next time the member is used.
David Brazdil92265222018-02-02 11:21:40 +0000104 if (runtime->ShouldDedupeHiddenApiWarnings()) {
David Brazdila02cb112018-01-31 11:36:39 +0000105 member->SetAccessFlags(HiddenApiAccessFlags::EncodeForRuntime(
106 member->GetAccessFlags(), HiddenApiAccessFlags::kWhitelist));
107 }
108 WarnAboutMemberAccess(member);
David Brazdil92265222018-02-02 11:21:40 +0000109 if (action == kAllowButWarnAndToast || runtime->ShouldAlwaysSetHiddenApiWarningFlag()) {
110 Runtime::Current()->SetPendingHiddenApiWarning(true);
111 }
David Brazdila02cb112018-01-31 11:36:39 +0000112 return false;
David Brazdila02cb112018-01-31 11:36:39 +0000113 }
David Brazdilee7d2fd2018-01-20 17:25:23 +0000114}
115
David Brazdila02cb112018-01-31 11:36:39 +0000116// Returns true if access to member with `access_flags` should be denied to `caller`.
117// This function should be called on statically linked uses of hidden API.
118inline bool ShouldBlockAccessToMember(uint32_t access_flags, mirror::Class* caller)
David Brazdilee7d2fd2018-01-20 17:25:23 +0000119 REQUIRES_SHARED(Locks::mutator_lock_) {
David Brazdila02cb112018-01-31 11:36:39 +0000120 if (!Runtime::Current()->AreHiddenApiChecksEnabled()) {
121 // Exit early. Nothing to enforce.
122 return false;
David Brazdilee7d2fd2018-01-20 17:25:23 +0000123 }
124
David Brazdila02cb112018-01-31 11:36:39 +0000125 // Only continue if we want to deny access. Warnings are *not* printed.
126 if (GetMemberAction(access_flags) != kDeny) {
127 return false;
David Brazdilee7d2fd2018-01-20 17:25:23 +0000128 }
129
David Brazdila02cb112018-01-31 11:36:39 +0000130 // Member is hidden. Check if the caller is in boot class path.
131 if (caller == nullptr) {
132 // The caller is unknown. We assume that this is *not* boot class path.
133 return true;
134 }
135
136 return !caller->IsBootStrapClassLoaded();
David Brazdilee7d2fd2018-01-20 17:25:23 +0000137}
138
David Brazdil5a61bb72018-01-19 16:59:46 +0000139} // namespace hiddenapi
140} // namespace art
141
142#endif // ART_RUNTIME_HIDDEN_API_H_