• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 package org.chromium.net.impl;
6 
7 import android.content.Context;
8 import android.os.ConditionVariable;
9 import android.os.Handler;
10 import android.os.HandlerThread;
11 import android.os.Looper;
12 import android.os.Process;
13 
14 import androidx.annotation.VisibleForTesting;
15 
16 import org.chromium.base.ContextUtils;
17 import org.chromium.base.Log;
18 import org.chromium.base.annotations.CalledByNative;
19 import org.chromium.base.annotations.JNINamespace;
20 import org.chromium.base.annotations.NativeMethods;
21 import org.chromium.net.NetworkChangeNotifier;
22 
23 /**
24  * CronetLibraryLoader loads and initializes native library on init thread.
25  */
26 @JNINamespace("cronet")
27 @VisibleForTesting
28 public class CronetLibraryLoader {
29     // Synchronize initialization.
30     private static final Object sLoadLock = new Object();
31     private static final String LIBRARY_NAME = "cronet." + ImplVersion.getCronetVersion();
32     private static final String TAG = CronetLibraryLoader.class.getSimpleName();
33     // Thread used for initialization work and processing callbacks for
34     // long-lived global singletons. This thread lives forever as things like
35     // the global singleton NetworkChangeNotifier live on it and are never killed.
36     private static final HandlerThread sInitThread = new HandlerThread("CronetInit");
37     // Has library loading commenced?  Setting guarded by sLoadLock.
38     private static volatile boolean sLibraryLoaded = false;
39     // Has ensureInitThreadInitialized() completed?
40     private static volatile boolean sInitThreadInitDone;
41     // Block calling native methods until this ConditionVariable opens to indicate loadLibrary()
42     // is completed and native methods have been registered.
43     private static final ConditionVariable sWaitForLibLoad = new ConditionVariable();
44 
45     /**
46      * Ensure that native library is loaded and initialized. Can be called from
47      * any thread, the load and initialization is performed on init thread.
48      */
ensureInitialized( Context applicationContext, final CronetEngineBuilderImpl builder)49     public static void ensureInitialized(
50             Context applicationContext, final CronetEngineBuilderImpl builder) {
51         synchronized (sLoadLock) {
52             if (!sInitThreadInitDone) {
53                 ContextUtils.initApplicationContext(applicationContext);
54                 if (!sInitThread.isAlive()) {
55                     sInitThread.start();
56                 }
57                 postToInitThread(CronetLibraryLoader::ensureInitializedOnInitThread);
58             }
59             if (!sLibraryLoaded) {
60                 System.loadLibrary(LIBRARY_NAME);
61                 String implVersion = ImplVersion.getCronetVersion();
62                 if (!implVersion.equals(CronetLibraryLoaderJni.get().getCronetVersion())) {
63                     throw new RuntimeException(String.format("Expected Cronet version number %s, "
64                                     + "actual version number %s.",
65                             implVersion, CronetLibraryLoaderJni.get().getCronetVersion()));
66                 }
67                 Log.i(TAG, "Cronet version: %s, arch: %s", implVersion,
68                         System.getProperty("os.arch"));
69                 sLibraryLoaded = true;
70                 sWaitForLibLoad.open();
71             }
72         }
73     }
74 
75     /**
76      * Returns {@code true} if running on the initialization thread.
77      */
onInitThread()78     private static boolean onInitThread() {
79         return sInitThread.getLooper() == Looper.myLooper();
80     }
81 
82     /**
83      * Ensure that the init thread initialization has completed. Can only be called from
84      * the init thread. Ensures that the NetworkChangeNotifier is initialzied and the
85      * init thread native MessageLoop is initialized.
86      */
ensureInitializedOnInitThread()87     static void ensureInitializedOnInitThread() {
88         assert onInitThread();
89         if (sInitThreadInitDone) {
90             return;
91         }
92         NetworkChangeNotifier.init();
93         // Registers to always receive network notifications. Note
94         // that this call is fine for Cronet because Cronet
95         // embedders do not have API access to create network change
96         // observers. Existing observers in the net stack do not
97         // perform expensive work.
98         NetworkChangeNotifier.registerToReceiveNotificationsAlways();
99         // Wait for loadLibrary() to complete so JNI is registered.
100         sWaitForLibLoad.block();
101 
102         assert sLibraryLoaded;
103         // registerToReceiveNotificationsAlways() is called before the native
104         // NetworkChangeNotifierAndroid is created, so as to avoid receiving
105         // the undesired initial network change observer notification, which
106         // will cause active requests to fail with ERR_NETWORK_CHANGED.
107         CronetLibraryLoaderJni.get().cronetInitOnInitThread();
108         sInitThreadInitDone = true;
109     }
110 
111     /**
112      * Run {@code r} on the initialization thread.
113      */
postToInitThread(Runnable r)114     public static void postToInitThread(Runnable r) {
115         if (onInitThread()) {
116             r.run();
117         } else {
118             new Handler(sInitThread.getLooper()).post(r);
119         }
120     }
121 
122     /**
123      * Called from native library to get default user agent constructed
124      * using application context. May be called on any thread.
125      *
126      * Expects that ContextUtils.initApplicationContext() was called already
127      * either by some testing framework or an embedder constructing a Java
128      * CronetEngine via CronetEngine.Builder.build().
129      */
130     @CalledByNative
getDefaultUserAgent()131     private static String getDefaultUserAgent() {
132         return UserAgent.getDefault();
133     }
134 
135     /**
136      * Called from native library to ensure that library is initialized.
137      * May be called on any thread, but initialization is performed on
138      * this.sInitThread.
139      *
140      * Expects that ContextUtils.initApplicationContext() was called already
141      * either by some testing framework or an embedder constructing a Java
142      * CronetEngine via CronetEngine.Builder.build().
143      *
144      * TODO(mef): In the long term this should be changed to some API with
145      * lower overhead like CronetEngine.Builder.loadNativeCronet().
146      */
147     @CalledByNative
ensureInitializedFromNative()148     private static void ensureInitializedFromNative() {
149         // Called by native, so native library is already loaded.
150         // It is possible that loaded native library is not regular
151         // "libcronet.xyz.so" but test library that statically links
152         // native code like "libcronet_unittests.so".
153         synchronized (sLoadLock) {
154             sLibraryLoaded = true;
155             sWaitForLibLoad.open();
156         }
157 
158         // The application context must already be initialized
159         // using ContextUtils.initApplicationContext().
160         Context applicationContext = ContextUtils.getApplicationContext();
161         assert applicationContext != null;
162         ensureInitialized(applicationContext, null);
163     }
164 
165     @CalledByNative
setNetworkThreadPriorityOnNetworkThread(int priority)166     private static void setNetworkThreadPriorityOnNetworkThread(int priority) {
167         Process.setThreadPriority(priority);
168     }
169 
170     @NativeMethods
171     interface Natives {
172         // Native methods are implemented in cronet_library_loader.cc.
cronetInitOnInitThread()173         void cronetInitOnInitThread();
174 
getCronetVersion()175         String getCronetVersion();
176     }
177 }
178