- add sources.
[platform/framework/web/crosswalk.git] / src / content / public / android / java / src / org / chromium / content / app / LibraryLoader.java
1 // Copyright (c) 2012 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 package org.chromium.content.app;
6
7 import android.text.TextUtils;
8 import android.util.Log;
9
10 import org.chromium.base.JNINamespace;
11 import org.chromium.base.SysUtils;
12 import org.chromium.content.common.CommandLine;
13 import org.chromium.content.common.ProcessInitException;
14 import org.chromium.content.common.ResultCodes;
15 import org.chromium.content.common.TraceEvent;
16
17 /**
18  * This class provides functionality to load and register the native libraries.
19  * Callers are allowed to separate loading the libraries from initializing them.
20  * This may be an advantage for Android Webview, where the libraries can be loaded
21  * by the zygote process, but then needs per process initialization after the
22  * application processes are forked from the zygote process.
23  *
24  * The libraries may be loaded and initialized from any thread. Synchronization
25  * primitives are used to ensure that overlapping requests from different
26  * threads are handled sequentially.
27  *
28  * See also content/app/android/library_loader_hooks.cc, which contains
29  * the native counterpart to this class.
30  */
31 @JNINamespace("content")
32 public class LibraryLoader {
33     private static final String TAG = "LibraryLoader";
34
35     // Guards all access to the libraries
36     private static final Object sLock = new Object();
37
38     // One-way switch becomes true when the libraries are loaded.
39     private static boolean sLoaded = false;
40
41     // One-way switch becomes true when the libraries are initialized (
42     // by calling nativeLibraryLoaded, which forwards to LibraryLoaded(...) in
43     // library_loader_hooks.cc).
44     private static boolean sInitialized = false;
45
46     // TODO(cjhopman): Remove this once it's unused.
47     /**
48      * Doesn't do anything.
49      */
50     @Deprecated
51     public static void setLibraryToLoad(String library) {
52     }
53
54     /**
55      *  This method blocks until the library is fully loaded and initialized.
56      */
57     public static void ensureInitialized() throws ProcessInitException {
58         synchronized (sLock) {
59             if (sInitialized) {
60                 // Already initialized, nothing to do.
61                 return;
62             }
63             loadAlreadyLocked();
64             initializeAlreadyLocked(CommandLine.getJavaSwitchesOrNull());
65         }
66     }
67
68     /**
69      * Checks if library is fully loaded and initialized.
70      */
71     public static boolean isInitialized() {
72         synchronized (sLock) {
73             return sInitialized;
74         }
75     }
76
77     /**
78      * Loads the library and blocks until the load completes. The caller is responsible
79      * for subsequently calling ensureInitialized().
80      * May be called on any thread, but should only be called once. Note the thread
81      * this is called on will be the thread that runs the native code's static initializers.
82      * See the comment in doInBackground() for more considerations on this.
83      *
84      * @throws ProcessInitException if the native library failed to load.
85      */
86     public static void loadNow() throws ProcessInitException {
87         synchronized (sLock) {
88             loadAlreadyLocked();
89         }
90     }
91
92
93     /**
94      * initializes the library here and now: must be called on the thread that the
95      * native will call its "main" thread. The library must have previously been
96      * loaded with loadNow.
97      * @param initCommandLine The command line arguments that native command line will
98      * be initialized with.
99      */
100     static void initialize(String[] initCommandLine) throws ProcessInitException {
101         synchronized (sLock) {
102             initializeAlreadyLocked(initCommandLine);
103         }
104     }
105
106
107     // Invoke System.loadLibrary(...), triggering JNI_OnLoad in native code
108     private static void loadAlreadyLocked() throws ProcessInitException {
109         try {
110             if (!sLoaded) {
111                 assert !sInitialized;
112
113                 long startTime = System.currentTimeMillis();
114                 boolean useContentLinker = Linker.isUsed();
115
116                 if (useContentLinker)
117                     Linker.prepareLibraryLoad();
118
119                 for (String library : NativeLibraries.libraries) {
120                     Log.i(TAG, "Loading: " + library);
121                     if (useContentLinker)
122                         Linker.loadLibrary(library);
123                     else
124                         System.loadLibrary(library);
125                 }
126                 if (useContentLinker)
127                     Linker.finishLibraryLoad();
128                 long stopTime = System.currentTimeMillis();
129                 Log.i(TAG, String.format("Time to load native libraries: %d ms (timestamps %d-%d)",
130                                          stopTime - startTime,
131                                          startTime % 10000,
132                                          stopTime % 10000));
133                 sLoaded = true;
134             }
135         } catch (UnsatisfiedLinkError e) {
136             throw new ProcessInitException(ResultCodes.RESULT_CODE_NATIVE_LIBRARY_LOAD_FAILED, e);
137         }
138     }
139
140
141     // Invoke content::LibraryLoaded in library_loader_hooks.cc
142     private static void initializeAlreadyLocked(String[] initCommandLine)
143             throws ProcessInitException {
144         if (sInitialized) {
145             return;
146         }
147         int resultCode = nativeLibraryLoaded(initCommandLine);
148         if (resultCode != 0) {
149             Log.e(TAG, "error calling nativeLibraryLoaded");
150             throw new ProcessInitException(resultCode);
151         }
152         // From this point on, native code is ready to use and checkIsReady()
153         // shouldn't complain from now on (and in fact, it's used by the
154         // following calls).
155         sInitialized = true;
156         CommandLine.enableNativeProxy();
157         TraceEvent.setEnabledToMatchNative();
158         // Record histogram for the content linker.
159         if (Linker.isUsed())
160           nativeRecordContentAndroidLinkerHistogram(Linker.loadAtFixedAddressFailed(),
161                                                     SysUtils.isLowEndDevice());
162     }
163
164     // This is the only method that is registered during System.loadLibrary. We then call it
165     // to register everything else. This process is called "initialization".
166     // This method will be mapped (by generated code) to the LibraryLoaded
167     // definition in content/app/android/library_loader_hooks.cc.
168     //
169     // Return 0 on success, otherwise return the error code from
170     // content/public/common/result_codes.h.
171     private static native int nativeLibraryLoaded(String[] initCommandLine);
172
173     // Method called to record statistics about the content linker operation,
174     // i.e. whether the library failed to be loaded at a fixed address, and
175     // whether the device is 'low-memory'.
176     private static native void nativeRecordContentAndroidLinkerHistogram(
177          boolean loadedAtFixedAddressFailed,
178          boolean isLowMemoryDevice);
179 }