| Index: base/native_library_win.cc
|
| diff --git a/base/native_library_win.cc b/base/native_library_win.cc
|
| index 64c7380f173247c28b78e1f339b963d7374cf83f..68ff3d1f95d53a9fd289f4fc3268591247448dcd 100644
|
| --- a/base/native_library_win.cc
|
| +++ b/base/native_library_win.cc
|
| @@ -7,6 +7,7 @@
|
| #include <windows.h>
|
|
|
| #include "base/files/file_util.h"
|
| +#include "base/metrics/histogram_macros.h"
|
| #include "base/strings/string_util.h"
|
| #include "base/strings/stringprintf.h"
|
| #include "base/strings/utf_string_conversions.h"
|
| @@ -14,16 +15,108 @@
|
|
|
| namespace base {
|
|
|
| -typedef HMODULE (WINAPI* LoadLibraryFunction)(const wchar_t* file_name);
|
| +using AddDllDirectory = HMODULE (*)(PCWSTR new_directory);
|
|
|
| namespace {
|
| +// This enum is used to back an UMA histogram, and should therefore be treated
|
| +// as append-only.
|
| +enum LoadLibraryResult {
|
| + // LoadLibraryExW API/flags are available and the call succeeds.
|
| + SUCCEED = 0,
|
| + // LoadLibraryExW API/flags are availabe to use but the call fails, then
|
| + // LoadLibraryW is used and succeeds.
|
| + FAIL_AND_SUCCEED,
|
| + // LoadLibraryExW API/flags are availabe to use but the call fails, then
|
| + // LoadLibraryW is used but fails as well.
|
| + FAIL_AND_FAIL,
|
| + // LoadLibraryExW API/flags are unavailabe to use, then LoadLibraryW is used
|
| + // and succeeds.
|
| + UNAVAILABLE_AND_SUCCEED,
|
| + // LoadLibraryExW API/flags are unavailabe to use, then LoadLibraryW is used
|
| + // but fails.
|
| + UNAVAILABLE_AND_FAIL,
|
| + // Add new items before this one, always keep this one at the end.
|
| + END
|
| +};
|
| +
|
| +// A helper method to log library loading result to UMA.
|
| +void LogLibrarayLoadResultToUMA(LoadLibraryResult result) {
|
| + UMA_HISTOGRAM_ENUMERATION("LibraryLoader.LoadNativeLibraryWindows", result,
|
| + LoadLibraryResult::END);
|
| +}
|
| +
|
| +// A helper method to check if AddDllDirectory method is available, thus
|
| +// LOAD_LIBRARY_SEARCH_* flags are available on systems.
|
| +bool AreSearchFlagsAvailable() {
|
| + // The LOAD_LIBRARY_SEARCH_* flags are available on systems that have
|
| + // KB2533623 installed. To determine whether the flags are available, use
|
| + // GetProcAddress to get the address of the AddDllDirectory,
|
| + // RemoveDllDirectory, or SetDefaultDllDirectories function. If GetProcAddress
|
| + // succeeds, the LOAD_LIBRARY_SEARCH_* flags can be used with LoadLibraryEx.
|
| + // https://msdn.microsoft.com/en-us/library/windows/desktop/ms684179(v=vs.85).aspx
|
| + // The LOAD_LIBRARY_SEARCH_* flags are used in the LoadNativeLibraryHelper
|
| + // method.
|
| + auto add_dll_dir_func = reinterpret_cast<AddDllDirectory>(
|
| + GetProcAddress(GetModuleHandle(L"kernel32.dll"), "AddDllDirectory"));
|
| + return !!add_dll_dir_func;
|
| +}
|
| +
|
| +// A helper method to encode the library loading result to enum
|
| +// LoadLibraryResult.
|
| +LoadLibraryResult GetLoadLibraryResult(bool are_search_flags_available,
|
| + bool has_load_library_succeeded) {
|
| + LoadLibraryResult result;
|
| + if (are_search_flags_available) {
|
| + if (has_load_library_succeeded)
|
| + result = LoadLibraryResult::FAIL_AND_SUCCEED;
|
| + else
|
| + result = LoadLibraryResult::FAIL_AND_FAIL;
|
| + } else if (has_load_library_succeeded) {
|
| + result = LoadLibraryResult::UNAVAILABLE_AND_SUCCEED;
|
| + } else {
|
| + result = LoadLibraryResult::UNAVAILABLE_AND_FAIL;
|
| + }
|
| + return result;
|
| +}
|
|
|
| NativeLibrary LoadNativeLibraryHelper(const FilePath& library_path,
|
| - LoadLibraryFunction load_library_api,
|
| NativeLibraryLoadError* error) {
|
| // LoadLibrary() opens the file off disk.
|
| ThreadRestrictions::AssertIOAllowed();
|
|
|
| + HMODULE module = nullptr;
|
| +
|
| + // This variable records the library loading result.
|
| + LoadLibraryResult load_library_result = LoadLibraryResult::SUCCEED;
|
| +
|
| + bool are_search_flags_available = AreSearchFlagsAvailable();
|
| + if (are_search_flags_available) {
|
| + // LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR flag is needed to search the library
|
| + // directory as the library may have dependencies on DLLs in this
|
| + // directory.
|
| + module = ::LoadLibraryExW(
|
| + library_path.value().c_str(), nullptr,
|
| + LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
|
| + // If LoadLibraryExW succeeds, log this metric and return.
|
| + if (module) {
|
| + LogLibrarayLoadResultToUMA(load_library_result);
|
| + return module;
|
| + }
|
| + // GetLastError() needs to be called immediately after
|
| + // LoadLibraryExW call.
|
| + if (error)
|
| + error->code = GetLastError();
|
| + }
|
| +
|
| + // If LoadLibraryExW API/flags are unavailable or API call fails, try
|
| + // LoadLibraryW API.
|
| + // TODO(chengx): Currently, if LoadLibraryExW API call fails, LoadLibraryW is
|
| + // still tried. We should strictly prefer the LoadLibraryExW over the
|
| + // LoadLibraryW if LoadLibraryW is statistically showing no extra benefits. If
|
| + // UMA metric shows that FAIL_AND_FAIL is the primary failure mode and/or
|
| + // FAIL_AND_SUCCESS is close to zero, we should remove this fallback.
|
| + // (http://crbug.com/701944)
|
| +
|
| // Switch the current directory to the library directory as the library
|
| // may have dependencies on DLLs in this directory.
|
| bool restore_directory = false;
|
| @@ -36,18 +129,21 @@ NativeLibrary LoadNativeLibraryHelper(const FilePath& library_path,
|
| }
|
| }
|
|
|
| - HMODULE module = (*load_library_api)(library_path.value().c_str());
|
| - if (!module && error) {
|
| - // GetLastError() needs to be called immediately after |load_library_api|.
|
| + module = ::LoadLibraryW(library_path.value().c_str());
|
| +
|
| + // GetLastError() needs to be called immediately after LoadLibraryW call.
|
| + if (!module && error)
|
| error->code = GetLastError();
|
| - }
|
|
|
| if (restore_directory)
|
| SetCurrentDirectory(current_directory);
|
|
|
| + // Get the library loading result and log it to UMA.
|
| + LogLibrarayLoadResultToUMA(
|
| + GetLoadLibraryResult(are_search_flags_available, !!module));
|
| +
|
| return module;
|
| }
|
| -
|
| } // namespace
|
|
|
| std::string NativeLibraryLoadError::ToString() const {
|
| @@ -58,16 +154,7 @@ std::string NativeLibraryLoadError::ToString() const {
|
| NativeLibrary LoadNativeLibraryWithOptions(const FilePath& library_path,
|
| const NativeLibraryOptions& options,
|
| NativeLibraryLoadError* error) {
|
| - return LoadNativeLibraryHelper(library_path, LoadLibraryW, error);
|
| -}
|
| -
|
| -NativeLibrary LoadNativeLibraryDynamically(const FilePath& library_path) {
|
| - typedef HMODULE (WINAPI* LoadLibraryFunction)(const wchar_t* file_name);
|
| -
|
| - LoadLibraryFunction load_library = reinterpret_cast<LoadLibraryFunction>(
|
| - GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryW"));
|
| -
|
| - return LoadNativeLibraryHelper(library_path, load_library, NULL);
|
| + return LoadNativeLibraryHelper(library_path, error);
|
| }
|
|
|
| // static
|
|
|