Index: components/cronet/android/java/src/org/chromium/net/CronetUrlRequestContext.java |
diff --git a/components/cronet/android/java/src/org/chromium/net/CronetUrlRequestContext.java b/components/cronet/android/java/src/org/chromium/net/CronetUrlRequestContext.java |
index 4c7afc6c0f2278fc2be06da86220681d7d2ee5ac..40c91d2241ada52b7408e0f5eef9273b58c55110 100644 |
--- a/components/cronet/android/java/src/org/chromium/net/CronetUrlRequestContext.java |
+++ b/components/cronet/android/java/src/org/chromium/net/CronetUrlRequestContext.java |
@@ -6,6 +6,9 @@ package org.chromium.net; |
import android.content.Context; |
import android.os.Build; |
+import android.os.ConditionVariable; |
+import android.os.Handler; |
+import android.os.Looper; |
import android.os.Process; |
import android.util.Log; |
@@ -25,29 +28,54 @@ public class CronetUrlRequestContext extends UrlRequestContext { |
private static final int LOG_VERBOSE = -2; // LOG(FATAL...INFO), VLOG(2) |
static final String LOG_TAG = "ChromiumNetwork"; |
+ /** |
+ * Synchronize access to mUrlRequestContextAdapter and shutdown routine. |
+ */ |
+ private final Object mLock = new Object(); |
+ private final ConditionVariable mInitCompleted = new ConditionVariable(false); |
+ private final AtomicInteger mActiveRequestCount = new AtomicInteger(0); |
+ |
private long mUrlRequestContextAdapter = 0; |
private Thread mNetworkThread; |
- private AtomicInteger mActiveRequestCount = new AtomicInteger(0); |
public CronetUrlRequestContext(Context context, |
UrlRequestContextConfig config) { |
+ CronetLibraryLoader.ensureInitialized(context, config); |
nativeSetMinLogLevel(getLoggingLevel()); |
mUrlRequestContextAdapter = nativeCreateRequestContextAdapter( |
context, config.toString()); |
if (mUrlRequestContextAdapter == 0) { |
- throw new NullPointerException("Context Adapter creation failed"); |
+ throw new NullPointerException("Context Adapter creation failed."); |
+ } |
+ |
+ // Init native Chromium URLRequestContext on main UI thread. |
+ Runnable task = new Runnable() { |
+ @Override |
+ public void run() { |
+ synchronized (mLock) { |
+ // mUrlRequestContextAdapter is guaranteed to exist until |
+ // initialization on main and network threads completes and |
+ // initNetworkThread is called back on network thread. |
+ nativeInitRequestContextOnMainThread(mUrlRequestContextAdapter); |
+ } |
+ } |
+ }; |
+ // Run task immediately or post it to the UI thread. |
+ if (Looper.getMainLooper() == Looper.myLooper()) { |
+ task.run(); |
+ } else { |
+ new Handler(Looper.getMainLooper()).post(task); |
} |
} |
@Override |
public UrlRequest createRequest(String url, UrlRequestListener listener, |
Executor executor) { |
- if (mUrlRequestContextAdapter == 0) { |
- throw new IllegalStateException( |
- "Cannot create requests on shutdown context."); |
+ synchronized (mLock) { |
+ checkHaveAdapter(); |
+ return new CronetUrlRequest(this, mUrlRequestContextAdapter, url, |
+ UrlRequest.REQUEST_PRIORITY_MEDIUM, listener, executor); |
} |
- return new CronetUrlRequest(this, mUrlRequestContextAdapter, url, |
- UrlRequest.REQUEST_PRIORITY_MEDIUM, listener, executor); |
} |
@Override |
@@ -62,28 +90,47 @@ public class CronetUrlRequestContext extends UrlRequestContext { |
@Override |
public void shutdown() { |
- if (mActiveRequestCount.get() != 0) { |
- throw new IllegalStateException( |
- "Cannot shutdown with active requests."); |
+ synchronized (mLock) { |
+ checkHaveAdapter(); |
+ if (mActiveRequestCount.get() != 0) { |
+ throw new IllegalStateException( |
+ "Cannot shutdown with active requests."); |
+ } |
+ // Destroying adapter stops the network thread, so it cannot be |
+ // called on network thread. |
+ if (Thread.currentThread() == mNetworkThread) { |
+ throw new IllegalThreadStateException( |
+ "Cannot shutdown from network thread."); |
+ } |
} |
- // Destroying adapter stops the network thread, so it cannot be called |
- // on network thread. |
- if (Thread.currentThread() == mNetworkThread) { |
- throw new IllegalThreadStateException( |
- "Cannot shutdown from network thread."); |
+ // Wait for init to complete on main and network thread (without lock, |
+ // so other thread could access it). |
+ mInitCompleted.block(); |
+ |
+ synchronized (mLock) { |
+ // It is possible that adapter is already destroyed on another thread. |
+ if (!haveRequestContextAdapter()) { |
+ return; |
+ } |
+ nativeDestroyRequestContextAdapter(mUrlRequestContextAdapter); |
+ mUrlRequestContextAdapter = 0; |
} |
- nativeDestroyRequestContextAdapter(mUrlRequestContextAdapter); |
- mUrlRequestContextAdapter = 0; |
} |
@Override |
public void startNetLogToFile(String fileName) { |
- nativeStartNetLogToFile(mUrlRequestContextAdapter, fileName); |
+ synchronized (mLock) { |
+ checkHaveAdapter(); |
+ nativeStartNetLogToFile(mUrlRequestContextAdapter, fileName); |
+ } |
} |
@Override |
public void stopNetLog() { |
- nativeStopNetLog(mUrlRequestContextAdapter); |
+ synchronized (mLock) { |
+ checkHaveAdapter(); |
+ nativeStopNetLog(mUrlRequestContextAdapter); |
+ } |
} |
/** |
@@ -103,10 +150,20 @@ public class CronetUrlRequestContext extends UrlRequestContext { |
} |
long getUrlRequestContextAdapter() { |
- if (mUrlRequestContextAdapter == 0) { |
- throw new IllegalStateException("Context Adapter is destroyed."); |
+ synchronized (mLock) { |
+ checkHaveAdapter(); |
+ return mUrlRequestContextAdapter; |
} |
- return mUrlRequestContextAdapter; |
+ } |
+ |
+ private void checkHaveAdapter() throws IllegalStateException { |
+ if (!haveRequestContextAdapter()) { |
+ throw new IllegalStateException("Context is shut down."); |
+ } |
+ } |
+ |
+ private boolean haveRequestContextAdapter() { |
+ return mUrlRequestContextAdapter != 0; |
} |
/** |
@@ -128,7 +185,10 @@ public class CronetUrlRequestContext extends UrlRequestContext { |
@SuppressWarnings("unused") |
@CalledByNative |
private void initNetworkThread() { |
- mNetworkThread = Thread.currentThread(); |
+ synchronized (mLock) { |
+ mNetworkThread = Thread.currentThread(); |
+ mInitCompleted.open(); |
+ } |
Thread.currentThread().setName("ChromiumNet"); |
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); |
} |
@@ -146,4 +206,7 @@ public class CronetUrlRequestContext extends UrlRequestContext { |
private native void nativeStopNetLog(long urlRequestContextAdapter); |
private native int nativeSetMinLogLevel(int loggingLevel); |
+ |
+ private native void nativeInitRequestContextOnMainThread( |
+ long urlRequestContextAdapter); |
} |