blob: 7ca2378a07547cfe3ddbc51c0b837933fd8f5382 [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 Brazdil8ce3bfa2018-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 Brazdil8ce3bfa2018-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 Brazdil8ce3bfa2018-03-12 18:01:18 +000039 kJNI,
40 kLinking,
David Brazdil068d68d2018-02-12 13:04:17 -080041};
42
43inline std::ostream& operator<<(std::ostream& os, AccessMethod value) {
44 switch (value) {
45 case kReflection:
46 os << "reflection";
47 break;
48 case kJNI:
49 os << "JNI";
50 break;
David Brazdil8ce3bfa2018-03-12 18:01:18 +000051 case kLinking:
52 os << "linking";
53 break;
David Brazdil068d68d2018-02-12 13:04:17 -080054 }
55 return os;
56}
57
David Brazdila02cb112018-01-31 11:36:39 +000058inline Action GetMemberAction(uint32_t access_flags) {
David Brazdil5a61bb72018-01-19 16:59:46 +000059 switch (HiddenApiAccessFlags::DecodeFromRuntime(access_flags)) {
60 case HiddenApiAccessFlags::kWhitelist:
David Brazdila02cb112018-01-31 11:36:39 +000061 return kAllow;
David Brazdil5a61bb72018-01-19 16:59:46 +000062 case HiddenApiAccessFlags::kLightGreylist:
David Brazdila02cb112018-01-31 11:36:39 +000063 return kAllowButWarn;
David Brazdil92265222018-02-02 11:21:40 +000064 case HiddenApiAccessFlags::kDarkGreylist:
65 return kAllowButWarnAndToast;
David Brazdil5a61bb72018-01-19 16:59:46 +000066 case HiddenApiAccessFlags::kBlacklist:
David Brazdila02cb112018-01-31 11:36:39 +000067 return kDeny;
David Brazdil5a61bb72018-01-19 16:59:46 +000068 }
69}
70
David Brazdilee7d2fd2018-01-20 17:25:23 +000071// Issue a warning about field access.
David Brazdil068d68d2018-02-12 13:04:17 -080072inline void WarnAboutMemberAccess(ArtField* field, AccessMethod access_method)
73 REQUIRES_SHARED(Locks::mutator_lock_) {
David Brazdil1077bbc2018-01-31 14:33:08 +000074 std::string tmp;
75 LOG(WARNING) << "Accessing hidden field "
76 << field->GetDeclaringClass()->GetDescriptor(&tmp) << "->"
David Brazdil068d68d2018-02-12 13:04:17 -080077 << field->GetName() << ":" << field->GetTypeDescriptor()
78 << " (" << HiddenApiAccessFlags::DecodeFromRuntime(field->GetAccessFlags())
79 << ", " << access_method << ")";
David Brazdilee7d2fd2018-01-20 17:25:23 +000080}
81
82// Issue a warning about method access.
David Brazdil068d68d2018-02-12 13:04:17 -080083inline void WarnAboutMemberAccess(ArtMethod* method, AccessMethod access_method)
84 REQUIRES_SHARED(Locks::mutator_lock_) {
David Brazdil1077bbc2018-01-31 14:33:08 +000085 std::string tmp;
86 LOG(WARNING) << "Accessing hidden method "
87 << method->GetDeclaringClass()->GetDescriptor(&tmp) << "->"
David Brazdil068d68d2018-02-12 13:04:17 -080088 << method->GetName() << method->GetSignature().ToString()
89 << " (" << HiddenApiAccessFlags::DecodeFromRuntime(method->GetAccessFlags())
90 << ", " << access_method << ")";
David Brazdilee7d2fd2018-01-20 17:25:23 +000091}
92
David Brazdila02cb112018-01-31 11:36:39 +000093// Returns true if access to `member` should be denied to the caller of the
94// reflective query. The decision is based on whether the caller is in boot
95// class path or not. Because different users of this function determine this
96// in a different way, `fn_caller_in_boot(self)` is called and should return
97// true if the caller is in boot class path.
David Brazdil8ce3bfa2018-03-12 18:01:18 +000098// This function might print warnings into the log if the member is hidden.
David Brazdilee7d2fd2018-01-20 17:25:23 +000099template<typename T>
David Brazdila02cb112018-01-31 11:36:39 +0000100inline bool ShouldBlockAccessToMember(T* member,
101 Thread* self,
David Brazdil068d68d2018-02-12 13:04:17 -0800102 std::function<bool(Thread*)> fn_caller_in_boot,
103 AccessMethod access_method)
David Brazdilee7d2fd2018-01-20 17:25:23 +0000104 REQUIRES_SHARED(Locks::mutator_lock_) {
105 DCHECK(member != nullptr);
David Brazdil92265222018-02-02 11:21:40 +0000106 Runtime* runtime = Runtime::Current();
David Brazdila02cb112018-01-31 11:36:39 +0000107
David Brazdil92265222018-02-02 11:21:40 +0000108 if (!runtime->AreHiddenApiChecksEnabled()) {
David Brazdila02cb112018-01-31 11:36:39 +0000109 // Exit early. Nothing to enforce.
110 return false;
David Brazdilee7d2fd2018-01-20 17:25:23 +0000111 }
112
David Brazdila02cb112018-01-31 11:36:39 +0000113 Action action = GetMemberAction(member->GetAccessFlags());
114 if (action == kAllow) {
115 // Nothing to do.
116 return false;
117 }
118
119 // Member is hidden. Walk the stack to find the caller.
120 // This can be *very* expensive. Save it for last.
121 if (fn_caller_in_boot(self)) {
122 // Caller in boot class path. Exit.
123 return false;
124 }
125
David Brazdil068d68d2018-02-12 13:04:17 -0800126 // Member is hidden and we are not in the boot class path.
127
128 // Print a log message with information about this class member access.
129 // We do this regardless of whether we block the access or not.
130 WarnAboutMemberAccess(member, access_method);
131
132 // Block access if on blacklist.
David Brazdil92265222018-02-02 11:21:40 +0000133 if (action == kDeny) {
134 return true;
David Brazdila02cb112018-01-31 11:36:39 +0000135 }
David Brazdil068d68d2018-02-12 13:04:17 -0800136
137 // Allow access to this member but print a warning.
138 DCHECK(action == kAllowButWarn || action == kAllowButWarnAndToast);
139
140 // Depending on a runtime flag, we might move the member into whitelist and
141 // skip the warning the next time the member is accessed.
142 if (runtime->ShouldDedupeHiddenApiWarnings()) {
143 member->SetAccessFlags(HiddenApiAccessFlags::EncodeForRuntime(
144 member->GetAccessFlags(), HiddenApiAccessFlags::kWhitelist));
145 }
146
147 // If this action requires a UI warning, set the appropriate flag.
148 if (action == kAllowButWarnAndToast || runtime->ShouldAlwaysSetHiddenApiWarningFlag()) {
149 Runtime::Current()->SetPendingHiddenApiWarning(true);
150 }
151
152 return false;
David Brazdilee7d2fd2018-01-20 17:25:23 +0000153}
154
David Brazdil8ce3bfa2018-03-12 18:01:18 +0000155// Returns true if access to `member` should be denied to a caller loaded with
156// `caller_class_loader`.
157// This function might print warnings into the log if the member is hidden.
158template<typename T>
159inline bool ShouldBlockAccessToMember(T* member,
160 ObjPtr<mirror::ClassLoader> caller_class_loader,
161 AccessMethod access_method)
David Brazdilee7d2fd2018-01-20 17:25:23 +0000162 REQUIRES_SHARED(Locks::mutator_lock_) {
David Brazdil8ce3bfa2018-03-12 18:01:18 +0000163 bool caller_in_boot = (caller_class_loader.IsNull());
164 return ShouldBlockAccessToMember(member,
165 /* thread */ nullptr,
166 [caller_in_boot] (Thread*) { return caller_in_boot; },
167 access_method);
David Brazdilee7d2fd2018-01-20 17:25:23 +0000168}
169
David Brazdil5a61bb72018-01-19 16:59:46 +0000170} // namespace hiddenapi
171} // namespace art
172
173#endif // ART_RUNTIME_HIDDEN_API_H_