blob: f2ea2fdaaac782e59b2aca9b119e7844f3a22769 [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
David Brazdil6ca80d22018-03-12 18:01:18 +000020#include "art_field-inl.h"
21#include "art_method-inl.h"
David Sehr67bf42e2018-02-26 16:43:04 -080022#include "dex/hidden_api_access_flags.h"
David Brazdil6ca80d22018-03-12 18:01:18 +000023#include "mirror/class-inl.h"
David Brazdil5a61bb72018-01-19 16:59:46 +000024#include "reflection.h"
25#include "runtime.h"
26
27namespace art {
28namespace hiddenapi {
29
David Brazdila02cb112018-01-31 11:36:39 +000030enum Action {
31 kAllow,
32 kAllowButWarn,
David Brazdil92265222018-02-02 11:21:40 +000033 kAllowButWarnAndToast,
David Brazdila02cb112018-01-31 11:36:39 +000034 kDeny
35};
David Brazdil5a61bb72018-01-19 16:59:46 +000036
David Brazdil068d68d2018-02-12 13:04:17 -080037enum AccessMethod {
38 kReflection,
David Brazdil6ca80d22018-03-12 18:01:18 +000039 kJNI,
40 kLinking,
David Brazdila11ea9a2018-03-14 13:57:27 +000041 kOverride,
David Brazdil068d68d2018-02-12 13:04:17 -080042};
43
44inline std::ostream& operator<<(std::ostream& os, AccessMethod value) {
45 switch (value) {
46 case kReflection:
47 os << "reflection";
48 break;
49 case kJNI:
50 os << "JNI";
51 break;
David Brazdil6ca80d22018-03-12 18:01:18 +000052 case kLinking:
53 os << "linking";
54 break;
David Brazdila11ea9a2018-03-14 13:57:27 +000055 case kOverride:
56 os << "override";
57 break;
David Brazdil068d68d2018-02-12 13:04:17 -080058 }
59 return os;
60}
61
David Brazdila02cb112018-01-31 11:36:39 +000062inline Action GetMemberAction(uint32_t access_flags) {
David Brazdil5a61bb72018-01-19 16:59:46 +000063 switch (HiddenApiAccessFlags::DecodeFromRuntime(access_flags)) {
64 case HiddenApiAccessFlags::kWhitelist:
David Brazdila02cb112018-01-31 11:36:39 +000065 return kAllow;
David Brazdil5a61bb72018-01-19 16:59:46 +000066 case HiddenApiAccessFlags::kLightGreylist:
David Brazdila02cb112018-01-31 11:36:39 +000067 return kAllowButWarn;
David Brazdil92265222018-02-02 11:21:40 +000068 case HiddenApiAccessFlags::kDarkGreylist:
69 return kAllowButWarnAndToast;
David Brazdil5a61bb72018-01-19 16:59:46 +000070 case HiddenApiAccessFlags::kBlacklist:
David Brazdila02cb112018-01-31 11:36:39 +000071 return kDeny;
David Brazdil5a61bb72018-01-19 16:59:46 +000072 }
73}
74
David Brazdilee7d2fd2018-01-20 17:25:23 +000075// Issue a warning about field access.
David Brazdil068d68d2018-02-12 13:04:17 -080076inline void WarnAboutMemberAccess(ArtField* field, 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 field "
80 << field->GetDeclaringClass()->GetDescriptor(&tmp) << "->"
David Brazdil068d68d2018-02-12 13:04:17 -080081 << field->GetName() << ":" << field->GetTypeDescriptor()
82 << " (" << HiddenApiAccessFlags::DecodeFromRuntime(field->GetAccessFlags())
83 << ", " << access_method << ")";
David Brazdilee7d2fd2018-01-20 17:25:23 +000084}
85
86// Issue a warning about method access.
David Brazdil068d68d2018-02-12 13:04:17 -080087inline void WarnAboutMemberAccess(ArtMethod* method, AccessMethod access_method)
88 REQUIRES_SHARED(Locks::mutator_lock_) {
David Brazdil1077bbc2018-01-31 14:33:08 +000089 std::string tmp;
90 LOG(WARNING) << "Accessing hidden method "
91 << method->GetDeclaringClass()->GetDescriptor(&tmp) << "->"
David Brazdil068d68d2018-02-12 13:04:17 -080092 << method->GetName() << method->GetSignature().ToString()
93 << " (" << HiddenApiAccessFlags::DecodeFromRuntime(method->GetAccessFlags())
94 << ", " << access_method << ")";
David Brazdilee7d2fd2018-01-20 17:25:23 +000095}
96
David Brazdila02cb112018-01-31 11:36:39 +000097// Returns true if access to `member` should be denied to the caller of the
98// reflective query. The decision is based on whether the caller is in boot
99// class path or not. Because different users of this function determine this
100// in a different way, `fn_caller_in_boot(self)` is called and should return
101// true if the caller is in boot class path.
David Brazdil6ca80d22018-03-12 18:01:18 +0000102// This function might print warnings into the log if the member is hidden.
David Brazdilee7d2fd2018-01-20 17:25:23 +0000103template<typename T>
David Brazdila02cb112018-01-31 11:36:39 +0000104inline bool ShouldBlockAccessToMember(T* member,
105 Thread* self,
David Brazdil068d68d2018-02-12 13:04:17 -0800106 std::function<bool(Thread*)> fn_caller_in_boot,
107 AccessMethod access_method)
David Brazdilee7d2fd2018-01-20 17:25:23 +0000108 REQUIRES_SHARED(Locks::mutator_lock_) {
109 DCHECK(member != nullptr);
David Brazdil92265222018-02-02 11:21:40 +0000110 Runtime* runtime = Runtime::Current();
David Brazdila02cb112018-01-31 11:36:39 +0000111
David Brazdil92265222018-02-02 11:21:40 +0000112 if (!runtime->AreHiddenApiChecksEnabled()) {
David Brazdila02cb112018-01-31 11:36:39 +0000113 // Exit early. Nothing to enforce.
114 return false;
David Brazdilee7d2fd2018-01-20 17:25:23 +0000115 }
116
David Brazdila02cb112018-01-31 11:36:39 +0000117 Action action = GetMemberAction(member->GetAccessFlags());
118 if (action == kAllow) {
119 // Nothing to do.
120 return false;
121 }
122
123 // Member is hidden. Walk the stack to find the caller.
124 // This can be *very* expensive. Save it for last.
125 if (fn_caller_in_boot(self)) {
126 // Caller in boot class path. Exit.
127 return false;
128 }
129
David Brazdil068d68d2018-02-12 13:04:17 -0800130 // Member is hidden and we are not in the boot class path.
131
132 // Print a log message with information about this class member access.
133 // We do this regardless of whether we block the access or not.
134 WarnAboutMemberAccess(member, access_method);
135
136 // Block access if on blacklist.
David Brazdil92265222018-02-02 11:21:40 +0000137 if (action == kDeny) {
138 return true;
David Brazdila02cb112018-01-31 11:36:39 +0000139 }
David Brazdil068d68d2018-02-12 13:04:17 -0800140
141 // Allow access to this member but print a warning.
142 DCHECK(action == kAllowButWarn || action == kAllowButWarnAndToast);
143
144 // Depending on a runtime flag, we might move the member into whitelist and
145 // skip the warning the next time the member is accessed.
146 if (runtime->ShouldDedupeHiddenApiWarnings()) {
147 member->SetAccessFlags(HiddenApiAccessFlags::EncodeForRuntime(
148 member->GetAccessFlags(), HiddenApiAccessFlags::kWhitelist));
149 }
150
151 // If this action requires a UI warning, set the appropriate flag.
152 if (action == kAllowButWarnAndToast || runtime->ShouldAlwaysSetHiddenApiWarningFlag()) {
153 Runtime::Current()->SetPendingHiddenApiWarning(true);
154 }
155
156 return false;
David Brazdilee7d2fd2018-01-20 17:25:23 +0000157}
158
David Brazdil6ca80d22018-03-12 18:01:18 +0000159// Returns true if access to `member` should be denied to a caller loaded with
160// `caller_class_loader`.
161// This function might print warnings into the log if the member is hidden.
162template<typename T>
163inline bool ShouldBlockAccessToMember(T* member,
164 ObjPtr<mirror::ClassLoader> caller_class_loader,
165 AccessMethod access_method)
David Brazdilee7d2fd2018-01-20 17:25:23 +0000166 REQUIRES_SHARED(Locks::mutator_lock_) {
David Brazdil6ca80d22018-03-12 18:01:18 +0000167 bool caller_in_boot = (caller_class_loader.IsNull());
168 return ShouldBlockAccessToMember(member,
169 /* thread */ nullptr,
170 [caller_in_boot] (Thread*) { return caller_in_boot; },
171 access_method);
David Brazdilee7d2fd2018-01-20 17:25:23 +0000172}
173
David Brazdil5a61bb72018-01-19 16:59:46 +0000174} // namespace hiddenapi
175} // namespace art
176
177#endif // ART_RUNTIME_HIDDEN_API_H_