1 // Copyright 2017 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 "content/browser/network_service_instance_impl.h"
6 
7 #include <map>
8 #include <memory>
9 #include <string>
10 #include <utility>
11 
12 #include "base/bind.h"
13 #include "base/environment.h"
14 #include "base/feature_list.h"
15 #include "base/files/file.h"
16 #include "base/message_loop/message_pump_type.h"
17 #include "base/metrics/histogram_macros.h"
18 #include "base/no_destructor.h"
19 #include "base/sequenced_task_runner.h"
20 #include "base/strings/string_util.h"
21 #include "base/strings/utf_string_conversions.h"
22 #include "base/synchronization/waitable_event.h"
23 #include "base/threading/sequence_local_storage_slot.h"
24 #include "base/threading/thread.h"
25 #include "base/threading/thread_restrictions.h"
26 #include "build/build_config.h"
27 #include "content/browser/browser_main_loop.h"
28 #include "content/browser/network_service_client.h"
29 #include "content/browser/service_sandbox_type.h"
30 #include "content/public/browser/browser_task_traits.h"
31 #include "content/public/browser/browser_thread.h"
32 #include "content/public/browser/content_browser_client.h"
33 #include "content/public/browser/network_service_instance.h"
34 #include "content/public/browser/service_process_host.h"
35 #include "content/public/browser/system_connector.h"
36 #include "content/public/common/content_client.h"
37 #include "content/public/common/network_service_util.h"
38 #include "content/public/common/service_names.mojom.h"
39 #include "mojo/public/cpp/bindings/pending_receiver.h"
40 #include "mojo/public/cpp/bindings/remote.h"
41 #include "net/log/net_log_util.h"
42 #include "services/cert_verifier/cert_verifier_service_factory.h"
43 #include "services/network/network_service.h"
44 #include "services/network/public/cpp/features.h"
45 #include "services/network/public/cpp/network_switches.h"
46 #include "services/network/public/mojom/net_log.mojom.h"
47 #include "services/network/public/mojom/network_change_manager.mojom.h"
48 #include "services/network/public/mojom/network_service.mojom.h"
49 #include "services/network/public/mojom/network_service_test.mojom.h"
50 
51 namespace content {
52 
53 namespace {
54 
55 #if defined(OS_POSIX)
56 // Environment variable pointing to credential cache file.
57 constexpr char kKrb5CCEnvName[] = "KRB5CCNAME";
58 // Environment variable pointing to Kerberos config file.
59 constexpr char kKrb5ConfEnvName[] = "KRB5_CONFIG";
60 #endif
61 
62 bool g_force_create_network_service_directly = false;
63 mojo::Remote<network::mojom::NetworkService>* g_network_service_remote =
64     nullptr;
65 network::NetworkConnectionTracker* g_network_connection_tracker;
66 bool g_network_service_is_responding = false;
67 base::Time g_last_network_service_crash;
68 
GetLocalNetworkService()69 std::unique_ptr<network::NetworkService>& GetLocalNetworkService() {
70   static base::NoDestructor<
71       base::SequenceLocalStorageSlot<std::unique_ptr<network::NetworkService>>>
72       service;
73   return service->GetOrCreateValue();
74 }
75 
76 // If this feature is enabled, the Network Service will run on its own thread
77 // when running in-process; otherwise it will run on the IO thread.
78 //
79 // On Chrome OS, the Network Service must run on the IO thread because
80 // ProfileIOData and NetworkContext both try to set up NSS, which has to be
81 // called from the IO thread.
82 const base::Feature kNetworkServiceDedicatedThread {
83   "NetworkServiceDedicatedThread",
84 #if defined(OS_CHROMEOS)
85       base::FEATURE_DISABLED_BY_DEFAULT
86 #else
87       base::FEATURE_ENABLED_BY_DEFAULT
88 #endif
89 };
90 
GetNetworkServiceDedicatedThread()91 base::Thread& GetNetworkServiceDedicatedThread() {
92   static base::NoDestructor<base::Thread> thread{"NetworkService"};
93   DCHECK(base::FeatureList::IsEnabled(kNetworkServiceDedicatedThread));
94   return *thread;
95 }
96 
97 // The instance NetworkService used when hosting the service in-process. This is
98 // set up by |CreateInProcessNetworkServiceOnThread()| and destroyed by
99 // |ShutDownNetworkService()|.
100 network::NetworkService* g_in_process_instance = nullptr;
101 
CreateInProcessNetworkServiceOnThread(mojo::PendingReceiver<network::mojom::NetworkService> receiver)102 void CreateInProcessNetworkServiceOnThread(
103     mojo::PendingReceiver<network::mojom::NetworkService> receiver) {
104   // The test interface doesn't need to be implemented in the in-process case.
105   auto registry = std::make_unique<service_manager::BinderRegistry>();
106   registry->AddInterface(base::BindRepeating(
107       [](mojo::PendingReceiver<network::mojom::NetworkServiceTest>) {}));
108   g_in_process_instance = new network::NetworkService(
109       std::move(registry), std::move(receiver),
110       true /* delay_initialization_until_set_client */);
111 }
112 
GetNetworkTaskRunnerStorage()113 scoped_refptr<base::SequencedTaskRunner>& GetNetworkTaskRunnerStorage() {
114   static base::NoDestructor<scoped_refptr<base::SequencedTaskRunner>> storage;
115   return *storage;
116 }
117 
CreateInProcessNetworkService(mojo::PendingReceiver<network::mojom::NetworkService> receiver)118 void CreateInProcessNetworkService(
119     mojo::PendingReceiver<network::mojom::NetworkService> receiver) {
120   scoped_refptr<base::SingleThreadTaskRunner> task_runner;
121   if (base::FeatureList::IsEnabled(kNetworkServiceDedicatedThread)) {
122     base::Thread::Options options(base::MessagePumpType::IO, 0);
123     GetNetworkServiceDedicatedThread().StartWithOptions(options);
124     task_runner = GetNetworkServiceDedicatedThread().task_runner();
125   } else {
126     task_runner = GetIOThreadTaskRunner({});
127   }
128 
129   GetNetworkTaskRunnerStorage() = std::move(task_runner);
130 
131   GetNetworkTaskRunner()->PostTask(
132       FROM_HERE, base::BindOnce(&CreateInProcessNetworkServiceOnThread,
133                                 std::move(receiver)));
134 }
135 
CreateNetworkServiceParams()136 network::mojom::NetworkServiceParamsPtr CreateNetworkServiceParams() {
137   network::mojom::NetworkServiceParamsPtr network_service_params =
138       network::mojom::NetworkServiceParams::New();
139   network_service_params->initial_connection_type =
140       network::mojom::ConnectionType(
141           net::NetworkChangeNotifier::GetConnectionType());
142   network_service_params->initial_connection_subtype =
143       network::mojom::ConnectionSubtype(
144           net::NetworkChangeNotifier::GetConnectionSubtype());
145 
146 #if defined(OS_POSIX)
147   // Send Kerberos environment variables to the network service.
148   if (IsOutOfProcessNetworkService()) {
149     std::unique_ptr<base::Environment> env(base::Environment::Create());
150     std::string value;
151     if (env->HasVar(kKrb5CCEnvName)) {
152       env->GetVar(kKrb5CCEnvName, &value);
153       network_service_params->environment.push_back(
154           network::mojom::EnvironmentVariable::New(kKrb5CCEnvName, value));
155     }
156     if (env->HasVar(kKrb5ConfEnvName)) {
157       env->GetVar(kKrb5ConfEnvName, &value);
158       network_service_params->environment.push_back(
159           network::mojom::EnvironmentVariable::New(kKrb5ConfEnvName, value));
160     }
161   }
162 #endif
163   return network_service_params;
164 }
165 
CreateNetworkServiceOnIOForTesting(mojo::PendingReceiver<network::mojom::NetworkService> receiver,base::WaitableEvent * completion_event)166 void CreateNetworkServiceOnIOForTesting(
167     mojo::PendingReceiver<network::mojom::NetworkService> receiver,
168     base::WaitableEvent* completion_event) {
169   if (GetLocalNetworkService()) {
170     GetLocalNetworkService()->Bind(std::move(receiver));
171     return;
172   }
173 
174   GetLocalNetworkService() = std::make_unique<network::NetworkService>(
175       nullptr /* registry */, std::move(receiver),
176       true /* delay_initialization_until_set_client */);
177   GetLocalNetworkService()->StopMetricsTimerForTesting();
178   GetLocalNetworkService()->Initialize(
179       network::mojom::NetworkServiceParams::New(),
180       true /* mock_network_change_notifier */);
181   if (completion_event)
182     completion_event->Signal();
183 }
184 
BindNetworkChangeManagerReceiver(mojo::PendingReceiver<network::mojom::NetworkChangeManager> receiver)185 void BindNetworkChangeManagerReceiver(
186     mojo::PendingReceiver<network::mojom::NetworkChangeManager> receiver) {
187   GetNetworkService()->GetNetworkChangeManager(std::move(receiver));
188 }
189 
GetCrashHandlersList()190 base::CallbackList<void()>& GetCrashHandlersList() {
191   static base::NoDestructor<base::CallbackList<void()>> s_list;
192   return *s_list;
193 }
194 
OnNetworkServiceCrash()195 void OnNetworkServiceCrash() {
196   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
197   DCHECK(g_network_service_remote);
198   DCHECK(g_network_service_remote->is_bound());
199   DCHECK(!g_network_service_remote->is_connected());
200   g_last_network_service_crash = base::Time::Now();
201   GetCrashHandlersList().Notify();
202 }
203 
204 // Parses the desired granularity of NetLog capturing specified by the command
205 // line.
GetNetCaptureModeFromCommandLine(const base::CommandLine & command_line)206 net::NetLogCaptureMode GetNetCaptureModeFromCommandLine(
207     const base::CommandLine& command_line) {
208   base::StringPiece switch_name = network::switches::kNetLogCaptureMode;
209 
210   if (command_line.HasSwitch(switch_name)) {
211     std::string value = command_line.GetSwitchValueASCII(switch_name);
212 
213     if (value == "Default")
214       return net::NetLogCaptureMode::kDefault;
215     if (value == "IncludeSensitive")
216       return net::NetLogCaptureMode::kIncludeSensitive;
217     if (value == "Everything")
218       return net::NetLogCaptureMode::kEverything;
219 
220     // Warn when using the old command line switches.
221     if (value == "IncludeCookiesAndCredentials") {
222       LOG(ERROR) << "Deprecated value for --" << switch_name
223                  << ". Use IncludeSensitive instead";
224       return net::NetLogCaptureMode::kIncludeSensitive;
225     }
226     if (value == "IncludeSocketBytes") {
227       LOG(ERROR) << "Deprecated value for --" << switch_name
228                  << ". Use Everything instead";
229       return net::NetLogCaptureMode::kEverything;
230     }
231 
232     LOG(ERROR) << "Unrecognized value for --" << switch_name;
233   }
234 
235   return net::NetLogCaptureMode::kDefault;
236 }
237 
238 static NetworkServiceClient* g_client = nullptr;
239 
240 }  // namespace
241 
242 class NetworkServiceInstancePrivate {
243  public:
244   // Opens the specified file, blocking until the file is open. Used to open
245   // files specified by network::switches::kLogNetLog or
246   // network::switches::kSSLKeyLogFile. Since these arguments can be used to
247   // debug startup behavior, asynchronously opening the file on another thread
248   // would result in losing data, hence the need for blocking open operations.
249   // |file_flags| specifies the flags passed to the base::File constructor call.
250   //
251   // ThreadRestrictions needs to be able to friend the class/method to allow
252   // blocking, but can't friend CONTENT_EXPORT methods, so have it friend
253   // NetworkServiceInstancePrivate instead of GetNetworkService().
BlockingOpenFile(const base::FilePath & path,int file_flags)254   static base::File BlockingOpenFile(const base::FilePath& path,
255                                      int file_flags) {
256     base::ScopedAllowBlocking allow_blocking;
257     return base::File(path, file_flags);
258   }
259 };
260 
GetNetworkService()261 network::mojom::NetworkService* GetNetworkService() {
262   if (!g_network_service_remote)
263     g_network_service_remote = new mojo::Remote<network::mojom::NetworkService>;
264   if (!g_network_service_remote->is_bound() ||
265       !g_network_service_remote->is_connected()) {
266     bool service_was_bound = g_network_service_remote->is_bound();
267     g_network_service_remote->reset();
268     if (GetContentClient()->browser()->IsShuttingDown()) {
269       // This happens at system shutdown, since in other scenarios the network
270       // process would only be torn down once the message loop stopped running.
271       // We don't want to start the network service again so just create message
272       // pipe that's not bound to stop consumers from requesting creation of the
273       // service.
274       auto receiver = g_network_service_remote->BindNewPipeAndPassReceiver();
275       auto leaked_pipe = receiver.PassPipe().release();
276     } else {
277       if (!g_force_create_network_service_directly) {
278         mojo::PendingReceiver<network::mojom::NetworkService> receiver =
279             g_network_service_remote->BindNewPipeAndPassReceiver();
280         g_network_service_remote->set_disconnect_handler(
281             base::BindOnce(&OnNetworkServiceCrash));
282         if (IsInProcessNetworkService()) {
283           CreateInProcessNetworkService(std::move(receiver));
284         } else {
285           if (service_was_bound)
286             LOG(ERROR) << "Network service crashed, restarting service.";
287           ServiceProcessHost::Launch(
288               std::move(receiver),
289               ServiceProcessHost::Options()
290                   .WithDisplayName(base::UTF8ToUTF16("Network Service"))
291                   .Pass());
292         }
293       } else {
294         // This should only be reached in unit tests.
295         if (BrowserThread::CurrentlyOn(BrowserThread::IO)) {
296           CreateNetworkServiceOnIOForTesting(
297               g_network_service_remote->BindNewPipeAndPassReceiver(),
298               /*completion_event=*/nullptr);
299         } else {
300           base::WaitableEvent event;
301           GetIOThreadTaskRunner({})->PostTask(
302               FROM_HERE,
303               base::BindOnce(
304                   CreateNetworkServiceOnIOForTesting,
305                   g_network_service_remote->BindNewPipeAndPassReceiver(),
306                   base::Unretained(&event)));
307           event.Wait();
308         }
309       }
310 
311       mojo::PendingRemote<network::mojom::NetworkServiceClient> client_remote;
312       auto client_receiver = client_remote.InitWithNewPipeAndPassReceiver();
313       // Call SetClient before creating NetworkServiceClient, as the latter
314       // might make requests to NetworkService that depend on initialization.
315       (*g_network_service_remote)
316           ->SetClient(std::move(client_remote), CreateNetworkServiceParams());
317       g_network_service_is_responding = false;
318       g_network_service_remote->QueryVersion(base::BindOnce(
319           [](base::Time start_time, uint32_t) {
320             g_network_service_is_responding = true;
321             base::TimeDelta delta = base::Time::Now() - start_time;
322             UMA_HISTOGRAM_MEDIUM_TIMES("NetworkService.TimeToFirstResponse",
323                                        delta);
324             if (g_last_network_service_crash.is_null()) {
325               UMA_HISTOGRAM_MEDIUM_TIMES(
326                   "NetworkService.TimeToFirstResponse.OnStartup", delta);
327             } else {
328               UMA_HISTOGRAM_MEDIUM_TIMES(
329                   "NetworkService.TimeToFirstResponse.AfterCrash", delta);
330             }
331           },
332           base::Time::Now()));
333 
334       delete g_client;  // In case we're recreating the network service.
335       g_client = new NetworkServiceClient(std::move(client_receiver));
336 
337       const base::CommandLine* command_line =
338           base::CommandLine::ForCurrentProcess();
339       if (command_line->HasSwitch(network::switches::kLogNetLog)) {
340         base::FilePath log_path =
341             command_line->GetSwitchValuePath(network::switches::kLogNetLog);
342 
343         base::File file = NetworkServiceInstancePrivate::BlockingOpenFile(
344             log_path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
345         if (!file.IsValid()) {
346           LOG(ERROR) << "Failed opening NetLog: " << log_path.value();
347         } else {
348           (*g_network_service_remote)
349               ->StartNetLog(
350                   std::move(file),
351                   GetNetCaptureModeFromCommandLine(*command_line),
352                   GetContentClient()->browser()->GetNetLogConstants());
353         }
354       }
355 
356       base::FilePath ssl_key_log_path;
357       if (command_line->HasSwitch(network::switches::kSSLKeyLogFile)) {
358         UMA_HISTOGRAM_ENUMERATION(kSSLKeyLogFileHistogram,
359                                   SSLKeyLogFileAction::kSwitchFound);
360         ssl_key_log_path =
361             command_line->GetSwitchValuePath(network::switches::kSSLKeyLogFile);
362         LOG_IF(WARNING, ssl_key_log_path.empty())
363             << "ssl-key-log-file argument missing";
364       } else {
365         std::unique_ptr<base::Environment> env(base::Environment::Create());
366         std::string env_str;
367         if (env->GetVar("SSLKEYLOGFILE", &env_str)) {
368           UMA_HISTOGRAM_ENUMERATION(kSSLKeyLogFileHistogram,
369                                     SSLKeyLogFileAction::kEnvVarFound);
370 #if defined(OS_WIN)
371           // base::Environment returns environment variables in UTF-8 on
372           // Windows.
373           ssl_key_log_path = base::FilePath(base::UTF8ToUTF16(env_str));
374 #else
375           ssl_key_log_path = base::FilePath(env_str);
376 #endif
377         }
378       }
379 
380       if (!ssl_key_log_path.empty()) {
381         base::File file = NetworkServiceInstancePrivate::BlockingOpenFile(
382             ssl_key_log_path,
383             base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_APPEND);
384         if (!file.IsValid()) {
385           LOG(ERROR) << "Failed opening SSL key log file: "
386                      << ssl_key_log_path.value();
387         } else {
388           UMA_HISTOGRAM_ENUMERATION(kSSLKeyLogFileHistogram,
389                                     SSLKeyLogFileAction::kLogFileEnabled);
390           (*g_network_service_remote)->SetSSLKeyLogFile(std::move(file));
391         }
392       }
393 
394       GetContentClient()->browser()->OnNetworkServiceCreated(
395           g_network_service_remote->get());
396     }
397   }
398   return g_network_service_remote->get();
399 }
400 
401 std::unique_ptr<base::CallbackList<void()>::Subscription>
RegisterNetworkServiceCrashHandler(base::RepeatingClosure handler)402 RegisterNetworkServiceCrashHandler(base::RepeatingClosure handler) {
403   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
404   DCHECK(!handler.is_null());
405 
406   return GetCrashHandlersList().Add(std::move(handler));
407 }
408 
409 #if defined(OS_CHROMEOS)
GetNetworkChangeNotifier()410 net::NetworkChangeNotifier* GetNetworkChangeNotifier() {
411   return BrowserMainLoop::GetInstance()->network_change_notifier();
412 }
413 #endif
414 
FlushNetworkServiceInstanceForTesting()415 void FlushNetworkServiceInstanceForTesting() {
416   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
417 
418   if (g_network_service_remote)
419     g_network_service_remote->FlushForTesting();
420 }
421 
GetNetworkConnectionTracker()422 network::NetworkConnectionTracker* GetNetworkConnectionTracker() {
423   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
424          !BrowserThread::IsThreadInitialized(BrowserThread::UI));
425   if (!g_network_connection_tracker) {
426     g_network_connection_tracker = new network::NetworkConnectionTracker(
427         base::BindRepeating(&BindNetworkChangeManagerReceiver));
428   }
429   return g_network_connection_tracker;
430 }
431 
GetNetworkConnectionTrackerFromUIThread(base::OnceCallback<void (network::NetworkConnectionTracker *)> callback)432 void GetNetworkConnectionTrackerFromUIThread(
433     base::OnceCallback<void(network::NetworkConnectionTracker*)> callback) {
434   GetUIThreadTaskRunner({base::TaskPriority::BEST_EFFORT})
435       ->PostTaskAndReplyWithResult(FROM_HERE,
436                                    base::BindOnce(&GetNetworkConnectionTracker),
437                                    std::move(callback));
438 }
439 
440 network::NetworkConnectionTrackerAsyncGetter
CreateNetworkConnectionTrackerAsyncGetter()441 CreateNetworkConnectionTrackerAsyncGetter() {
442   return base::BindRepeating(&content::GetNetworkConnectionTrackerFromUIThread);
443 }
444 
SetNetworkConnectionTrackerForTesting(network::NetworkConnectionTracker * network_connection_tracker)445 void SetNetworkConnectionTrackerForTesting(
446     network::NetworkConnectionTracker* network_connection_tracker) {
447   if (g_network_connection_tracker != network_connection_tracker) {
448     DCHECK(!g_network_connection_tracker || !network_connection_tracker);
449     g_network_connection_tracker = network_connection_tracker;
450   }
451 }
452 
GetNetworkTaskRunner()453 const scoped_refptr<base::SequencedTaskRunner>& GetNetworkTaskRunner() {
454   DCHECK(IsInProcessNetworkService());
455   return GetNetworkTaskRunnerStorage();
456 }
457 
ForceCreateNetworkServiceDirectlyForTesting()458 void ForceCreateNetworkServiceDirectlyForTesting() {
459   g_force_create_network_service_directly = true;
460 }
461 
ResetNetworkServiceForTesting()462 void ResetNetworkServiceForTesting() {
463   ShutDownNetworkService();
464 }
465 
ShutDownNetworkService()466 void ShutDownNetworkService() {
467   delete g_network_service_remote;
468   g_network_service_remote = nullptr;
469   delete g_client;
470   g_client = nullptr;
471   if (g_in_process_instance) {
472     GetNetworkTaskRunner()->DeleteSoon(FROM_HERE, g_in_process_instance);
473     g_in_process_instance = nullptr;
474   }
475   GetNetworkTaskRunnerStorage().reset();
476 }
477 
GetNetworkServiceAvailability()478 NetworkServiceAvailability GetNetworkServiceAvailability() {
479   if (!g_network_service_remote)
480     return NetworkServiceAvailability::NOT_CREATED;
481   else if (!g_network_service_remote->is_bound())
482     return NetworkServiceAvailability::NOT_BOUND;
483   else if (!g_network_service_remote->is_connected())
484     return NetworkServiceAvailability::ENCOUNTERED_ERROR;
485   else if (!g_network_service_is_responding)
486     return NetworkServiceAvailability::NOT_RESPONDING;
487   else
488     return NetworkServiceAvailability::AVAILABLE;
489 }
490 
GetTimeSinceLastNetworkServiceCrash()491 base::TimeDelta GetTimeSinceLastNetworkServiceCrash() {
492   if (g_last_network_service_crash.is_null())
493     return base::TimeDelta();
494   return base::Time::Now() - g_last_network_service_crash;
495 }
496 
PingNetworkService(base::OnceClosure closure)497 void PingNetworkService(base::OnceClosure closure) {
498   GetNetworkService();
499   // Unfortunately, QueryVersion requires a RepeatingCallback.
500   g_network_service_remote->QueryVersion(base::BindOnce(
501       [](base::OnceClosure closure, uint32_t) {
502         if (closure)
503           std::move(closure).Run();
504       },
505       base::Passed(std::move(closure))));
506 }
507 
508 namespace {
509 
510 mojo::PendingRemote<cert_verifier::mojom::CertVerifierService>
GetNewCertVerifierServiceRemote(cert_verifier::mojom::CertVerifierServiceFactory * cert_verifier_service_factory,network::mojom::CertVerifierCreationParamsPtr creation_params)511 GetNewCertVerifierServiceRemote(
512     cert_verifier::mojom::CertVerifierServiceFactory*
513         cert_verifier_service_factory,
514     network::mojom::CertVerifierCreationParamsPtr creation_params) {
515   mojo::PendingRemote<cert_verifier::mojom::CertVerifierService>
516       cert_verifier_remote;
517   cert_verifier_service_factory->GetNewCertVerifier(
518       cert_verifier_remote.InitWithNewPipeAndPassReceiver(),
519       std::move(creation_params));
520   return cert_verifier_remote;
521 }
522 
CreateInProcessCertVerifierServiceOnThread(mojo::PendingReceiver<cert_verifier::mojom::CertVerifierServiceFactory> receiver)523 void CreateInProcessCertVerifierServiceOnThread(
524     mojo::PendingReceiver<cert_verifier::mojom::CertVerifierServiceFactory>
525         receiver) {
526   // Except in tests, our CertVerifierServiceFactoryImpl is a singleton.
527   static base::NoDestructor<cert_verifier::CertVerifierServiceFactoryImpl>
528       cv_service_factory(std::move(receiver));
529 }
530 
531 // Owns the CertVerifierServiceFactory used by the browser.
532 // Lives on the UI thread.
533 class CertVerifierServiceFactoryOwner {
534  public:
535   CertVerifierServiceFactoryOwner() = default;
536   CertVerifierServiceFactoryOwner(const CertVerifierServiceFactoryOwner&) =
537       delete;
538   CertVerifierServiceFactoryOwner& operator=(
539       const CertVerifierServiceFactoryOwner&) = delete;
540   ~CertVerifierServiceFactoryOwner() = delete;
541 
Get()542   static CertVerifierServiceFactoryOwner* Get() {
543     static base::NoDestructor<CertVerifierServiceFactoryOwner>
544         cert_verifier_service_factory_owner;
545     return &*cert_verifier_service_factory_owner;
546   }
547 
548   // Passing nullptr will reset the current remote.
SetCertVerifierServiceFactoryForTesting(cert_verifier::mojom::CertVerifierServiceFactory * service_factory)549   void SetCertVerifierServiceFactoryForTesting(
550       cert_verifier::mojom::CertVerifierServiceFactory* service_factory) {
551     if (service_factory) {
552       DCHECK(!service_factory_);
553     }
554     service_factory_ = service_factory;
555     service_factory_remote_.reset();
556   }
557 
558   // Returns a pointer to a CertVerifierServiceFactory usable on the UI thread.
559   cert_verifier::mojom::CertVerifierServiceFactory*
GetCertVerifierServiceFactory()560   GetCertVerifierServiceFactory() {
561     if (!service_factory_) {
562 #if defined(OS_CHROMEOS)
563       // ChromeOS's in-process CertVerifierService should run on the IO thread
564       // because it interacts with IO-bound NSS and ChromeOS user slots.
565       // See for example InitializeNSSForChromeOSUser().
566       GetIOThreadTaskRunner({})->PostTask(
567           FROM_HERE,
568           base::BindOnce(&CreateInProcessCertVerifierServiceOnThread,
569                          service_factory_remote_.BindNewPipeAndPassReceiver()));
570 #else
571       CreateInProcessCertVerifierServiceOnThread(
572           service_factory_remote_.BindNewPipeAndPassReceiver());
573 #endif
574       service_factory_ = service_factory_remote_.get();
575     }
576     return service_factory_;
577   }
578 
579  private:
580   // Bound to UI thread.
581   mojo::Remote<cert_verifier::mojom::CertVerifierServiceFactory>
582       service_factory_remote_;
583   cert_verifier::mojom::CertVerifierServiceFactory* service_factory_ = nullptr;
584 };
585 
586 }  // namespace
587 
GetCertVerifierParams(network::mojom::CertVerifierCreationParamsPtr cert_verifier_creation_params)588 network::mojom::CertVerifierParamsPtr GetCertVerifierParams(
589     network::mojom::CertVerifierCreationParamsPtr
590         cert_verifier_creation_params) {
591   if (!base::FeatureList::IsEnabled(network::features::kCertVerifierService)) {
592     return network::mojom::CertVerifierParams::NewCreationParams(
593         std::move(cert_verifier_creation_params));
594   }
595 
596   auto cv_service_remote_params =
597       network::mojom::CertVerifierServiceRemoteParams::New();
598 
599   // Create a cert verifier service.
600   cv_service_remote_params
601       ->cert_verifier_service = GetNewCertVerifierServiceRemote(
602       CertVerifierServiceFactoryOwner::Get()->GetCertVerifierServiceFactory(),
603       std::move(cert_verifier_creation_params));
604 
605   return network::mojom::CertVerifierParams::NewRemoteParams(
606       std::move(cv_service_remote_params));
607 }
608 
SetCertVerifierServiceFactoryForTesting(cert_verifier::mojom::CertVerifierServiceFactory * service_factory)609 void SetCertVerifierServiceFactoryForTesting(
610     cert_verifier::mojom::CertVerifierServiceFactory* service_factory) {
611   CertVerifierServiceFactoryOwner::Get()
612       ->SetCertVerifierServiceFactoryForTesting(service_factory);
613 }
614 
615 }  // namespace content
616