Home | History | Annotate | Download | only in library_loader
      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