• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "base/android/library_loader/library_loader_hooks.h"
6 
7 #include "base/android/command_line_android.h"
8 #include "base/android/jni_string.h"
9 #include "base/android/library_loader/library_load_from_apk_status_codes.h"
10 #include "base/android/library_loader/library_prefetcher.h"
11 #include "base/at_exit.h"
12 #include "base/metrics/histogram.h"
13 #include "base/metrics/histogram_macros.h"
14 #include "jni/LibraryLoader_jni.h"
15 
16 namespace base {
17 namespace android {
18 
19 namespace {
20 
21 base::AtExitManager* g_at_exit_manager = NULL;
22 const char* g_library_version_number = "";
23 LibraryLoadedHook* g_registration_callback = NULL;
24 NativeInitializationHook* g_native_initialization_hook = NULL;
25 
26 enum RendererHistogramCode {
27   // Renderer load at fixed address success, fail, or not attempted.
28   // Renderers do not attempt to load at at fixed address if on a
29   // low-memory device on which browser load at fixed address has already
30   // failed.
31   LFA_SUCCESS = 0,
32   LFA_BACKOFF_USED = 1,
33   LFA_NOT_ATTEMPTED = 2,
34 
35   // End sentinel, also used as nothing-pending indicator.
36   MAX_RENDERER_HISTOGRAM_CODE = 3,
37   NO_PENDING_HISTOGRAM_CODE = MAX_RENDERER_HISTOGRAM_CODE
38 };
39 
40 enum BrowserHistogramCode {
41   // Non-low-memory random address browser loads.
42   NORMAL_LRA_SUCCESS = 0,
43 
44   // Low-memory browser loads at fixed address, success or fail.
45   LOW_MEMORY_LFA_SUCCESS = 1,
46   LOW_MEMORY_LFA_BACKOFF_USED = 2,
47 
48   MAX_BROWSER_HISTOGRAM_CODE = 3,
49 };
50 
51 RendererHistogramCode g_renderer_histogram_code = NO_PENDING_HISTOGRAM_CODE;
52 
53 // Indicate whether g_library_preloader_renderer_histogram_code is valid
54 bool g_library_preloader_renderer_histogram_code_registered = false;
55 
56 // The return value of NativeLibraryPreloader.loadLibrary() in child processes,
57 // it is initialized to the invalid value which shouldn't showup in UMA report.
58 int g_library_preloader_renderer_histogram_code = -1;
59 
60 // The amount of time, in milliseconds, that it took to load the shared
61 // libraries in the renderer. Set in
62 // RegisterChromiumAndroidLinkerRendererHistogram.
63 long g_renderer_library_load_time_ms = 0;
64 
RecordChromiumAndroidLinkerRendererHistogram()65 void RecordChromiumAndroidLinkerRendererHistogram() {
66   if (g_renderer_histogram_code == NO_PENDING_HISTOGRAM_CODE)
67     return;
68   // Record and release the pending histogram value.
69   UMA_HISTOGRAM_ENUMERATION("ChromiumAndroidLinker.RendererStates",
70                             g_renderer_histogram_code,
71                             MAX_RENDERER_HISTOGRAM_CODE);
72   g_renderer_histogram_code = NO_PENDING_HISTOGRAM_CODE;
73 
74   // Record how long it took to load the shared libraries.
75   UMA_HISTOGRAM_TIMES("ChromiumAndroidLinker.RendererLoadTime",
76       base::TimeDelta::FromMilliseconds(g_renderer_library_load_time_ms));
77 }
78 
RecordLibraryPreloaderRendereHistogram()79 void RecordLibraryPreloaderRendereHistogram() {
80   if (g_library_preloader_renderer_histogram_code_registered) {
81     UMA_HISTOGRAM_SPARSE_SLOWLY(
82         "Android.NativeLibraryPreloader.Result.Renderer",
83         g_library_preloader_renderer_histogram_code);
84   }
85 }
86 
87 } // namespace
88 
RegisterChromiumAndroidLinkerRendererHistogram(JNIEnv * env,const JavaParamRef<jobject> & jcaller,jboolean requested_shared_relro,jboolean load_at_fixed_address_failed,jlong library_load_time_ms)89 static void RegisterChromiumAndroidLinkerRendererHistogram(
90     JNIEnv* env,
91     const JavaParamRef<jobject>& jcaller,
92     jboolean requested_shared_relro,
93     jboolean load_at_fixed_address_failed,
94     jlong library_load_time_ms) {
95   // Note a pending histogram value for later recording.
96   if (requested_shared_relro) {
97     g_renderer_histogram_code = load_at_fixed_address_failed
98                                 ? LFA_BACKOFF_USED : LFA_SUCCESS;
99   } else {
100     g_renderer_histogram_code = LFA_NOT_ATTEMPTED;
101   }
102 
103   g_renderer_library_load_time_ms = library_load_time_ms;
104 }
105 
RecordChromiumAndroidLinkerBrowserHistogram(JNIEnv * env,const JavaParamRef<jobject> & jcaller,jboolean is_using_browser_shared_relros,jboolean load_at_fixed_address_failed,jint library_load_from_apk_status,jlong library_load_time_ms)106 static void RecordChromiumAndroidLinkerBrowserHistogram(
107     JNIEnv* env,
108     const JavaParamRef<jobject>& jcaller,
109     jboolean is_using_browser_shared_relros,
110     jboolean load_at_fixed_address_failed,
111     jint library_load_from_apk_status,
112     jlong library_load_time_ms) {
113   // For low-memory devices, record whether or not we successfully loaded the
114   // browser at a fixed address. Otherwise just record a normal invocation.
115   BrowserHistogramCode histogram_code;
116   if (is_using_browser_shared_relros) {
117     histogram_code = load_at_fixed_address_failed
118                      ? LOW_MEMORY_LFA_BACKOFF_USED : LOW_MEMORY_LFA_SUCCESS;
119   } else {
120     histogram_code = NORMAL_LRA_SUCCESS;
121   }
122   UMA_HISTOGRAM_ENUMERATION("ChromiumAndroidLinker.BrowserStates",
123                             histogram_code,
124                             MAX_BROWSER_HISTOGRAM_CODE);
125 
126   // Record the device support for loading a library directly from the APK file.
127   UMA_HISTOGRAM_ENUMERATION("ChromiumAndroidLinker.LibraryLoadFromApkStatus",
128                             library_load_from_apk_status,
129                             LIBRARY_LOAD_FROM_APK_STATUS_CODES_MAX);
130 
131   // Record how long it took to load the shared libraries.
132   UMA_HISTOGRAM_TIMES("ChromiumAndroidLinker.BrowserLoadTime",
133                       base::TimeDelta::FromMilliseconds(library_load_time_ms));
134 }
135 
RecordLibraryPreloaderBrowserHistogram(JNIEnv * env,const JavaParamRef<jobject> & jcaller,jint status)136 static void RecordLibraryPreloaderBrowserHistogram(
137     JNIEnv* env,
138     const JavaParamRef<jobject>& jcaller,
139     jint status) {
140   UMA_HISTOGRAM_SPARSE_SLOWLY(
141       "Android.NativeLibraryPreloader.Result.Browser",
142       status);
143 }
144 
RegisterLibraryPreloaderRendererHistogram(JNIEnv * env,const JavaParamRef<jobject> & jcaller,jint status)145 static void RegisterLibraryPreloaderRendererHistogram(
146     JNIEnv* env,
147     const JavaParamRef<jobject>& jcaller,
148     jint status) {
149   g_library_preloader_renderer_histogram_code = status;
150   g_library_preloader_renderer_histogram_code_registered = true;
151 }
152 
SetNativeInitializationHook(NativeInitializationHook native_initialization_hook)153 void SetNativeInitializationHook(
154     NativeInitializationHook native_initialization_hook) {
155   g_native_initialization_hook = native_initialization_hook;
156 }
157 
RecordLibraryLoaderRendererHistograms()158 void RecordLibraryLoaderRendererHistograms() {
159   RecordChromiumAndroidLinkerRendererHistogram();
160   RecordLibraryPreloaderRendereHistogram();
161 }
162 
SetLibraryLoadedHook(LibraryLoadedHook * func)163 void SetLibraryLoadedHook(LibraryLoadedHook* func) {
164   g_registration_callback = func;
165 }
166 
InitCommandLine(JNIEnv * env,const JavaParamRef<jobject> & jcaller,const JavaParamRef<jobjectArray> & init_command_line)167 static void InitCommandLine(
168     JNIEnv* env,
169     const JavaParamRef<jobject>& jcaller,
170     const JavaParamRef<jobjectArray>& init_command_line) {
171   InitNativeCommandLineFromJavaArray(env, init_command_line);
172 }
173 
LibraryLoaded(JNIEnv * env,const JavaParamRef<jobject> & jcaller)174 static jboolean LibraryLoaded(JNIEnv* env,
175                               const JavaParamRef<jobject>& jcaller) {
176   if (g_native_initialization_hook && !g_native_initialization_hook()) {
177     return false;
178   }
179   if (g_registration_callback == NULL) {
180     return true;
181   }
182   return g_registration_callback(env, NULL);
183 }
184 
LibraryLoaderExitHook()185 void LibraryLoaderExitHook() {
186   if (g_at_exit_manager) {
187     delete g_at_exit_manager;
188     g_at_exit_manager = NULL;
189   }
190 }
191 
ForkAndPrefetchNativeLibrary(JNIEnv * env,const JavaParamRef<jclass> & clazz)192 static jboolean ForkAndPrefetchNativeLibrary(
193     JNIEnv* env,
194     const JavaParamRef<jclass>& clazz) {
195   return NativeLibraryPrefetcher::ForkAndPrefetchNativeLibrary();
196 }
197 
PercentageOfResidentNativeLibraryCode(JNIEnv * env,const JavaParamRef<jclass> & clazz)198 static jint PercentageOfResidentNativeLibraryCode(
199     JNIEnv* env,
200     const JavaParamRef<jclass>& clazz) {
201   return NativeLibraryPrefetcher::PercentageOfResidentNativeLibraryCode();
202 }
203 
RegisterLibraryLoaderEntryHook(JNIEnv * env)204 bool RegisterLibraryLoaderEntryHook(JNIEnv* env) {
205   return RegisterNativesImpl(env);
206 }
207 
SetVersionNumber(const char * version_number)208 void SetVersionNumber(const char* version_number) {
209   g_library_version_number = strdup(version_number);
210 }
211 
GetVersionNumber(JNIEnv * env,const JavaParamRef<jobject> & jcaller)212 ScopedJavaLocalRef<jstring> GetVersionNumber(
213     JNIEnv* env,
214     const JavaParamRef<jobject>& jcaller) {
215   return ConvertUTF8ToJavaString(env, g_library_version_number);
216 }
217 
GetLibraryProcessType(JNIEnv * env)218 LibraryProcessType GetLibraryProcessType(JNIEnv* env) {
219   return static_cast<LibraryProcessType>(
220       Java_LibraryLoader_getLibraryProcessType(env));
221 }
222 
InitAtExitManager()223 void InitAtExitManager() {
224   g_at_exit_manager = new base::AtExitManager();
225 }
226 
227 }  // namespace android
228 }  // namespace base
229