xref: /aosp_15_r20/external/cronet/base/native_library_win.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2011 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "base/native_library.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <windows.h>
8*6777b538SAndroid Build Coastguard Worker 
9*6777b538SAndroid Build Coastguard Worker #include "base/files/file_util.h"
10*6777b538SAndroid Build Coastguard Worker #include "base/metrics/histogram_macros.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/path_service.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/scoped_native_library.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/strings/strcat.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_piece.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_util.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/strings/stringprintf.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/strings/utf_string_conversions.h"
18*6777b538SAndroid Build Coastguard Worker #include "base/threading/scoped_blocking_call.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/threading/scoped_thread_priority.h"
20*6777b538SAndroid Build Coastguard Worker 
21*6777b538SAndroid Build Coastguard Worker namespace base {
22*6777b538SAndroid Build Coastguard Worker 
23*6777b538SAndroid Build Coastguard Worker namespace {
24*6777b538SAndroid Build Coastguard Worker 
LoadNativeLibraryHelper(const FilePath & library_path,NativeLibraryLoadError * error)25*6777b538SAndroid Build Coastguard Worker NativeLibrary LoadNativeLibraryHelper(const FilePath& library_path,
26*6777b538SAndroid Build Coastguard Worker                                       NativeLibraryLoadError* error) {
27*6777b538SAndroid Build Coastguard Worker   // LoadLibrary() opens the file off disk and acquires the LoaderLock, hence
28*6777b538SAndroid Build Coastguard Worker   // must not be called from DllMain.
29*6777b538SAndroid Build Coastguard Worker   ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
30*6777b538SAndroid Build Coastguard Worker 
31*6777b538SAndroid Build Coastguard Worker   // Mitigate the issues caused by loading DLLs on a background thread
32*6777b538SAndroid Build Coastguard Worker   // (see http://crbug/973868 for context). This temporarily boosts this
33*6777b538SAndroid Build Coastguard Worker   // thread's priority so that it doesn't get starved by higher priority threads
34*6777b538SAndroid Build Coastguard Worker   // while it holds the LoaderLock.
35*6777b538SAndroid Build Coastguard Worker   SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY_REPEATEDLY();
36*6777b538SAndroid Build Coastguard Worker 
37*6777b538SAndroid Build Coastguard Worker   HMODULE module_handle = nullptr;
38*6777b538SAndroid Build Coastguard Worker 
39*6777b538SAndroid Build Coastguard Worker   // LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR flag is needed to search the library
40*6777b538SAndroid Build Coastguard Worker   // directory as the library may have dependencies on DLLs in this
41*6777b538SAndroid Build Coastguard Worker   // directory.
42*6777b538SAndroid Build Coastguard Worker   module_handle = ::LoadLibraryExW(
43*6777b538SAndroid Build Coastguard Worker       library_path.value().c_str(), nullptr,
44*6777b538SAndroid Build Coastguard Worker       LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
45*6777b538SAndroid Build Coastguard Worker   // If LoadLibraryExW succeeds, log this metric and return.
46*6777b538SAndroid Build Coastguard Worker   if (module_handle) {
47*6777b538SAndroid Build Coastguard Worker     return module_handle;
48*6777b538SAndroid Build Coastguard Worker   }
49*6777b538SAndroid Build Coastguard Worker   // GetLastError() needs to be called immediately after
50*6777b538SAndroid Build Coastguard Worker   // LoadLibraryExW call.
51*6777b538SAndroid Build Coastguard Worker   if (error) {
52*6777b538SAndroid Build Coastguard Worker     error->code = ::GetLastError();
53*6777b538SAndroid Build Coastguard Worker   }
54*6777b538SAndroid Build Coastguard Worker 
55*6777b538SAndroid Build Coastguard Worker   // If LoadLibraryExW API/flags are unavailable or API call fails, try
56*6777b538SAndroid Build Coastguard Worker   // LoadLibraryW API. From UMA, this fallback is necessary for many users.
57*6777b538SAndroid Build Coastguard Worker 
58*6777b538SAndroid Build Coastguard Worker   // Switch the current directory to the library directory as the library
59*6777b538SAndroid Build Coastguard Worker   // may have dependencies on DLLs in this directory.
60*6777b538SAndroid Build Coastguard Worker   bool restore_directory = false;
61*6777b538SAndroid Build Coastguard Worker   FilePath current_directory;
62*6777b538SAndroid Build Coastguard Worker   if (GetCurrentDirectory(&current_directory)) {
63*6777b538SAndroid Build Coastguard Worker     FilePath plugin_path = library_path.DirName();
64*6777b538SAndroid Build Coastguard Worker     if (!plugin_path.empty()) {
65*6777b538SAndroid Build Coastguard Worker       SetCurrentDirectory(plugin_path);
66*6777b538SAndroid Build Coastguard Worker       restore_directory = true;
67*6777b538SAndroid Build Coastguard Worker     }
68*6777b538SAndroid Build Coastguard Worker   }
69*6777b538SAndroid Build Coastguard Worker   module_handle = ::LoadLibraryW(library_path.value().c_str());
70*6777b538SAndroid Build Coastguard Worker 
71*6777b538SAndroid Build Coastguard Worker   // GetLastError() needs to be called immediately after LoadLibraryW call.
72*6777b538SAndroid Build Coastguard Worker   if (!module_handle && error) {
73*6777b538SAndroid Build Coastguard Worker     error->code = ::GetLastError();
74*6777b538SAndroid Build Coastguard Worker   }
75*6777b538SAndroid Build Coastguard Worker 
76*6777b538SAndroid Build Coastguard Worker   if (restore_directory)
77*6777b538SAndroid Build Coastguard Worker     SetCurrentDirectory(current_directory);
78*6777b538SAndroid Build Coastguard Worker 
79*6777b538SAndroid Build Coastguard Worker   return module_handle;
80*6777b538SAndroid Build Coastguard Worker }
81*6777b538SAndroid Build Coastguard Worker 
LoadSystemLibraryHelper(const FilePath & library_path,NativeLibraryLoadError * error)82*6777b538SAndroid Build Coastguard Worker NativeLibrary LoadSystemLibraryHelper(const FilePath& library_path,
83*6777b538SAndroid Build Coastguard Worker                                       NativeLibraryLoadError* error) {
84*6777b538SAndroid Build Coastguard Worker   // GetModuleHandleEx and subsequently LoadLibraryEx acquire the LoaderLock,
85*6777b538SAndroid Build Coastguard Worker   // hence must not be called from Dllmain.
86*6777b538SAndroid Build Coastguard Worker   ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
87*6777b538SAndroid Build Coastguard Worker   NativeLibrary module;
88*6777b538SAndroid Build Coastguard Worker   BOOL module_found =
89*6777b538SAndroid Build Coastguard Worker       ::GetModuleHandleExW(0, library_path.value().c_str(), &module);
90*6777b538SAndroid Build Coastguard Worker   if (!module_found) {
91*6777b538SAndroid Build Coastguard Worker     module = ::LoadLibraryExW(library_path.value().c_str(), nullptr,
92*6777b538SAndroid Build Coastguard Worker                               LOAD_LIBRARY_SEARCH_SYSTEM32);
93*6777b538SAndroid Build Coastguard Worker 
94*6777b538SAndroid Build Coastguard Worker     if (!module && error)
95*6777b538SAndroid Build Coastguard Worker       error->code = ::GetLastError();
96*6777b538SAndroid Build Coastguard Worker   }
97*6777b538SAndroid Build Coastguard Worker 
98*6777b538SAndroid Build Coastguard Worker   return module;
99*6777b538SAndroid Build Coastguard Worker }
100*6777b538SAndroid Build Coastguard Worker 
GetSystemLibraryName(FilePath::StringPieceType name)101*6777b538SAndroid Build Coastguard Worker FilePath GetSystemLibraryName(FilePath::StringPieceType name) {
102*6777b538SAndroid Build Coastguard Worker   FilePath library_path;
103*6777b538SAndroid Build Coastguard Worker   // Use an absolute path to load the DLL to avoid DLL preloading attacks.
104*6777b538SAndroid Build Coastguard Worker   if (PathService::Get(DIR_SYSTEM, &library_path))
105*6777b538SAndroid Build Coastguard Worker     library_path = library_path.Append(name);
106*6777b538SAndroid Build Coastguard Worker   return library_path;
107*6777b538SAndroid Build Coastguard Worker }
108*6777b538SAndroid Build Coastguard Worker 
109*6777b538SAndroid Build Coastguard Worker }  // namespace
110*6777b538SAndroid Build Coastguard Worker 
ToString() const111*6777b538SAndroid Build Coastguard Worker std::string NativeLibraryLoadError::ToString() const {
112*6777b538SAndroid Build Coastguard Worker   return StringPrintf("%lu", code);
113*6777b538SAndroid Build Coastguard Worker }
114*6777b538SAndroid Build Coastguard Worker 
LoadNativeLibraryWithOptions(const FilePath & library_path,const NativeLibraryOptions & options,NativeLibraryLoadError * error)115*6777b538SAndroid Build Coastguard Worker NativeLibrary LoadNativeLibraryWithOptions(const FilePath& library_path,
116*6777b538SAndroid Build Coastguard Worker                                            const NativeLibraryOptions& options,
117*6777b538SAndroid Build Coastguard Worker                                            NativeLibraryLoadError* error) {
118*6777b538SAndroid Build Coastguard Worker   return LoadNativeLibraryHelper(library_path, error);
119*6777b538SAndroid Build Coastguard Worker }
120*6777b538SAndroid Build Coastguard Worker 
UnloadNativeLibrary(NativeLibrary library)121*6777b538SAndroid Build Coastguard Worker void UnloadNativeLibrary(NativeLibrary library) {
122*6777b538SAndroid Build Coastguard Worker   FreeLibrary(library);
123*6777b538SAndroid Build Coastguard Worker }
124*6777b538SAndroid Build Coastguard Worker 
GetFunctionPointerFromNativeLibrary(NativeLibrary library,const char * name)125*6777b538SAndroid Build Coastguard Worker void* GetFunctionPointerFromNativeLibrary(NativeLibrary library,
126*6777b538SAndroid Build Coastguard Worker                                           const char* name) {
127*6777b538SAndroid Build Coastguard Worker   return reinterpret_cast<void*>(GetProcAddress(library, name));
128*6777b538SAndroid Build Coastguard Worker }
129*6777b538SAndroid Build Coastguard Worker 
GetNativeLibraryName(StringPiece name)130*6777b538SAndroid Build Coastguard Worker std::string GetNativeLibraryName(StringPiece name) {
131*6777b538SAndroid Build Coastguard Worker   DCHECK(IsStringASCII(name));
132*6777b538SAndroid Build Coastguard Worker   return StrCat({name, ".dll"});
133*6777b538SAndroid Build Coastguard Worker }
134*6777b538SAndroid Build Coastguard Worker 
GetLoadableModuleName(StringPiece name)135*6777b538SAndroid Build Coastguard Worker std::string GetLoadableModuleName(StringPiece name) {
136*6777b538SAndroid Build Coastguard Worker   return GetNativeLibraryName(name);
137*6777b538SAndroid Build Coastguard Worker }
138*6777b538SAndroid Build Coastguard Worker 
LoadSystemLibrary(FilePath::StringPieceType name,NativeLibraryLoadError * error)139*6777b538SAndroid Build Coastguard Worker NativeLibrary LoadSystemLibrary(FilePath::StringPieceType name,
140*6777b538SAndroid Build Coastguard Worker                                 NativeLibraryLoadError* error) {
141*6777b538SAndroid Build Coastguard Worker   FilePath library_path = GetSystemLibraryName(name);
142*6777b538SAndroid Build Coastguard Worker   if (library_path.empty()) {
143*6777b538SAndroid Build Coastguard Worker     if (error)
144*6777b538SAndroid Build Coastguard Worker       error->code = ERROR_NOT_FOUND;
145*6777b538SAndroid Build Coastguard Worker     return nullptr;
146*6777b538SAndroid Build Coastguard Worker   }
147*6777b538SAndroid Build Coastguard Worker   return LoadSystemLibraryHelper(library_path, error);
148*6777b538SAndroid Build Coastguard Worker }
149*6777b538SAndroid Build Coastguard Worker 
PinSystemLibrary(FilePath::StringPieceType name,NativeLibraryLoadError * error)150*6777b538SAndroid Build Coastguard Worker NativeLibrary PinSystemLibrary(FilePath::StringPieceType name,
151*6777b538SAndroid Build Coastguard Worker                                NativeLibraryLoadError* error) {
152*6777b538SAndroid Build Coastguard Worker   FilePath library_path = GetSystemLibraryName(name);
153*6777b538SAndroid Build Coastguard Worker   if (library_path.empty()) {
154*6777b538SAndroid Build Coastguard Worker     if (error)
155*6777b538SAndroid Build Coastguard Worker       error->code = ERROR_NOT_FOUND;
156*6777b538SAndroid Build Coastguard Worker     return nullptr;
157*6777b538SAndroid Build Coastguard Worker   }
158*6777b538SAndroid Build Coastguard Worker 
159*6777b538SAndroid Build Coastguard Worker   // GetModuleHandleEx acquires the LoaderLock, hence must not be called from
160*6777b538SAndroid Build Coastguard Worker   // Dllmain.
161*6777b538SAndroid Build Coastguard Worker   ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
162*6777b538SAndroid Build Coastguard Worker   ScopedNativeLibrary module;
163*6777b538SAndroid Build Coastguard Worker   if (::GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_PIN,
164*6777b538SAndroid Build Coastguard Worker                            library_path.value().c_str(),
165*6777b538SAndroid Build Coastguard Worker                            ScopedNativeLibrary::Receiver(module).get())) {
166*6777b538SAndroid Build Coastguard Worker     return module.release();
167*6777b538SAndroid Build Coastguard Worker   }
168*6777b538SAndroid Build Coastguard Worker 
169*6777b538SAndroid Build Coastguard Worker   // Load and pin the library since it wasn't already loaded.
170*6777b538SAndroid Build Coastguard Worker   module = ScopedNativeLibrary(LoadSystemLibraryHelper(library_path, error));
171*6777b538SAndroid Build Coastguard Worker   if (!module.is_valid())
172*6777b538SAndroid Build Coastguard Worker     return nullptr;
173*6777b538SAndroid Build Coastguard Worker 
174*6777b538SAndroid Build Coastguard Worker   ScopedNativeLibrary temp;
175*6777b538SAndroid Build Coastguard Worker   if (::GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_PIN,
176*6777b538SAndroid Build Coastguard Worker                            library_path.value().c_str(),
177*6777b538SAndroid Build Coastguard Worker                            ScopedNativeLibrary::Receiver(temp).get())) {
178*6777b538SAndroid Build Coastguard Worker     return module.release();
179*6777b538SAndroid Build Coastguard Worker   }
180*6777b538SAndroid Build Coastguard Worker 
181*6777b538SAndroid Build Coastguard Worker   if (error)
182*6777b538SAndroid Build Coastguard Worker     error->code = ::GetLastError();
183*6777b538SAndroid Build Coastguard Worker   // Return nullptr since we failed to pin the module.
184*6777b538SAndroid Build Coastguard Worker   return nullptr;
185*6777b538SAndroid Build Coastguard Worker }
186*6777b538SAndroid Build Coastguard Worker 
187*6777b538SAndroid Build Coastguard Worker }  // namespace base
188