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 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 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 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 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 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 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 153 void SetNativeInitializationHook( 154 NativeInitializationHook native_initialization_hook) { 155 g_native_initialization_hook = native_initialization_hook; 156 } 157 158 void RecordLibraryLoaderRendererHistograms() { 159 RecordChromiumAndroidLinkerRendererHistogram(); 160 RecordLibraryPreloaderRendereHistogram(); 161 } 162 163 void SetLibraryLoadedHook(LibraryLoadedHook* func) { 164 g_registration_callback = func; 165 } 166 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 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 185 void LibraryLoaderExitHook() { 186 if (g_at_exit_manager) { 187 delete g_at_exit_manager; 188 g_at_exit_manager = NULL; 189 } 190 } 191 192 static jboolean ForkAndPrefetchNativeLibrary( 193 JNIEnv* env, 194 const JavaParamRef<jclass>& clazz) { 195 return NativeLibraryPrefetcher::ForkAndPrefetchNativeLibrary(); 196 } 197 198 static jint PercentageOfResidentNativeLibraryCode( 199 JNIEnv* env, 200 const JavaParamRef<jclass>& clazz) { 201 return NativeLibraryPrefetcher::PercentageOfResidentNativeLibraryCode(); 202 } 203 204 bool RegisterLibraryLoaderEntryHook(JNIEnv* env) { 205 return RegisterNativesImpl(env); 206 } 207 208 void SetVersionNumber(const char* version_number) { 209 g_library_version_number = strdup(version_number); 210 } 211 212 ScopedJavaLocalRef<jstring> GetVersionNumber( 213 JNIEnv* env, 214 const JavaParamRef<jobject>& jcaller) { 215 return ConvertUTF8ToJavaString(env, g_library_version_number); 216 } 217 218 LibraryProcessType GetLibraryProcessType(JNIEnv* env) { 219 return static_cast<LibraryProcessType>( 220 Java_LibraryLoader_getLibraryProcessType(env)); 221 } 222 223 void InitAtExitManager() { 224 g_at_exit_manager = new base::AtExitManager(); 225 } 226 227 } // namespace android 228 } // namespace base 229