blob: e51968209235a629fda3ba4045390d8eef766805 [file] [log] [blame]
Andreas Gampe80f5fe52018-03-28 16:23:24 -07001/*
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
Mathew Inwood73ddda42018-04-03 15:32:32 +010017#include <log/log_event_list.h>
18
Andreas Gampe80f5fe52018-03-28 16:23:24 -070019#include "hidden_api.h"
20
Narayan Kamathe453a8d2018-04-03 15:23:46 +010021#include <nativehelper/scoped_local_ref.h>
22
Andreas Gampe80f5fe52018-03-28 16:23:24 -070023#include "base/dumpable.h"
Narayan Kamathe453a8d2018-04-03 15:23:46 +010024#include "thread-current-inl.h"
25#include "well_known_classes.h"
Andreas Gampe80f5fe52018-03-28 16:23:24 -070026
27namespace art {
28namespace hiddenapi {
29
Mathew Inwood27199e62018-04-11 16:08:21 +010030// Set to true if we should always print a warning in logcat for all hidden API accesses, not just
31// dark grey and black. This can be set to true for developer preview / beta builds, but should be
32// false for public release builds.
Mathew Inwood6d6012e2018-04-12 15:43:11 +010033// Note that when flipping this flag, you must also update the expectations of test 674-hiddenapi
34// as it affects whether or not we warn for light grey APIs that have been added to the exemptions
35// list.
Mathew Inwood27199e62018-04-11 16:08:21 +010036static constexpr bool kLogAllAccesses = true;
37
Andreas Gampe80f5fe52018-03-28 16:23:24 -070038static inline std::ostream& operator<<(std::ostream& os, AccessMethod value) {
39 switch (value) {
David Brazdil54a99cf2018-04-05 16:57:32 +010040 case kNone:
41 LOG(FATAL) << "Internal access to hidden API should not be logged";
42 UNREACHABLE();
Andreas Gampe80f5fe52018-03-28 16:23:24 -070043 case kReflection:
44 os << "reflection";
45 break;
46 case kJNI:
47 os << "JNI";
48 break;
49 case kLinking:
50 os << "linking";
51 break;
52 }
53 return os;
54}
55
56static constexpr bool EnumsEqual(EnforcementPolicy policy, HiddenApiAccessFlags::ApiList apiList) {
57 return static_cast<int>(policy) == static_cast<int>(apiList);
58}
59
60// GetMemberAction-related static_asserts.
61static_assert(
Andreas Gampe80f5fe52018-03-28 16:23:24 -070062 EnumsEqual(EnforcementPolicy::kDarkGreyAndBlackList, HiddenApiAccessFlags::kDarkGreylist) &&
63 EnumsEqual(EnforcementPolicy::kBlacklistOnly, HiddenApiAccessFlags::kBlacklist),
64 "Mismatch between EnforcementPolicy and ApiList enums");
65static_assert(
Mathew Inwood68693692018-04-05 16:10:25 +010066 EnforcementPolicy::kJustWarn < EnforcementPolicy::kDarkGreyAndBlackList &&
Andreas Gampe80f5fe52018-03-28 16:23:24 -070067 EnforcementPolicy::kDarkGreyAndBlackList < EnforcementPolicy::kBlacklistOnly,
68 "EnforcementPolicy values ordering not correct");
69
70namespace detail {
71
Mathew Inwood73ddda42018-04-03 15:32:32 +010072// This is the ID of the event log event. It is duplicated from
73// system/core/logcat/event.logtags
74constexpr int EVENT_LOG_TAG_art_hidden_api_access = 20004;
75
Andreas Gampe80f5fe52018-03-28 16:23:24 -070076MemberSignature::MemberSignature(ArtField* field) {
Mathew Inwood73ddda42018-04-03 15:32:32 +010077 class_name_ = field->GetDeclaringClass()->GetDescriptor(&tmp_);
78 member_name_ = field->GetName();
79 type_signature_ = field->GetTypeDescriptor();
80 type_ = kField;
Andreas Gampe80f5fe52018-03-28 16:23:24 -070081}
82
83MemberSignature::MemberSignature(ArtMethod* method) {
Mathew Inwood73ddda42018-04-03 15:32:32 +010084 class_name_ = method->GetDeclaringClass()->GetDescriptor(&tmp_);
85 member_name_ = method->GetName();
86 type_signature_ = method->GetSignature().ToString();
87 type_ = kMethod;
88}
89
90inline std::vector<const char*> MemberSignature::GetSignatureParts() const {
91 if (type_ == kField) {
92 return { class_name_.c_str(), "->", member_name_.c_str(), ":", type_signature_.c_str() };
93 } else {
94 DCHECK_EQ(type_, kMethod);
95 return { class_name_.c_str(), "->", member_name_.c_str(), type_signature_.c_str() };
96 }
Andreas Gampe80f5fe52018-03-28 16:23:24 -070097}
98
99bool MemberSignature::DoesPrefixMatch(const std::string& prefix) const {
100 size_t pos = 0;
Mathew Inwood73ddda42018-04-03 15:32:32 +0100101 for (const char* part : GetSignatureParts()) {
102 size_t count = std::min(prefix.length() - pos, strlen(part));
Andreas Gampe80f5fe52018-03-28 16:23:24 -0700103 if (prefix.compare(pos, count, part, 0, count) == 0) {
104 pos += count;
105 } else {
106 return false;
107 }
108 }
109 // We have a complete match if all parts match (we exit the loop without
110 // returning) AND we've matched the whole prefix.
111 return pos == prefix.length();
112}
113
114bool MemberSignature::IsExempted(const std::vector<std::string>& exemptions) {
115 for (const std::string& exemption : exemptions) {
116 if (DoesPrefixMatch(exemption)) {
117 return true;
118 }
119 }
120 return false;
121}
122
123void MemberSignature::Dump(std::ostream& os) const {
Mathew Inwood73ddda42018-04-03 15:32:32 +0100124 for (const char* part : GetSignatureParts()) {
Andreas Gampe80f5fe52018-03-28 16:23:24 -0700125 os << part;
126 }
127}
128
129void MemberSignature::WarnAboutAccess(AccessMethod access_method,
130 HiddenApiAccessFlags::ApiList list) {
Mathew Inwood73ddda42018-04-03 15:32:32 +0100131 LOG(WARNING) << "Accessing hidden " << (type_ == kField ? "field " : "method ")
132 << Dumpable<MemberSignature>(*this) << " (" << list << ", " << access_method << ")";
133}
134
135void MemberSignature::LogAccessToEventLog(AccessMethod access_method, Action action_taken) {
136 if (access_method == kLinking) {
137 // Linking warnings come from static analysis/compilation of the bytecode
138 // and can contain false positives (i.e. code that is never run). We choose
139 // not to log these in the event log.
140 return;
141 }
142 uint32_t flags = 0;
143 if (action_taken == kDeny) {
144 flags |= kAccessDenied;
145 }
146 if (type_ == kField) {
147 flags |= kMemberIsField;
148 }
149 android_log_event_list ctx(EVENT_LOG_TAG_art_hidden_api_access);
150 ctx << access_method;
151 ctx << flags;
152 ctx << class_name_;
153 ctx << member_name_;
154 ctx << type_signature_;
155 ctx << LOG_ID_EVENTS;
Andreas Gampe80f5fe52018-03-28 16:23:24 -0700156}
157
158template<typename T>
Narayan Kamathe453a8d2018-04-03 15:23:46 +0100159Action GetMemberActionImpl(T* member, Action action, AccessMethod access_method) {
David Brazdil54a99cf2018-04-05 16:57:32 +0100160 DCHECK_NE(action, kAllow);
161
Andreas Gampe80f5fe52018-03-28 16:23:24 -0700162 // Get the signature, we need it later.
163 MemberSignature member_signature(member);
164
165 Runtime* runtime = Runtime::Current();
166
Mathew Inwoodc8ce5f52018-04-05 13:58:55 +0100167 // Check for an exemption first. Exempted APIs are treated as white list.
168 // We only do this if we're about to deny, or if the app is debuggable. This is because:
169 // - we only print a warning for light greylist violations for debuggable apps
170 // - for non-debuggable apps, there is no distinction between light grey & whitelisted APIs.
171 // - we want to avoid the overhead of checking for exemptions for light greylisted APIs whenever
172 // possible.
Mathew Inwood27199e62018-04-11 16:08:21 +0100173 if (kLogAllAccesses || action == kDeny || runtime->IsJavaDebuggable()) {
Andreas Gampe80f5fe52018-03-28 16:23:24 -0700174 if (member_signature.IsExempted(runtime->GetHiddenApiExemptions())) {
Mathew Inwoodc8ce5f52018-04-05 13:58:55 +0100175 action = kAllow;
Andreas Gampe80f5fe52018-03-28 16:23:24 -0700176 // Avoid re-examining the exemption list next time.
Mathew Inwoodc8ce5f52018-04-05 13:58:55 +0100177 // Note this results in no warning for the member, which seems like what one would expect.
178 // Exemptions effectively adds new members to the whitelist.
Mathew Inwood64ee8ae2018-04-09 12:24:55 +0100179 if (runtime->ShouldDedupeHiddenApiWarnings()) {
180 member->SetAccessFlags(HiddenApiAccessFlags::EncodeForRuntime(
181 member->GetAccessFlags(), HiddenApiAccessFlags::kWhitelist));
182 }
Mathew Inwoodc8ce5f52018-04-05 13:58:55 +0100183 return kAllow;
Andreas Gampe80f5fe52018-03-28 16:23:24 -0700184 }
Andreas Gampe80f5fe52018-03-28 16:23:24 -0700185
Mathew Inwoodc8ce5f52018-04-05 13:58:55 +0100186 if (access_method != kNone) {
187 // Print a log message with information about this class member access.
188 // We do this if we're about to block access, or the app is debuggable.
189 member_signature.WarnAboutAccess(access_method,
190 HiddenApiAccessFlags::DecodeFromRuntime(member->GetAccessFlags()));
191 }
David Brazdil54a99cf2018-04-05 16:57:32 +0100192 }
Andreas Gampe80f5fe52018-03-28 16:23:24 -0700193
Mathew Inwood73ddda42018-04-03 15:32:32 +0100194 if (kIsTargetBuild) {
195 uint32_t eventLogSampleRate = runtime->GetHiddenApiEventLogSampleRate();
196 // Assert that RAND_MAX is big enough, to ensure sampling below works as expected.
197 static_assert(RAND_MAX >= 0xffff, "RAND_MAX too small");
198 if (eventLogSampleRate != 0 &&
199 (static_cast<uint32_t>(std::rand()) & 0xffff) < eventLogSampleRate) {
200 member_signature.LogAccessToEventLog(access_method, action);
201 }
202 }
203
Andreas Gampe80f5fe52018-03-28 16:23:24 -0700204 if (action == kDeny) {
205 // Block access
Narayan Kamathe453a8d2018-04-03 15:23:46 +0100206 return action;
Andreas Gampe80f5fe52018-03-28 16:23:24 -0700207 }
208
209 // Allow access to this member but print a warning.
210 DCHECK(action == kAllowButWarn || action == kAllowButWarnAndToast);
211
David Brazdil54a99cf2018-04-05 16:57:32 +0100212 if (access_method != kNone) {
213 // Depending on a runtime flag, we might move the member into whitelist and
214 // skip the warning the next time the member is accessed.
215 if (runtime->ShouldDedupeHiddenApiWarnings()) {
216 member->SetAccessFlags(HiddenApiAccessFlags::EncodeForRuntime(
217 member->GetAccessFlags(), HiddenApiAccessFlags::kWhitelist));
218 }
Andreas Gampe80f5fe52018-03-28 16:23:24 -0700219
David Brazdil54a99cf2018-04-05 16:57:32 +0100220 // If this action requires a UI warning, set the appropriate flag.
221 if (action == kAllowButWarnAndToast || runtime->ShouldAlwaysSetHiddenApiWarningFlag()) {
222 runtime->SetPendingHiddenApiWarning(true);
223 }
Andreas Gampe80f5fe52018-03-28 16:23:24 -0700224 }
225
Narayan Kamathe453a8d2018-04-03 15:23:46 +0100226 return action;
Andreas Gampe80f5fe52018-03-28 16:23:24 -0700227}
228
229// Need to instantiate this.
Narayan Kamathe453a8d2018-04-03 15:23:46 +0100230template Action GetMemberActionImpl<ArtField>(ArtField* member,
231 Action action,
232 AccessMethod access_method);
233template Action GetMemberActionImpl<ArtMethod>(ArtMethod* member,
234 Action action,
235 AccessMethod access_method);
Andreas Gampe80f5fe52018-03-28 16:23:24 -0700236} // namespace detail
Narayan Kamathe453a8d2018-04-03 15:23:46 +0100237
238template<typename T>
239void NotifyHiddenApiListener(T* member) {
240 Runtime* runtime = Runtime::Current();
241 if (!runtime->IsAotCompiler()) {
242 ScopedObjectAccessUnchecked soa(Thread::Current());
243
244 ScopedLocalRef<jobject> consumer_object(soa.Env(),
245 soa.Env()->GetStaticObjectField(
246 WellKnownClasses::dalvik_system_VMRuntime,
247 WellKnownClasses::dalvik_system_VMRuntime_nonSdkApiUsageConsumer));
248 // If the consumer is non-null, we call back to it to let it know that we
249 // have encountered an API that's in one of our lists.
250 if (consumer_object != nullptr) {
251 detail::MemberSignature member_signature(member);
252 std::ostringstream member_signature_str;
253 member_signature.Dump(member_signature_str);
254
255 ScopedLocalRef<jobject> signature_str(
256 soa.Env(),
257 soa.Env()->NewStringUTF(member_signature_str.str().c_str()));
258
259 // Call through to Consumer.accept(String memberSignature);
260 soa.Env()->CallVoidMethod(consumer_object.get(),
261 WellKnownClasses::java_util_function_Consumer_accept,
262 signature_str.get());
263 }
264 }
265}
266
267template void NotifyHiddenApiListener<ArtMethod>(ArtMethod* member);
268template void NotifyHiddenApiListener<ArtField>(ArtField* member);
269
Andreas Gampe80f5fe52018-03-28 16:23:24 -0700270} // namespace hiddenapi
271} // namespace art