1 // Copyright 2014 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 "components/cronet/android/org_chromium_net_UrlRequestContext.h" 6 7 #include <string> 8 9 #include "base/android/jni_android.h" 10 #include "base/android/jni_string.h" 11 #include "base/json/json_reader.h" 12 #include "base/memory/scoped_ptr.h" 13 #include "base/metrics/statistics_recorder.h" 14 #include "base/values.h" 15 #include "components/cronet/android/org_chromium_net_UrlRequest.h" 16 #include "components/cronet/android/url_request_context_peer.h" 17 #include "components/cronet/android/url_request_peer.h" 18 #include "components/cronet/url_request_context_config.h" 19 #include "jni/UrlRequestContext_jni.h" 20 21 // Version of this build of Chromium NET. 22 #define CHROMIUM_NET_VERSION "1" 23 24 namespace { 25 26 const char kVersion[] = CHROMIUM_VERSION "/" CHROMIUM_NET_VERSION; 27 28 // Delegate of URLRequestContextPeer that delivers callbacks to the Java layer. 29 class JniURLRequestContextPeerDelegate 30 : public cronet::URLRequestContextPeer::URLRequestContextPeerDelegate { 31 public: 32 JniURLRequestContextPeerDelegate(JNIEnv* env, jobject owner) 33 : owner_(env->NewGlobalRef(owner)) { 34 } 35 36 virtual void OnContextInitialized( 37 cronet::URLRequestContextPeer* context) OVERRIDE { 38 JNIEnv* env = base::android::AttachCurrentThread(); 39 cronet::Java_UrlRequestContext_initNetworkThread(env, owner_); 40 // TODO(dplotnikov): figure out if we need to detach from the thread. 41 // The documentation says we should detach just before the thread exits. 42 } 43 44 protected: 45 virtual ~JniURLRequestContextPeerDelegate() { 46 JNIEnv* env = base::android::AttachCurrentThread(); 47 env->DeleteGlobalRef(owner_); 48 } 49 50 private: 51 jobject owner_; 52 }; 53 54 } // namespace 55 56 namespace cronet { 57 58 // Explicitly register static JNI functions. 59 bool UrlRequestContextRegisterJni(JNIEnv* env) { 60 return RegisterNativesImpl(env); 61 } 62 63 static jstring GetVersion(JNIEnv* env, jclass unused) { 64 return base::android::ConvertUTF8ToJavaString(env, kVersion).Release(); 65 } 66 67 // Sets global user-agent to be used for all subsequent requests. 68 static jlong CreateRequestContextPeer(JNIEnv* env, 69 jobject object, 70 jobject context, 71 jstring user_agent, 72 jint log_level, 73 jstring config) { 74 std::string user_agent_string = 75 base::android::ConvertJavaStringToUTF8(env, user_agent); 76 77 std::string config_string = 78 base::android::ConvertJavaStringToUTF8(env, config); 79 80 scoped_ptr<base::Value> config_value(base::JSONReader::Read(config_string)); 81 if (!config_value || !config_value->IsType(base::Value::TYPE_DICTIONARY)) { 82 DLOG(ERROR) << "Bad JSON: " << config_string; 83 return 0; 84 } 85 86 scoped_ptr<URLRequestContextConfig> context_config( 87 new URLRequestContextConfig()); 88 base::JSONValueConverter<URLRequestContextConfig> converter; 89 if (!converter.Convert(*config_value, context_config.get())) { 90 DLOG(ERROR) << "Bad Config: " << config_value; 91 return 0; 92 } 93 94 // Set application context. 95 base::android::ScopedJavaLocalRef<jobject> scoped_context(env, context); 96 base::android::InitApplicationContext(env, scoped_context); 97 98 int logging_level = log_level; 99 100 // TODO(dplotnikov): set application context. 101 URLRequestContextPeer* peer = new URLRequestContextPeer( 102 new JniURLRequestContextPeerDelegate(env, object), 103 user_agent_string, 104 logging_level, 105 kVersion); 106 peer->AddRef(); // Hold onto this ref-counted object. 107 peer->Initialize(context_config.Pass()); 108 return reinterpret_cast<jlong>(peer); 109 } 110 111 // Releases native objects. 112 static void ReleaseRequestContextPeer(JNIEnv* env, 113 jobject object, 114 jlong urlRequestContextPeer) { 115 URLRequestContextPeer* peer = 116 reinterpret_cast<URLRequestContextPeer*>(urlRequestContextPeer); 117 // TODO(mef): Revisit this from thread safety point of view: Can we delete a 118 // thread while running on that thread? 119 // URLRequestContextPeer is a ref-counted object, and may have pending tasks, 120 // so we need to release it instead of deleting here. 121 peer->Release(); 122 } 123 124 // Starts recording statistics. 125 static void InitializeStatistics(JNIEnv* env, jobject jcaller) { 126 base::StatisticsRecorder::Initialize(); 127 } 128 129 // Gets current statistics with |filter| as a substring as JSON text (an empty 130 // |filter| will include all registered histograms). 131 static jstring GetStatisticsJSON(JNIEnv* env, jobject jcaller, jstring filter) { 132 std::string query = base::android::ConvertJavaStringToUTF8(env, filter); 133 std::string json = base::StatisticsRecorder::ToJSON(query); 134 return base::android::ConvertUTF8ToJavaString(env, json).Release(); 135 } 136 137 // Starts recording NetLog into file with |fileName|. 138 static void StartNetLogToFile(JNIEnv* env, 139 jobject jcaller, 140 jlong urlRequestContextPeer, 141 jstring fileName) { 142 URLRequestContextPeer* peer = 143 reinterpret_cast<URLRequestContextPeer*>(urlRequestContextPeer); 144 std::string file_name = base::android::ConvertJavaStringToUTF8(env, fileName); 145 peer->StartNetLogToFile(file_name); 146 } 147 148 // Stops recording NetLog. 149 static void StopNetLog(JNIEnv* env, 150 jobject jcaller, 151 jlong urlRequestContextPeer) { 152 URLRequestContextPeer* peer = 153 reinterpret_cast<URLRequestContextPeer*>(urlRequestContextPeer); 154 peer->StopNetLog(); 155 } 156 157 } // namespace cronet 158