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/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