Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(53)

Side by Side Diff: base/native_library_win.cc

Issue 2744043003: Use LoadLibraryExW if applicable in LoadNativeLibrary on Windows (Closed)
Patch Set: Better variable name. Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/native_library.h ('k') | tools/metrics/histograms/histograms.xml » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 using AddDllDirectory = HMODULE (*)(PCWSTR new_directory);
18 19
19 namespace { 20 namespace {
21 // This enum is used to back an UMA histogram, and should therefore be treated
22 // as append-only.
23 enum LoadLibraryResult {
24 // LoadLibraryExW API/flags are available and the call succeeds.
25 SUCCEED = 0,
26 // LoadLibraryExW API/flags are availabe to use but the call fails, then
27 // LoadLibraryW is used and succeeds.
28 FAIL_AND_SUCCEED,
29 // LoadLibraryExW API/flags are availabe to use but the call fails, then
30 // LoadLibraryW is used but fails as well.
31 FAIL_AND_FAIL,
32 // LoadLibraryExW API/flags are unavailabe to use, then LoadLibraryW is used
33 // and succeeds.
34 UNAVAILABLE_AND_SUCCEED,
35 // LoadLibraryExW API/flags are unavailabe to use, then LoadLibraryW is used
36 // but fails.
37 UNAVAILABLE_AND_FAIL,
38 // Add new items before this one, always keep this one at the end.
39 END
40 };
41
42 // A helper method to log library loading result to UMA.
43 void LogLibrarayLoadResultToUMA(LoadLibraryResult result) {
44 UMA_HISTOGRAM_ENUMERATION("LibraryLoader.LoadNativeLibraryWindows", result,
45 LoadLibraryResult::END);
46 }
47
48 // A helper method to check if AddDllDirectory method is available, thus
49 // LOAD_LIBRARY_SEARCH_* flags are available on systems.
50 bool AreSearchFlagsAvailable() {
51 // The LOAD_LIBRARY_SEARCH_* flags are available on systems that have
52 // KB2533623 installed. To determine whether the flags are available, use
53 // GetProcAddress to get the address of the AddDllDirectory,
54 // RemoveDllDirectory, or SetDefaultDllDirectories function. If GetProcAddress
55 // succeeds, the LOAD_LIBRARY_SEARCH_* flags can be used with LoadLibraryEx.
56 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms684179(v=vs.85). aspx
57 // The LOAD_LIBRARY_SEARCH_* flags are used in the LoadNativeLibraryHelper
58 // method.
59 auto add_dll_dir_func = reinterpret_cast<AddDllDirectory>(
60 GetProcAddress(GetModuleHandle(L"kernel32.dll"), "AddDllDirectory"));
61 return !!add_dll_dir_func;
62 }
63
64 // A helper method to encode the library loading result to enum
65 // LoadLibraryResult.
66 LoadLibraryResult GetLoadLibraryResult(bool are_search_flags_available,
67 bool has_load_library_succeeded) {
68 LoadLibraryResult result;
69 if (are_search_flags_available) {
70 if (has_load_library_succeeded)
71 result = LoadLibraryResult::FAIL_AND_SUCCEED;
72 else
73 result = LoadLibraryResult::FAIL_AND_FAIL;
74 } else if (has_load_library_succeeded) {
75 result = LoadLibraryResult::UNAVAILABLE_AND_SUCCEED;
76 } else {
77 result = LoadLibraryResult::UNAVAILABLE_AND_FAIL;
78 }
79 return result;
80 }
20 81
21 NativeLibrary LoadNativeLibraryHelper(const FilePath& library_path, 82 NativeLibrary LoadNativeLibraryHelper(const FilePath& library_path,
22 LoadLibraryFunction load_library_api,
23 NativeLibraryLoadError* error) { 83 NativeLibraryLoadError* error) {
24 // LoadLibrary() opens the file off disk. 84 // LoadLibrary() opens the file off disk.
25 ThreadRestrictions::AssertIOAllowed(); 85 ThreadRestrictions::AssertIOAllowed();
26 86
87 HMODULE module = nullptr;
88
89 // This variable records the library loading result.
90 LoadLibraryResult load_library_result = LoadLibraryResult::SUCCEED;
91
92 bool are_search_flags_available = AreSearchFlagsAvailable();
93 if (are_search_flags_available) {
94 // LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR flag is needed to search the library
95 // directory as the library may have dependencies on DLLs in this
96 // directory.
97 module = ::LoadLibraryExW(
98 library_path.value().c_str(), nullptr,
99 LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
100 // If LoadLibraryExW succeeds, log this metric and return.
101 if (module) {
102 LogLibrarayLoadResultToUMA(load_library_result);
103 return module;
104 }
105 // GetLastError() needs to be called immediately after
106 // LoadLibraryExW call.
107 if (error)
108 error->code = GetLastError();
109 }
110
111 // If LoadLibraryExW API/flags are unavailable or API call fails, try
112 // LoadLibraryW API.
113 // TODO(chengx): Currently, if LoadLibraryExW API call fails, LoadLibraryW is
114 // still tried. We should strictly prefer the LoadLibraryExW over the
115 // LoadLibraryW if LoadLibraryW is statistically showing no extra benefits. If
116 // UMA metric shows that FAIL_AND_FAIL is the primary failure mode and/or
117 // FAIL_AND_SUCCESS is close to zero, we should remove this fallback.
118 // (http://crbug.com/701944)
119
27 // Switch the current directory to the library directory as the library 120 // Switch the current directory to the library directory as the library
28 // may have dependencies on DLLs in this directory. 121 // may have dependencies on DLLs in this directory.
29 bool restore_directory = false; 122 bool restore_directory = false;
30 FilePath current_directory; 123 FilePath current_directory;
31 if (GetCurrentDirectory(&current_directory)) { 124 if (GetCurrentDirectory(&current_directory)) {
32 FilePath plugin_path = library_path.DirName(); 125 FilePath plugin_path = library_path.DirName();
33 if (!plugin_path.empty()) { 126 if (!plugin_path.empty()) {
34 SetCurrentDirectory(plugin_path); 127 SetCurrentDirectory(plugin_path);
35 restore_directory = true; 128 restore_directory = true;
36 } 129 }
37 } 130 }
38 131
39 HMODULE module = (*load_library_api)(library_path.value().c_str()); 132 module = ::LoadLibraryW(library_path.value().c_str());
40 if (!module && error) { 133
41 // GetLastError() needs to be called immediately after |load_library_api|. 134 // GetLastError() needs to be called immediately after LoadLibraryW call.
135 if (!module && error)
42 error->code = GetLastError(); 136 error->code = GetLastError();
43 }
44 137
45 if (restore_directory) 138 if (restore_directory)
46 SetCurrentDirectory(current_directory); 139 SetCurrentDirectory(current_directory);
47 140
141 // Get the library loading result and log it to UMA.
142 LogLibrarayLoadResultToUMA(
143 GetLoadLibraryResult(are_search_flags_available, !!module));
144
48 return module; 145 return module;
49 } 146 }
50
51 } // namespace 147 } // namespace
52 148
53 std::string NativeLibraryLoadError::ToString() const { 149 std::string NativeLibraryLoadError::ToString() const {
54 return StringPrintf("%u", code); 150 return StringPrintf("%u", code);
55 } 151 }
56 152
57 // static 153 // static
58 NativeLibrary LoadNativeLibraryWithOptions(const FilePath& library_path, 154 NativeLibrary LoadNativeLibraryWithOptions(const FilePath& library_path,
59 const NativeLibraryOptions& options, 155 const NativeLibraryOptions& options,
60 NativeLibraryLoadError* error) { 156 NativeLibraryLoadError* error) {
61 return LoadNativeLibraryHelper(library_path, LoadLibraryW, error); 157 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 } 158 }
72 159
73 // static 160 // static
74 void UnloadNativeLibrary(NativeLibrary library) { 161 void UnloadNativeLibrary(NativeLibrary library) {
75 FreeLibrary(library); 162 FreeLibrary(library);
76 } 163 }
77 164
78 // static 165 // static
79 void* GetFunctionPointerFromNativeLibrary(NativeLibrary library, 166 void* GetFunctionPointerFromNativeLibrary(NativeLibrary library,
80 StringPiece name) { 167 StringPiece name) {
81 return GetProcAddress(library, name.data()); 168 return GetProcAddress(library, name.data());
82 } 169 }
83 170
84 // static 171 // static
85 std::string GetNativeLibraryName(StringPiece name) { 172 std::string GetNativeLibraryName(StringPiece name) {
86 DCHECK(IsStringASCII(name)); 173 DCHECK(IsStringASCII(name));
87 return name.as_string() + ".dll"; 174 return name.as_string() + ".dll";
88 } 175 }
89 176
90 } // namespace base 177 } // namespace base
OLDNEW
« no previous file with comments | « base/native_library.h ('k') | tools/metrics/histograms/histograms.xml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698