Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/native_library.h" | 5 #include "base/native_library.h" |
| 6 | 6 |
| 7 #include <windows.h> | 7 #include <windows.h> |
| 8 | 8 |
| 9 #include "base/files/file_util.h" | 9 #include "base/files/file_util.h" |
| 10 #include "base/metrics/histogram_macros.h" | |
| 10 #include "base/strings/string_util.h" | 11 #include "base/strings/string_util.h" |
| 11 #include "base/strings/stringprintf.h" | 12 #include "base/strings/stringprintf.h" |
| 12 #include "base/strings/utf_string_conversions.h" | 13 #include "base/strings/utf_string_conversions.h" |
| 13 #include "base/threading/thread_restrictions.h" | 14 #include "base/threading/thread_restrictions.h" |
| 14 | 15 |
| 15 namespace base { | 16 namespace base { |
| 16 | 17 |
| 17 typedef HMODULE (WINAPI* LoadLibraryFunction)(const wchar_t* file_name); | 18 typedef HMODULE(WINAPI* AddDllDirectory)(PCWSTR NewDirectory); |
| 18 | 19 |
| 19 namespace { | 20 namespace { |
| 21 enum LoadLibraryResult { | |
|
Ilya Sherman
2017/03/14 18:42:28
nit: Please document that this is used to back an
chengx
2017/03/14 23:08:30
Done.
| |
| 22 // LoadLibraryExW API/flags are available and the call succeeds. | |
| 23 SUCCEED = 0, | |
| 24 // LoadLibraryExW API/flags are availabe to use but the call fails, then | |
| 25 // LoadLibraryW is used and succeeds. | |
| 26 FAIL_AND_SUCCEED, | |
| 27 // LoadLibraryExW API/flags are availabe to use but the call fails, then | |
| 28 // LoadLibraryW is used but fails as well. | |
| 29 FAIL_AND_FAIL, | |
| 30 // LoadLibraryExW API/flags are unavailabe to use, then LoadLibraryW is used | |
| 31 // and succeeds. | |
| 32 UNAVAILABLE_AND_SUCCEED, | |
| 33 // LoadLibraryExW API/flags are unavailabe to use, then LoadLibraryW is used | |
| 34 // but fails. | |
| 35 UNAVAILABLE_AND_FAIL, | |
| 36 // Add new items before this one, always keep this one at the end. | |
| 37 END | |
| 38 }; | |
| 39 | |
| 40 // A helper method to log library loading result to UMA. | |
| 41 void LogLibrarayLoadResultToUMA(LoadLibraryResult& result) { | |
|
xhwang
2017/03/14 21:48:25
We pretty much never pass non-const ref in Chromiu
chengx
2017/03/14 23:08:30
Yep, should pass by const ref or pass by value (ac
| |
| 42 UMA_HISTOGRAM_ENUMERATION("LibraryLoader.NativeLibraryDynamicallyLoad", | |
| 43 result, LoadLibraryResult::END); | |
| 44 } | |
| 45 | |
| 46 // A helper method to check if AddDllDirectory method is available, thus | |
| 47 // LOAD_LIBRARY_SEARCH_* flags are available on systems. | |
| 48 bool IsLoadLibSearchFlagsAvailable() { | |
|
xhwang
2017/03/14 21:48:25
nit: s/Is/Are. Also since this is related to LOAD_
chengx
2017/03/14 23:08:30
Renamed to AreSearchFlagsAvailable().
| |
| 49 // The LOAD_LIBRARY_SEARCH_* flags are available on systems that have | |
| 50 // KB2533623 installed. To determine whether the flags are available, use | |
| 51 // GetProcAddress to get the address of the AddDllDirectory, | |
| 52 // RemoveDllDirectory, or SetDefaultDllDirectories function. If GetProcAddress | |
| 53 // succeeds, the LOAD_LIBRARY_SEARCH_* flags can be used with LoadLibraryEx. | |
| 54 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms684179(v=vs.85). aspx | |
| 55 // The LOAD_LIBRARY_SEARCH_* flags are used in LoadNativeLibraryHelperEx | |
| 56 // method above. | |
|
xhwang
2017/03/14 21:48:25
"above" is not accurate now
chengx
2017/03/14 23:08:30
Done.
| |
| 57 auto add_dll_dir_func = reinterpret_cast<AddDllDirectory>( | |
| 58 GetProcAddress(GetModuleHandle(L"kernel32.dll"), "AddDllDirectory")); | |
| 59 return !!add_dll_dir_func; | |
| 60 } | |
| 20 | 61 |
| 21 NativeLibrary LoadNativeLibraryHelper(const FilePath& library_path, | 62 NativeLibrary LoadNativeLibraryHelper(const FilePath& library_path, |
| 22 LoadLibraryFunction load_library_api, | |
| 23 NativeLibraryLoadError* error) { | 63 NativeLibraryLoadError* error) { |
| 24 // LoadLibrary() opens the file off disk. | 64 // LoadLibrary() opens the file off disk. |
| 25 ThreadRestrictions::AssertIOAllowed(); | 65 ThreadRestrictions::AssertIOAllowed(); |
| 26 | 66 |
| 67 HMODULE load_library_module = nullptr; | |
|
xhwang
2017/03/14 21:48:25
nit: ISTM the old name |module| is concise and cle
chengx
2017/03/14 23:08:30
Done.
| |
| 68 | |
| 69 // This variable records the library loading result. | |
| 70 LoadLibraryResult load_library_status = LoadLibraryResult::SUCCEED; | |
| 71 | |
| 72 bool is_load_lib_flags_available = IsLoadLibSearchFlagsAvailable(); | |
| 73 if (is_load_lib_flags_available) { | |
| 74 // LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR flag is needed to search the library | |
| 75 // directory as the library may have dependencies on DLLs in this | |
| 76 // directory. | |
| 77 load_library_module = ::LoadLibraryExW( | |
| 78 library_path.value().c_str(), nullptr, | |
| 79 LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); | |
| 80 // If LoadLibraryExW succeeds, log this metric and return. | |
| 81 if (load_library_module) { | |
| 82 LogLibrarayLoadResultToUMA(load_library_status); | |
| 83 return load_library_module; | |
| 84 } | |
| 85 // GetLastError() needs to be called immediately after | |
| 86 // LoadLibraryExW call. | |
| 87 if (error) | |
| 88 error->code = GetLastError(); | |
| 89 } | |
| 90 | |
| 91 // If LoadLibraryExW API/flags are unavailable or API call fails, try | |
| 92 // LoadLibraryW API. | |
|
xhwang
2017/03/14 21:48:25
nit: add an empty line here since these two lines
chengx
2017/03/14 23:08:30
Done.
| |
| 27 // Switch the current directory to the library directory as the library | 93 // Switch the current directory to the library directory as the library |
| 28 // may have dependencies on DLLs in this directory. | 94 // may have dependencies on DLLs in this directory. |
| 29 bool restore_directory = false; | 95 bool restore_directory = false; |
| 30 FilePath current_directory; | 96 FilePath current_directory; |
| 31 if (GetCurrentDirectory(¤t_directory)) { | 97 if (GetCurrentDirectory(¤t_directory)) { |
| 32 FilePath plugin_path = library_path.DirName(); | 98 FilePath plugin_path = library_path.DirName(); |
| 33 if (!plugin_path.empty()) { | 99 if (!plugin_path.empty()) { |
| 34 SetCurrentDirectory(plugin_path); | 100 SetCurrentDirectory(plugin_path); |
| 35 restore_directory = true; | 101 restore_directory = true; |
| 36 } | 102 } |
| 37 } | 103 } |
| 38 | 104 |
| 39 HMODULE module = (*load_library_api)(library_path.value().c_str()); | 105 load_library_module = ::LoadLibraryW(library_path.value().c_str()); |
| 40 if (!module && error) { | 106 |
| 41 // GetLastError() needs to be called immediately after |load_library_api|. | 107 // GetLastError() needs to be called immediately after LoadLibraryW call. |
| 108 if (!load_library_module && error) | |
| 42 error->code = GetLastError(); | 109 error->code = GetLastError(); |
| 43 } | |
| 44 | 110 |
| 45 if (restore_directory) | 111 if (restore_directory) |
| 46 SetCurrentDirectory(current_directory); | 112 SetCurrentDirectory(current_directory); |
| 47 | 113 |
| 48 return module; | 114 // Record the library loading result. |
| 115 if (is_load_lib_flags_available) { | |
| 116 if (load_library_module) | |
| 117 load_library_status = LoadLibraryResult::FAIL_AND_SUCCEED; | |
| 118 else | |
| 119 load_library_status = LoadLibraryResult::FAIL_AND_FAIL; | |
| 120 } else if (load_library_module) | |
|
xhwang
2017/03/14 21:48:25
nit: use curly here and below as well:
https://go
chengx
2017/03/14 23:08:30
Done.
| |
| 121 load_library_status = LoadLibraryResult::UNAVAILABLE_AND_SUCCEED; | |
| 122 else | |
| 123 load_library_status = LoadLibraryResult::UNAVAILABLE_AND_FAIL; | |
|
xhwang
2017/03/14 21:48:25
nit: Probably move these into a helper function as
chengx
2017/03/14 23:08:30
Done.
| |
| 124 | |
| 125 LogLibrarayLoadResultToUMA(load_library_status); | |
| 126 | |
| 127 return load_library_module; | |
| 49 } | 128 } |
| 50 | |
| 51 } // namespace | 129 } // namespace |
| 52 | 130 |
| 53 std::string NativeLibraryLoadError::ToString() const { | 131 std::string NativeLibraryLoadError::ToString() const { |
| 54 return StringPrintf("%u", code); | 132 return StringPrintf("%u", code); |
| 55 } | 133 } |
| 56 | 134 |
| 57 // static | 135 // static |
| 58 NativeLibrary LoadNativeLibraryWithOptions(const FilePath& library_path, | 136 NativeLibrary LoadNativeLibraryWithOptions(const FilePath& library_path, |
| 59 const NativeLibraryOptions& options, | 137 const NativeLibraryOptions& options, |
| 60 NativeLibraryLoadError* error) { | 138 NativeLibraryLoadError* error) { |
| 61 return LoadNativeLibraryHelper(library_path, LoadLibraryW, error); | 139 return LoadNativeLibraryHelper(library_path, error); |
| 62 } | |
| 63 | |
| 64 NativeLibrary LoadNativeLibraryDynamically(const FilePath& library_path) { | |
| 65 typedef HMODULE (WINAPI* LoadLibraryFunction)(const wchar_t* file_name); | |
| 66 | |
| 67 LoadLibraryFunction load_library = reinterpret_cast<LoadLibraryFunction>( | |
| 68 GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryW")); | |
| 69 | |
| 70 return LoadNativeLibraryHelper(library_path, load_library, NULL); | |
| 71 } | 140 } |
| 72 | 141 |
| 73 // static | 142 // static |
| 74 void UnloadNativeLibrary(NativeLibrary library) { | 143 void UnloadNativeLibrary(NativeLibrary library) { |
| 75 FreeLibrary(library); | 144 FreeLibrary(library); |
| 76 } | 145 } |
| 77 | 146 |
| 78 // static | 147 // static |
| 79 void* GetFunctionPointerFromNativeLibrary(NativeLibrary library, | 148 void* GetFunctionPointerFromNativeLibrary(NativeLibrary library, |
| 80 StringPiece name) { | 149 StringPiece name) { |
| 81 return GetProcAddress(library, name.data()); | 150 return GetProcAddress(library, name.data()); |
| 82 } | 151 } |
| 83 | 152 |
| 84 // static | 153 // static |
| 85 std::string GetNativeLibraryName(StringPiece name) { | 154 std::string GetNativeLibraryName(StringPiece name) { |
| 86 DCHECK(IsStringASCII(name)); | 155 DCHECK(IsStringASCII(name)); |
| 87 return name.as_string() + ".dll"; | 156 return name.as_string() + ".dll"; |
| 88 } | 157 } |
| 89 | 158 |
| 90 } // namespace base | 159 } // namespace base |
| OLD | NEW |