Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/browser/android/safe_browsing/safe_browsing_api_handler_bridge. h" | |
| 6 | |
| 7 #include <memory> | |
| 8 #include <string> | |
| 9 | |
| 10 #include "base/android/context_utils.h" | |
| 11 #include "base/android/jni_android.h" | |
| 12 #include "base/android/jni_array.h" | |
| 13 #include "base/android/jni_string.h" | |
| 14 #include "base/metrics/histogram_macros.h" | |
| 15 #include "chrome/browser/safe_browsing/safe_browsing_util.h" | |
| 16 #include "components/safe_browsing_db/safe_browsing_api_handler_util.h" | |
| 17 #include "content/public/browser/browser_thread.h" | |
| 18 #include "jni/SafeBrowsingApiBridge_jni.h" | |
| 19 | |
| 20 using base::android::AttachCurrentThread; | |
| 21 using base::android::ConvertJavaStringToUTF8; | |
| 22 using base::android::ConvertUTF8ToJavaString; | |
| 23 using base::android::GetApplicationContext; | |
| 24 using base::android::ScopedJavaLocalRef; | |
| 25 using base::android::ToJavaIntArray; | |
| 26 using content::BrowserThread; | |
| 27 | |
| 28 namespace safe_browsing { | |
| 29 | |
| 30 namespace { | |
| 31 // Takes ownership of callback ptr. | |
| 32 void RunCallbackOnIOThread( | |
| 33 SafeBrowsingApiHandler::URLCheckCallbackMeta* callback, | |
| 34 SBThreatType threat_type, | |
| 35 const ThreatMetadata& metadata) { | |
| 36 BrowserThread::PostTask( | |
| 37 BrowserThread::IO, FROM_HERE, | |
| 38 base::Bind(&SafeBrowsingApiHandler::URLCheckCallbackMeta::Run, | |
| 39 base::Owned(callback), threat_type, metadata)); | |
| 40 } | |
| 41 | |
| 42 void ReportUmaResult(safe_browsing::UmaRemoteCallResult result) { | |
| 43 UMA_HISTOGRAM_ENUMERATION("SB2.RemoteCall.Result", result, | |
| 44 safe_browsing::UMA_STATUS_MAX_VALUE); | |
| 45 } | |
| 46 | |
| 47 // Convert a SBThreatType to a Java threat type. We only support a few. | |
| 48 int SBThreatTypeToJavaThreatType(const SBThreatType& sb_threat_type) { | |
| 49 switch (sb_threat_type) { | |
| 50 case SB_THREAT_TYPE_URL_PHISHING: | |
| 51 return safe_browsing::JAVA_THREAT_TYPE_SOCIAL_ENGINEERING; | |
| 52 case SB_THREAT_TYPE_URL_MALWARE: | |
| 53 return safe_browsing::JAVA_THREAT_TYPE_POTENTIALLY_HARMFUL_APPLICATION; | |
| 54 default: | |
| 55 NOTREACHED(); | |
| 56 return 0; | |
| 57 } | |
| 58 } | |
| 59 | |
| 60 // Convert a vector of SBThreatTypes to JavaIntArray of Java threat types. | |
| 61 ScopedJavaLocalRef<jintArray> SBThreatTypesToJavaArray( | |
| 62 JNIEnv* env, | |
| 63 const std::vector<SBThreatType>& threat_types) { | |
| 64 DCHECK(threat_types.size() > 0); | |
| 65 int int_threat_types[threat_types.size()]; | |
| 66 int* itr = &int_threat_types[0]; | |
| 67 for (auto threat_type : threat_types) { | |
| 68 *itr++ = SBThreatTypeToJavaThreatType(threat_type); | |
| 69 } | |
| 70 return ToJavaIntArray(env, int_threat_types, threat_types.size()); | |
| 71 } | |
| 72 | |
| 73 } // namespace | |
| 74 | |
| 75 | |
| 76 bool RegisterSafeBrowsingApiBridge(JNIEnv* env) { | |
| 77 return RegisterNativesImpl(env); | |
| 78 } | |
| 79 | |
| 80 // Java->Native call, invoked when a check is done. | |
| 81 // |callback_id| is an int form of pointer to a URLCheckCallbackMeta | |
| 82 // that will be called and then deleted here. | |
| 83 // |result_status| is one of those from SafeBrowsingApiHandler.java | |
| 84 // |metadata| is a JSON string classifying the threat if there is one. | |
| 85 void OnUrlCheckDone(JNIEnv* env, | |
| 86 const JavaParamRef<jclass>& context, | |
| 87 jlong callback_id, | |
| 88 jint result_status, | |
| 89 const JavaParamRef<jstring>& metadata) { | |
| 90 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 91 DCHECK(callback_id); | |
| 92 | |
| 93 const std::string metadata_str = | |
| 94 (metadata ? ConvertJavaStringToUTF8(env, metadata) : ""); | |
| 95 | |
| 96 DVLOG(1) << "OnURLCheckDone invoked for check " << callback_id | |
| 97 << " with status=" << result_status << " and metadata=[" | |
| 98 << metadata_str << "]"; | |
| 99 | |
| 100 // Convert java long long int to c++ pointer, take ownership. | |
| 101 std::unique_ptr<SafeBrowsingApiHandler::URLCheckCallbackMeta> callback( | |
| 102 reinterpret_cast<SafeBrowsingApiHandlerBridge::URLCheckCallbackMeta*>( | |
| 103 callback_id)); | |
| 104 | |
| 105 if (result_status != RESULT_STATUS_SUCCESS) { | |
| 106 // TODO(nparker): If the API is consistently failing, we might want to | |
| 107 // turn it off altogether and retest periodically. This would | |
| 108 // alleviate a bad experience if GMSCore is somehow busted. | |
| 109 if (result_status == RESULT_STATUS_TIMEOUT) { | |
| 110 ReportUmaResult(UMA_STATUS_TIMEOUT); | |
| 111 VLOG(1) << "Safe browsing API call timed-out"; | |
| 112 } else { | |
| 113 DCHECK_EQ(result_status, RESULT_STATUS_INTERNAL_ERROR); | |
| 114 ReportUmaResult(UMA_STATUS_INTERNAL_ERROR); | |
| 115 LOG(WARNING) << "Safe browsing API had internal error"; | |
| 116 } | |
| 117 RunCallbackOnIOThread(callback.release(), SB_THREAT_TYPE_SAFE, | |
| 118 ThreatMetadata()); | |
| 119 return; | |
| 120 } | |
| 121 | |
| 122 // Shortcut for safe, so we don't have to parse JSON. | |
| 123 if (metadata_str == "{}") { | |
| 124 ReportUmaResult(UMA_STATUS_SAFE); | |
| 125 RunCallbackOnIOThread(callback.release(), SB_THREAT_TYPE_SAFE, | |
| 126 ThreatMetadata()); | |
| 127 } else { | |
| 128 // Unsafe, assuming we can parse the JSON. | |
| 129 SBThreatType worst_threat; | |
| 130 ThreatMetadata threat_metadata; | |
| 131 ReportUmaResult( | |
| 132 ParseJsonFromGMSCore(metadata_str, &worst_threat, &threat_metadata)); | |
| 133 if (worst_threat != SB_THREAT_TYPE_SAFE) { | |
| 134 DVLOG(1) << "Check " << callback_id << " marked as UNSAFE"; | |
| 135 } | |
| 136 | |
| 137 RunCallbackOnIOThread(callback.release(), worst_threat, threat_metadata); | |
| 138 } | |
| 139 } | |
| 140 | |
| 141 // | |
| 142 // SafeBrowsingApiHandlerBridge | |
| 143 // | |
| 144 SafeBrowsingApiHandlerBridge::SafeBrowsingApiHandlerBridge() | |
| 145 : checked_api_support_(false) {} | |
| 146 | |
| 147 SafeBrowsingApiHandlerBridge::~SafeBrowsingApiHandlerBridge() { | |
| 148 } | |
| 149 | |
| 150 bool SafeBrowsingApiHandlerBridge::CheckApiIsSupported() { | |
| 151 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 152 if (!checked_api_support_) { | |
| 153 DVLOG(1) << "Checking API support."; | |
| 154 j_api_handler_ = Java_SafeBrowsingApiBridge_create( | |
| 155 AttachCurrentThread(), GetApplicationContext()); | |
|
Nathan Parker
2016/04/29 20:42:04
On public-android builds, this will return null...
Yaron
2016/05/02 13:25:07
yep, the java side of the bridge needs to be given
| |
| 156 checked_api_support_ = true; | |
| 157 } | |
| 158 return j_api_handler_.obj() != nullptr; | |
| 159 } | |
| 160 | |
| 161 void SafeBrowsingApiHandlerBridge::StartURLCheck( | |
| 162 const SafeBrowsingApiHandler::URLCheckCallbackMeta& callback, | |
| 163 const GURL& url, | |
| 164 const std::vector<SBThreatType>& threat_types) { | |
| 165 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 166 | |
| 167 if (!CheckApiIsSupported()) { | |
| 168 // Mark all requests as safe. Only users who have an old, broken GMSCore or | |
| 169 // have sideloaded Chrome w/o PlayStore should land here. | |
| 170 RunCallbackOnIOThread(new URLCheckCallbackMeta(callback), | |
| 171 SB_THREAT_TYPE_SAFE, ThreatMetadata()); | |
| 172 ReportUmaResult(UMA_STATUS_UNSUPPORTED); | |
| 173 return; | |
| 174 } | |
| 175 | |
| 176 // Make copy on the heap so we can pass the pointer through JNI. | |
| 177 intptr_t callback_id = | |
| 178 reinterpret_cast<intptr_t>(new URLCheckCallbackMeta(callback)); | |
| 179 | |
| 180 DVLOG(1) << "Starting check " << callback_id << " for URL " << url; | |
| 181 | |
| 182 // Default threat types, to support upstream code that doesn't yet set them. | |
| 183 std::vector<SBThreatType> local_threat_types(threat_types); | |
| 184 if (local_threat_types.empty()) { | |
| 185 local_threat_types.push_back(SB_THREAT_TYPE_URL_PHISHING); | |
| 186 local_threat_types.push_back(SB_THREAT_TYPE_URL_MALWARE); | |
| 187 } | |
| 188 | |
| 189 JNIEnv* env = AttachCurrentThread(); | |
| 190 ScopedJavaLocalRef<jstring> j_url = ConvertUTF8ToJavaString(env, url.spec()); | |
| 191 ScopedJavaLocalRef<jintArray> j_threat_types = | |
| 192 SBThreatTypesToJavaArray(env, local_threat_types); | |
| 193 | |
| 194 Java_SafeBrowsingApiBridge_startUriLookup(env, j_api_handler_.obj(), | |
| 195 callback_id, j_url.obj(), | |
| 196 j_threat_types.obj()); | |
| 197 } | |
| 198 | |
| 199 } // namespace safe_browsing | |
| OLD | NEW |