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