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.
5 package org
.chromium
.net
;
7 import android
.content
.Context
;
8 import android
.os
.Build
;
9 import android
.os
.ConditionVariable
;
10 import android
.os
.Handler
;
11 import android
.os
.Looper
;
12 import android
.os
.Process
;
13 import android
.util
.Log
;
15 import org
.chromium
.base
.CalledByNative
;
16 import org
.chromium
.base
.JNINamespace
;
17 import org
.chromium
.base
.NativeClassQualifiedName
;
18 import org
.chromium
.base
.annotations
.UsedByReflection
;
20 import java
.util
.concurrent
.Executor
;
21 import java
.util
.concurrent
.atomic
.AtomicInteger
;
24 * UrlRequest context using Chromium HTTP stack implementation.
26 @JNINamespace("cronet")
27 @UsedByReflection("UrlRequestContext.java")
28 public class CronetUrlRequestContext
extends UrlRequestContext
{
29 private static final int LOG_NONE
= 3; // LOG(FATAL), no VLOG.
30 private static final int LOG_DEBUG
= -1; // LOG(FATAL...INFO), VLOG(1)
31 private static final int LOG_VERBOSE
= -2; // LOG(FATAL...INFO), VLOG(2)
32 static final String LOG_TAG
= "ChromiumNetwork";
35 * Synchronize access to mUrlRequestContextAdapter and shutdown routine.
37 private final Object mLock
= new Object();
38 private final ConditionVariable mInitCompleted
= new ConditionVariable(false);
39 private final AtomicInteger mActiveRequestCount
= new AtomicInteger(0);
41 private long mUrlRequestContextAdapter
= 0;
42 private Thread mNetworkThread
;
44 @UsedByReflection("UrlRequestContext.java")
45 public CronetUrlRequestContext(Context context
,
46 UrlRequestContextConfig config
) {
47 CronetLibraryLoader
.ensureInitialized(context
, config
);
48 nativeSetMinLogLevel(getLoggingLevel());
49 mUrlRequestContextAdapter
= nativeCreateRequestContextAdapter(config
.toString());
50 if (mUrlRequestContextAdapter
== 0) {
51 throw new NullPointerException("Context Adapter creation failed.");
54 // Init native Chromium URLRequestContext on main UI thread.
55 Runnable task
= new Runnable() {
58 synchronized (mLock
) {
59 // mUrlRequestContextAdapter is guaranteed to exist until
60 // initialization on main and network threads completes and
61 // initNetworkThread is called back on network thread.
62 nativeInitRequestContextOnMainThread(mUrlRequestContextAdapter
);
66 // Run task immediately or post it to the UI thread.
67 if (Looper
.getMainLooper() == Looper
.myLooper()) {
70 new Handler(Looper
.getMainLooper()).post(task
);
75 public UrlRequest
createRequest(String url
, UrlRequestListener listener
,
77 synchronized (mLock
) {
79 return new CronetUrlRequest(this, mUrlRequestContextAdapter
, url
,
80 UrlRequest
.REQUEST_PRIORITY_MEDIUM
, listener
, executor
);
85 public boolean isEnabled() {
86 return Build
.VERSION
.SDK_INT
>= 14;
90 public String
getVersionString() {
91 return "Cronet/" + Version
.getVersion();
95 public void shutdown() {
96 synchronized (mLock
) {
98 if (mActiveRequestCount
.get() != 0) {
99 throw new IllegalStateException(
100 "Cannot shutdown with active requests.");
102 // Destroying adapter stops the network thread, so it cannot be
103 // called on network thread.
104 if (Thread
.currentThread() == mNetworkThread
) {
105 throw new IllegalThreadStateException(
106 "Cannot shutdown from network thread.");
109 // Wait for init to complete on main and network thread (without lock,
110 // so other thread could access it).
111 mInitCompleted
.block();
113 synchronized (mLock
) {
114 // It is possible that adapter is already destroyed on another thread.
115 if (!haveRequestContextAdapter()) {
118 nativeDestroy(mUrlRequestContextAdapter
);
119 mUrlRequestContextAdapter
= 0;
124 public void startNetLogToFile(String fileName
) {
125 synchronized (mLock
) {
127 nativeStartNetLogToFile(mUrlRequestContextAdapter
, fileName
);
132 public void stopNetLog() {
133 synchronized (mLock
) {
135 nativeStopNetLog(mUrlRequestContextAdapter
);
140 * Mark request as started to prevent shutdown when there are active
143 void onRequestStarted(UrlRequest urlRequest
) {
144 mActiveRequestCount
.incrementAndGet();
148 * Mark request as completed to allow shutdown when there are no active
151 void onRequestDestroyed(UrlRequest urlRequest
) {
152 mActiveRequestCount
.decrementAndGet();
155 long getUrlRequestContextAdapter() {
156 synchronized (mLock
) {
158 return mUrlRequestContextAdapter
;
162 private void checkHaveAdapter() throws IllegalStateException
{
163 if (!haveRequestContextAdapter()) {
164 throw new IllegalStateException("Context is shut down.");
168 private boolean haveRequestContextAdapter() {
169 return mUrlRequestContextAdapter
!= 0;
173 * @return loggingLevel see {@link #LOG_NONE}, {@link #LOG_DEBUG} and
174 * {@link #LOG_VERBOSE}.
176 private int getLoggingLevel() {
178 if (Log
.isLoggable(LOG_TAG
, Log
.VERBOSE
)) {
179 loggingLevel
= LOG_VERBOSE
;
180 } else if (Log
.isLoggable(LOG_TAG
, Log
.DEBUG
)) {
181 loggingLevel
= LOG_DEBUG
;
183 loggingLevel
= LOG_NONE
;
188 @SuppressWarnings("unused")
190 private void initNetworkThread() {
191 synchronized (mLock
) {
192 mNetworkThread
= Thread
.currentThread();
193 mInitCompleted
.open();
195 Thread
.currentThread().setName("ChromiumNet");
196 Process
.setThreadPriority(Process
.THREAD_PRIORITY_BACKGROUND
);
199 // Native methods are implemented in cronet_url_request_context.cc.
200 private static native long nativeCreateRequestContextAdapter(String config
);
202 private static native int nativeSetMinLogLevel(int loggingLevel
);
204 @NativeClassQualifiedName("CronetURLRequestContextAdapter")
205 private native void nativeDestroy(long nativePtr
);
207 @NativeClassQualifiedName("CronetURLRequestContextAdapter")
208 private native void nativeStartNetLogToFile(long nativePtr
,
211 @NativeClassQualifiedName("CronetURLRequestContextAdapter")
212 private native void nativeStopNetLog(long nativePtr
);
214 @NativeClassQualifiedName("CronetURLRequestContextAdapter")
215 private native void nativeInitRequestContextOnMainThread(long nativePtr
);