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