blob: d7e5e18b9e34df87e644e69fc988d9412b6cd16c [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 Brazdil068d68d2018-02-12 13:04:17 -080034enum AccessMethod {
35 kReflection,
36 kJNI
37};
38
39inline std::ostream& operator<<(std::ostream& os, AccessMethod value) {
40 switch (value) {
41 case kReflection:
42 os << "reflection";
43 break;
44 case kJNI:
45 os << "JNI";
46 break;
47 }
48 return os;
49}
50
David Brazdila02cb112018-01-31 11:36:39 +000051inline Action GetMemberAction(uint32_t access_flags) {
David Brazdil5a61bb72018-01-19 16:59:46 +000052 switch (HiddenApiAccessFlags::DecodeFromRuntime(access_flags)) {
53 case HiddenApiAccessFlags::kWhitelist:
David Brazdila02cb112018-01-31 11:36:39 +000054 return kAllow;
David Brazdil5a61bb72018-01-19 16:59:46 +000055 case HiddenApiAccessFlags::kLightGreylist:
David Brazdila02cb112018-01-31 11:36:39 +000056 return kAllowButWarn;
David Brazdil92265222018-02-02 11:21:40 +000057 case HiddenApiAccessFlags::kDarkGreylist:
58 return kAllowButWarnAndToast;
David Brazdil5a61bb72018-01-19 16:59:46 +000059 case HiddenApiAccessFlags::kBlacklist:
David Brazdila02cb112018-01-31 11:36:39 +000060 return kDeny;
David Brazdil5a61bb72018-01-19 16:59:46 +000061 }
62}
63
David Brazdilee7d2fd2018-01-20 17:25:23 +000064// Issue a warning about field access.
David Brazdil068d68d2018-02-12 13:04:17 -080065inline void WarnAboutMemberAccess(ArtField* field, AccessMethod access_method)
66 REQUIRES_SHARED(Locks::mutator_lock_) {
David Brazdil1077bbc2018-01-31 14:33:08 +000067 std::string tmp;
68 LOG(WARNING) << "Accessing hidden field "
69 << field->GetDeclaringClass()->GetDescriptor(&tmp) << "->"
David Brazdil068d68d2018-02-12 13:04:17 -080070 << field->GetName() << ":" << field->GetTypeDescriptor()
71 << " (" << HiddenApiAccessFlags::DecodeFromRuntime(field->GetAccessFlags())
72 << ", " << access_method << ")";
David Brazdilee7d2fd2018-01-20 17:25:23 +000073}
74
75// Issue a warning about method access.
David Brazdil068d68d2018-02-12 13:04:17 -080076inline void WarnAboutMemberAccess(ArtMethod* method, AccessMethod access_method)
77 REQUIRES_SHARED(Locks::mutator_lock_) {
David Brazdil1077bbc2018-01-31 14:33:08 +000078 std::string tmp;
79 LOG(WARNING) << "Accessing hidden method "
80 << method->GetDeclaringClass()->GetDescriptor(&tmp) << "->"
David Brazdil068d68d2018-02-12 13:04:17 -080081 << method->GetName() << method->GetSignature().ToString()
82 << " (" << HiddenApiAccessFlags::DecodeFromRuntime(method->GetAccessFlags())
83 << ", " << access_method << ")";
David Brazdilee7d2fd2018-01-20 17:25:23 +000084}
85
David Brazdila02cb112018-01-31 11:36:39 +000086// Returns true if access to `member` should be denied to the caller of the
87// reflective query. The decision is based on whether the caller is in boot
88// class path or not. Because different users of this function determine this
89// in a different way, `fn_caller_in_boot(self)` is called and should return
90// true if the caller is in boot class path.
91// This function might print warnings into the log if the member is greylisted.
David Brazdilee7d2fd2018-01-20 17:25:23 +000092template<typename T>
David Brazdila02cb112018-01-31 11:36:39 +000093inline bool ShouldBlockAccessToMember(T* member,
94 Thread* self,
David Brazdil068d68d2018-02-12 13:04:17 -080095 std::function<bool(Thread*)> fn_caller_in_boot,
96 AccessMethod access_method)
David Brazdilee7d2fd2018-01-20 17:25:23 +000097 REQUIRES_SHARED(Locks::mutator_lock_) {
98 DCHECK(member != nullptr);
David Brazdil92265222018-02-02 11:21:40 +000099 Runtime* runtime = Runtime::Current();
David Brazdila02cb112018-01-31 11:36:39 +0000100
David Brazdil92265222018-02-02 11:21:40 +0000101 if (!runtime->AreHiddenApiChecksEnabled()) {
David Brazdila02cb112018-01-31 11:36:39 +0000102 // Exit early. Nothing to enforce.
103 return false;
David Brazdilee7d2fd2018-01-20 17:25:23 +0000104 }
105
David Brazdila02cb112018-01-31 11:36:39 +0000106 Action action = GetMemberAction(member->GetAccessFlags());
107 if (action == kAllow) {
108 // Nothing to do.
109 return false;
110 }
111
112 // Member is hidden. Walk the stack to find the caller.
113 // This can be *very* expensive. Save it for last.
114 if (fn_caller_in_boot(self)) {
115 // Caller in boot class path. Exit.
116 return false;
117 }
118
David Brazdil068d68d2018-02-12 13:04:17 -0800119 // Member is hidden and we are not in the boot class path.
120
121 // Print a log message with information about this class member access.
122 // We do this regardless of whether we block the access or not.
123 WarnAboutMemberAccess(member, access_method);
124
125 // Block access if on blacklist.
David Brazdil92265222018-02-02 11:21:40 +0000126 if (action == kDeny) {
127 return true;
David Brazdila02cb112018-01-31 11:36:39 +0000128 }
David Brazdil068d68d2018-02-12 13:04:17 -0800129
130 // Allow access to this member but print a warning.
131 DCHECK(action == kAllowButWarn || action == kAllowButWarnAndToast);
132
133 // Depending on a runtime flag, we might move the member into whitelist and
134 // skip the warning the next time the member is accessed.
135 if (runtime->ShouldDedupeHiddenApiWarnings()) {
136 member->SetAccessFlags(HiddenApiAccessFlags::EncodeForRuntime(
137 member->GetAccessFlags(), HiddenApiAccessFlags::kWhitelist));
138 }
139
140 // If this action requires a UI warning, set the appropriate flag.
141 if (action == kAllowButWarnAndToast || runtime->ShouldAlwaysSetHiddenApiWarningFlag()) {
142 Runtime::Current()->SetPendingHiddenApiWarning(true);
143 }
144
145 return false;
David Brazdilee7d2fd2018-01-20 17:25:23 +0000146}
147
David Brazdila02cb112018-01-31 11:36:39 +0000148// Returns true if access to member with `access_flags` should be denied to `caller`.
149// This function should be called on statically linked uses of hidden API.
150inline bool ShouldBlockAccessToMember(uint32_t access_flags, mirror::Class* caller)
David Brazdilee7d2fd2018-01-20 17:25:23 +0000151 REQUIRES_SHARED(Locks::mutator_lock_) {
David Brazdila02cb112018-01-31 11:36:39 +0000152 if (!Runtime::Current()->AreHiddenApiChecksEnabled()) {
153 // Exit early. Nothing to enforce.
154 return false;
David Brazdilee7d2fd2018-01-20 17:25:23 +0000155 }
156
David Brazdila02cb112018-01-31 11:36:39 +0000157 // Only continue if we want to deny access. Warnings are *not* printed.
158 if (GetMemberAction(access_flags) != kDeny) {
159 return false;
David Brazdilee7d2fd2018-01-20 17:25:23 +0000160 }
161
David Brazdila02cb112018-01-31 11:36:39 +0000162 // Member is hidden. Check if the caller is in boot class path.
163 if (caller == nullptr) {
164 // The caller is unknown. We assume that this is *not* boot class path.
165 return true;
166 }
167
168 return !caller->IsBootStrapClassLoaded();
David Brazdilee7d2fd2018-01-20 17:25:23 +0000169}
170
David Brazdil5a61bb72018-01-19 16:59:46 +0000171} // namespace hiddenapi
172} // namespace art
173
174#endif // ART_RUNTIME_HIDDEN_API_H_