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