[Lacros] Propagate proxy settings from Ash-Chrome
Proxy settings on different platforms are monitored using platform
specific implementations of ProxyConfigService
(i.e. ProxyConfigServiceMac, ProxyConfigServiceWin,
ProxyConfigServiceLinux etc.) which listens/polls proxy configs from
the OS.
This CL introduces the ProxyConfigServiceLacros which listens for
proxy settings coming from Ash-Chrome via the mojo crosapi. The proxy
configs are propagated to the browser's NetworkService only if the
pref kUseAshProxy is true. If kUseAshProxy is false, the proxy config
sent by Ash-Chrome is not used by the NetworkService.
To keep the existing order of precedence, if a proxy is configured via
an extension, it will have priority over the proxy config coming from
Ash-Chrome, regardless of the value of kUseAshProxy.
Not forcing secondary profiles to go through the system proxy is a
privacy improvement, especially in a commercial deployment. In a
follow-up CL we will add a UI checkbox to allow secondary profiles to
opt-in on using the system proxy. For now, kUseAshProxy is always true
for primary profiles and false for secondary profiles.
Bug: b/192914999
Test: unit tests, browser test
Change-Id: Icac55ce896caf0afe789b7a86c6b93093c1ed444
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3122991
Reviewed-by: Dominic Battré <[email protected]>
Reviewed-by: Roland Bock <[email protected]>
Reviewed-by: Matt Menke <[email protected]>
Reviewed-by: Pavol Marko <[email protected]>
Commit-Queue: Andreea-Elena Costinas <[email protected]>
Cr-Commit-Position: refs/heads/main@{#923876}
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 58d98f7..d9f6692 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -4984,6 +4984,11 @@
"lacros/lacros_url_handling.h",
"lacros/metrics_reporting_observer.cc",
"lacros/metrics_reporting_observer.h",
+ "lacros/net/network_settings_translation.h",
+ "lacros/net/proxy_config_service_lacros.cc",
+ "lacros/net/proxy_config_service_lacros.h",
+ "lacros/net/network_settings_translation_crosapi.cc",
+ "lacros/net/network_settings_translation_net_proxy.cc",
"lacros/prefs_ash_observer.cc",
"lacros/prefs_ash_observer.h",
"lacros/snap_controller_lacros.cc",
diff --git a/chrome/browser/lacros/net/network_settings_translation.h b/chrome/browser/lacros/net/network_settings_translation.h
new file mode 100644
index 0000000..758e60c
--- /dev/null
+++ b/chrome/browser/lacros/net/network_settings_translation.h
@@ -0,0 +1,25 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_LACROS_NET_NETWORK_SETTINGS_TRANSLATION_H_
+#define CHROME_BROWSER_LACROS_NET_NETWORK_SETTINGS_TRANSLATION_H_
+
+#include "chromeos/crosapi/mojom/network_settings_service.mojom.h"
+#include "net/proxy_resolution/proxy_config_with_annotation.h"
+
+namespace chromeos {
+
+// Translates the proxy from a crosapi mojo representation to an internal //net
+// proxy representation. Used when sending the proxy configuration set by an
+// extension in the Lacros primary profile to Ash-Chrome.
+net::ProxyConfigWithAnnotation CrosapiProxyToNetProxy(
+ crosapi::mojom::ProxyConfigPtr crosapi_proxy);
+
+// Translates the proxy from an internal //net proxy representation to a crosapi
+// mojo representation.
+crosapi::mojom::ProxyConfigPtr NetProxyToCrosapiProxy(
+ const net::ProxyConfigWithAnnotation& proxy_config);
+
+} // namespace chromeos
+#endif // CHROME_BROWSER_LACROS_NET_NETWORK_SETTINGS_TRANSLATION_H_
diff --git a/chrome/browser/lacros/net/network_settings_translation_crosapi.cc b/chrome/browser/lacros/net/network_settings_translation_crosapi.cc
new file mode 100644
index 0000000..8fafe4e
--- /dev/null
+++ b/chrome/browser/lacros/net/network_settings_translation_crosapi.cc
@@ -0,0 +1,122 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/lacros/net/network_settings_translation.h"
+
+#include "components/proxy_config/proxy_config_pref_names.h"
+#include "components/proxy_config/proxy_prefs.h"
+#include "net/base/host_port_pair.h"
+#include "net/base/proxy_server.h"
+#include "net/proxy_resolution/proxy_config.h"
+#include "net/proxy_resolution/proxy_list.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+
+namespace {
+
+constexpr net::NetworkTrafficAnnotationTag kAshProxyConfigTrafficAnnotation =
+ net::DefineNetworkTrafficAnnotation("proxy_config_system", R"(
+ semantics {
+ sender: "Proxy Config"
+ description:
+ "Establishing a connection through a proxy server using system proxy "
+ "settings."
+ trigger:
+ "Whenever a network request is made when the system proxy settings "
+ "are used, and they indicate to use a proxy server."
+ data:
+ "Proxy configuration."
+ destination: OTHER
+ destination_other:
+ "The proxy server specified in the configuration."
+ }
+ policy {
+ cookies_allowed: NO
+ setting:
+ "User cannot override system proxy settings, but can change them "
+ "through the Chrome OS Network Settings UI."
+ policy_exception_justification:
+ "Using either of 'ProxyMode', 'ProxyServer', or 'ProxyPacUrl' "
+ "policies can set Chrome to use a specific proxy settings and avoid "
+ "system proxy."
+ })");
+
+net::ProxyConfigWithAnnotation TranslatePacProxySettings(
+ crosapi::mojom::ProxySettingsPacPtr proxy_settings) {
+ if (!proxy_settings->pac_url.is_valid())
+ return net::ProxyConfigWithAnnotation::CreateDirect();
+ net::ProxyConfig proxy_config =
+ net::ProxyConfig::CreateFromCustomPacURL(proxy_settings->pac_url);
+ if (proxy_settings->pac_mandatory)
+ proxy_config.set_pac_mandatory(proxy_settings->pac_mandatory);
+ return net::ProxyConfigWithAnnotation(proxy_config,
+ kAshProxyConfigTrafficAnnotation);
+}
+
+net::ProxyConfigWithAnnotation TranslateWpadProxySettings(
+ crosapi::mojom::ProxySettingsWpadPtr proxy_settings) {
+ // Ash-Chrome has it's own mechanisms for detecting the PAC URL when
+ // configured via WPAD.
+ net::ProxyConfig proxy_config = net::ProxyConfig::CreateAutoDetect();
+ return net::ProxyConfigWithAnnotation(proxy_config,
+ kAshProxyConfigTrafficAnnotation);
+}
+
+net::ProxyConfigWithAnnotation TranslateManualProxySettings(
+ crosapi::mojom::ProxySettingsManualPtr proxy_settings) {
+ net::ProxyConfig proxy_config = net::ProxyConfig();
+ proxy_config.proxy_rules().type =
+ net::ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME;
+
+ for (auto const& proxy : proxy_settings->http_proxies) {
+ proxy_config.proxy_rules().proxies_for_http.AddProxyServer(
+ net::ProxyServer(net::ProxyServer::Scheme::SCHEME_HTTP,
+ net::HostPortPair(proxy->host, proxy->port)));
+ }
+ for (auto const& proxy : proxy_settings->secure_http_proxies) {
+ proxy_config.proxy_rules().proxies_for_https.AddProxyServer(
+ net::ProxyServer(net::ProxyServer::Scheme::SCHEME_HTTPS,
+ net::HostPortPair(proxy->host, proxy->port)));
+ }
+ for (auto const& proxy : proxy_settings->socks_proxies) {
+ // See `net::ProxyServer::GetSchemeFromPacTypeInternal()`.
+ proxy_config.proxy_rules().fallback_proxies.AddProxyServer(
+ net::ProxyServer(net::ProxyServer::Scheme::SCHEME_SOCKS4,
+ net::HostPortPair(proxy->host, proxy->port)));
+ }
+
+ for (const auto& domains : proxy_settings->exclude_domains) {
+ proxy_config.proxy_rules().bypass_rules.AddRuleFromString(domains);
+ }
+ return net::ProxyConfigWithAnnotation(proxy_config,
+ kAshProxyConfigTrafficAnnotation);
+}
+
+} // namespace
+
+namespace chromeos {
+
+net::ProxyConfigWithAnnotation CrosapiProxyToNetProxy(
+ crosapi::mojom::ProxyConfigPtr crosapi_proxy) {
+ if (!crosapi_proxy)
+ return net::ProxyConfigWithAnnotation::CreateDirect();
+
+ if (crosapi_proxy->proxy_settings->is_direct())
+ return net::ProxyConfigWithAnnotation::CreateDirect();
+
+ if (crosapi_proxy->proxy_settings->is_pac())
+ return TranslatePacProxySettings(
+ std::move(crosapi_proxy->proxy_settings->get_pac()));
+
+ if (crosapi_proxy->proxy_settings->is_wpad())
+ return TranslateWpadProxySettings(
+ std::move(crosapi_proxy->proxy_settings->get_wpad()));
+
+ if (crosapi_proxy->proxy_settings->is_manual())
+ return TranslateManualProxySettings(
+ std::move(crosapi_proxy->proxy_settings->get_manual()));
+
+ return net::ProxyConfigWithAnnotation::CreateDirect();
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/lacros/net/network_settings_translation_net_proxy.cc b/chrome/browser/lacros/net/network_settings_translation_net_proxy.cc
new file mode 100644
index 0000000..db3da75
--- /dev/null
+++ b/chrome/browser/lacros/net/network_settings_translation_net_proxy.cc
@@ -0,0 +1,103 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/lacros/net/network_settings_translation.h"
+
+#include "base/strings/string_split.h"
+#include "components/proxy_config/proxy_config_dictionary.h"
+#include "components/proxy_config/proxy_config_pref_names.h"
+#include "components/proxy_config/proxy_prefs.h"
+#include "net/base/host_port_pair.h"
+#include "net/base/proxy_server.h"
+#include "net/proxy_resolution/proxy_config.h"
+#include "net/proxy_resolution/proxy_list.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+
+namespace {
+
+std::vector<crosapi::mojom::ProxyLocationPtr> TranslateProxyLocations(
+ const net::ProxyList& proxy_list) {
+ std::vector<net::ProxyServer> proxies = proxy_list.GetAll();
+ std::vector<crosapi::mojom::ProxyLocationPtr> ptr_list;
+ crosapi::mojom::ProxyLocationPtr ptr;
+ for (const auto& proxy : proxies) {
+ ptr = crosapi::mojom::ProxyLocation::New();
+ ptr->host = proxy.host_port_pair().host();
+ ptr->port = proxy.host_port_pair().port();
+ ptr_list.push_back(std::move(ptr));
+ }
+ return ptr_list;
+}
+
+crosapi::mojom::ProxySettingsManualPtr TranslateManualProxySettings(
+ const net::ProxyConfig::ProxyRules& rules) {
+ crosapi::mojom::ProxySettingsManualPtr ptr =
+ crosapi::mojom::ProxySettingsManual::New();
+ switch (rules.type) {
+ case net::ProxyConfig::ProxyRules::Type::EMPTY:
+ return nullptr;
+ case net::ProxyConfig::ProxyRules::Type::PROXY_LIST:
+ ptr->http_proxies = TranslateProxyLocations(rules.single_proxies);
+ ptr->secure_http_proxies = TranslateProxyLocations(rules.single_proxies);
+ ptr->socks_proxies = TranslateProxyLocations(rules.single_proxies);
+ break;
+ case net::ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME:
+ ptr->http_proxies = TranslateProxyLocations(rules.proxies_for_http);
+ ptr->secure_http_proxies =
+ TranslateProxyLocations(rules.proxies_for_https);
+ ptr->socks_proxies = TranslateProxyLocations(rules.fallback_proxies);
+ break;
+ }
+
+ for (const auto& domain : rules.bypass_rules.rules()) {
+ ptr->exclude_domains.push_back(domain->ToString());
+ }
+ return ptr;
+}
+
+crosapi::mojom::ProxySettingsPtr NetProxyToProxySettings(
+ const net::ProxyConfigWithAnnotation& net_proxy) {
+ net::ProxyConfig proxy_config = net_proxy.value();
+ auto proxy_settings = crosapi::mojom::ProxySettings::New();
+ if (proxy_config.proxy_rules().empty() &&
+ !proxy_config.HasAutomaticSettings()) {
+ proxy_settings->set_direct(crosapi::mojom::ProxySettingsDirect::New());
+ return proxy_settings;
+ }
+
+ if (proxy_config.has_pac_url()) {
+ auto pac = crosapi::mojom::ProxySettingsPac::New();
+ pac->pac_url = proxy_config.pac_url();
+ pac->pac_mandatory = proxy_config.pac_mandatory();
+ proxy_settings->set_pac(std::move(pac));
+ return proxy_settings;
+ }
+
+ if (proxy_config.auto_detect()) {
+ proxy_settings->set_wpad(crosapi::mojom::ProxySettingsWpad::New());
+ return proxy_settings;
+ }
+
+ crosapi::mojom::ProxySettingsManualPtr manual =
+ TranslateManualProxySettings(proxy_config.proxy_rules());
+ if (!manual) {
+ proxy_settings->set_direct(crosapi::mojom::ProxySettingsDirect::New());
+ return proxy_settings;
+ }
+ proxy_settings->set_manual(std::move(manual));
+ return proxy_settings;
+}
+
+} // namespace
+
+namespace chromeos {
+
+crosapi::mojom::ProxyConfigPtr NetProxyToCrosapiProxy(
+ const net::ProxyConfigWithAnnotation& net_proxy) {
+ auto proxy_config = crosapi::mojom::ProxyConfig::New();
+ proxy_config->proxy_settings = NetProxyToProxySettings(net_proxy);
+ return proxy_config;
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/lacros/net/network_settings_translation_unittest.cc b/chrome/browser/lacros/net/network_settings_translation_unittest.cc
new file mode 100644
index 0000000..aed511f
--- /dev/null
+++ b/chrome/browser/lacros/net/network_settings_translation_unittest.cc
@@ -0,0 +1,202 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/lacros/net/network_settings_translation.h"
+
+#include "chromeos/crosapi/mojom/network_settings_service.mojom.h"
+#include "components/proxy_config/pref_proxy_config_tracker_impl.h"
+#include "components/proxy_config/proxy_config_dictionary.h"
+#include "net/base/proxy_server.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+constexpr char kPacUrl[] = "http://pac.pac/";
+
+} // namespace
+
+namespace chromeos {
+
+TEST(NetworkSettingsTranslationTest, NetProxyToCrosapiProxyDirect) {
+ crosapi::mojom::ProxyConfigPtr actual =
+ NetProxyToCrosapiProxy(net::ProxyConfigWithAnnotation::CreateDirect());
+ EXPECT_TRUE(actual->proxy_settings->is_direct());
+}
+
+TEST(NetworkSettingsTranslationTest, NetProxyToCrosapiProxyWpad) {
+ crosapi::mojom::ProxyConfigPtr actual =
+ NetProxyToCrosapiProxy(net::ProxyConfigWithAnnotation(
+ net::ProxyConfig::CreateAutoDetect(), TRAFFIC_ANNOTATION_FOR_TESTS));
+ EXPECT_TRUE(actual->proxy_settings->is_wpad());
+}
+
+TEST(NetworkSettingsTranslationTest, NetProxyToCrosapiProxyPacNotMandatory) {
+ net::ProxyConfig config =
+ net::ProxyConfig::CreateFromCustomPacURL(GURL(kPacUrl));
+
+ crosapi::mojom::ProxyConfigPtr actual = NetProxyToCrosapiProxy(
+ net::ProxyConfigWithAnnotation(config, TRAFFIC_ANNOTATION_FOR_TESTS));
+ ASSERT_TRUE(actual->proxy_settings->is_pac());
+ EXPECT_EQ(actual->proxy_settings->get_pac()->pac_url, GURL(kPacUrl));
+ EXPECT_EQ(actual->proxy_settings->get_pac()->pac_mandatory, false);
+}
+
+TEST(NetworkSettingsTranslationTest, NetProxyToCrosapiProxyPacMandatory) {
+ net::ProxyConfig config =
+ net::ProxyConfig::CreateFromCustomPacURL(GURL(kPacUrl));
+ config.set_pac_mandatory(true);
+
+ crosapi::mojom::ProxyConfigPtr actual = NetProxyToCrosapiProxy(
+ net::ProxyConfigWithAnnotation(config, TRAFFIC_ANNOTATION_FOR_TESTS));
+ ASSERT_TRUE(actual->proxy_settings->is_pac());
+ EXPECT_EQ(actual->proxy_settings->get_pac()->pac_url, GURL(kPacUrl));
+ EXPECT_EQ(actual->proxy_settings->get_pac()->pac_mandatory, true);
+}
+
+TEST(NetworkSettingsTranslationTest, NetProxyToCrosapiProxyManual) {
+ net::ProxyConfig config;
+ config.proxy_rules().ParseFromString(
+ "http=proxy:80;https=secure_proxy:81;socks=socks_proxy:82;");
+ config.proxy_rules().bypass_rules.ParseFromString("localhost;google.com;");
+
+ crosapi::mojom::ProxyConfigPtr actual = NetProxyToCrosapiProxy(
+ net::ProxyConfigWithAnnotation(config, TRAFFIC_ANNOTATION_FOR_TESTS));
+ ASSERT_TRUE(actual->proxy_settings->is_manual());
+ std::vector<crosapi::mojom::ProxyLocationPtr> proxy_ptr =
+ std::move(actual->proxy_settings->get_manual()->http_proxies);
+ ASSERT_EQ(proxy_ptr.size(), 1u);
+ EXPECT_EQ(proxy_ptr[0]->host, "proxy");
+ EXPECT_EQ(proxy_ptr[0]->port, 80);
+
+ proxy_ptr =
+ std::move(actual->proxy_settings->get_manual()->secure_http_proxies);
+ ASSERT_EQ(proxy_ptr.size(), 1u);
+ EXPECT_EQ(proxy_ptr[0]->host, "secure_proxy");
+ EXPECT_EQ(proxy_ptr[0]->port, 81);
+
+ proxy_ptr = std::move(actual->proxy_settings->get_manual()->socks_proxies);
+ ASSERT_EQ(proxy_ptr.size(), 1u);
+ EXPECT_EQ(proxy_ptr[0]->host, "socks_proxy");
+ EXPECT_EQ(proxy_ptr[0]->port, 82);
+
+ const std::vector<std::string> exclude_domains =
+ actual->proxy_settings->get_manual()->exclude_domains;
+ ASSERT_EQ(exclude_domains.size(), 2u);
+ EXPECT_EQ(exclude_domains[0], "localhost");
+ EXPECT_EQ(exclude_domains[1], "google.com");
+}
+
+TEST(NetworkSettingsTranslationTest,
+ NetProxyToCrosapiProxyManualFromSingleProxies) {
+ net::ProxyConfig config;
+ config.proxy_rules().ParseFromString("proxy:80;");
+
+ crosapi::mojom::ProxyConfigPtr actual = NetProxyToCrosapiProxy(
+ net::ProxyConfigWithAnnotation(config, TRAFFIC_ANNOTATION_FOR_TESTS));
+ ASSERT_TRUE(actual->proxy_settings->is_manual());
+ std::vector<crosapi::mojom::ProxyLocationPtr> proxy_ptr =
+ std::move(actual->proxy_settings->get_manual()->http_proxies);
+ ASSERT_EQ(proxy_ptr.size(), 1u);
+ EXPECT_EQ(proxy_ptr[0]->host, "proxy");
+ EXPECT_EQ(proxy_ptr[0]->port, 80);
+
+ proxy_ptr =
+ std::move(actual->proxy_settings->get_manual()->secure_http_proxies);
+ ASSERT_EQ(proxy_ptr.size(), 1u);
+ EXPECT_EQ(proxy_ptr[0]->host, "proxy");
+ EXPECT_EQ(proxy_ptr[0]->port, 80);
+
+ proxy_ptr = std::move(actual->proxy_settings->get_manual()->socks_proxies);
+ ASSERT_EQ(proxy_ptr.size(), 1u);
+ EXPECT_EQ(proxy_ptr[0]->host, "proxy");
+ EXPECT_EQ(proxy_ptr[0]->port, 80);
+}
+
+TEST(NetworkSettingsTranslationTest, NetProxyToCrosapiProxyManualEmptyList) {
+ net::ProxyConfig config;
+ config.proxy_rules().ParseFromString("");
+ crosapi::mojom::ProxyConfigPtr actual = NetProxyToCrosapiProxy(
+ net::ProxyConfigWithAnnotation(config, TRAFFIC_ANNOTATION_FOR_TESTS));
+ EXPECT_TRUE(actual->proxy_settings->is_direct());
+}
+
+TEST(NetworkSettingsTranslationTest, CrosapiProxyToNetProxyDirect) {
+ crosapi::mojom::ProxyConfigPtr ptr = crosapi::mojom::ProxyConfig::New();
+ crosapi::mojom::ProxySettingsPtr proxy = crosapi::mojom::ProxySettings::New();
+ crosapi::mojom::ProxySettingsDirectPtr direct =
+ crosapi::mojom::ProxySettingsDirect::New();
+ proxy->set_direct(std::move(direct));
+ ptr->proxy_settings = std::move(proxy);
+
+ EXPECT_EQ(CrosapiProxyToNetProxy(std::move(ptr)).value().ToValue(),
+ net::ProxyConfig::CreateDirect().ToValue());
+}
+
+TEST(NetworkSettingsTranslationTest, CrosapiProxyToNetProxyWpad) {
+ crosapi::mojom::ProxyConfigPtr ptr = crosapi::mojom::ProxyConfig::New();
+ crosapi::mojom::ProxySettingsPtr proxy = crosapi::mojom::ProxySettings::New();
+ crosapi::mojom::ProxySettingsWpadPtr wpad =
+ crosapi::mojom::ProxySettingsWpad::New();
+ proxy->set_wpad(std::move(wpad));
+ ptr->proxy_settings = std::move(proxy);
+
+ auto actual = CrosapiProxyToNetProxy(std::move(ptr));
+ EXPECT_TRUE(actual.value().auto_detect());
+}
+
+TEST(NetworkSettingsTranslationTest, CrosapiProxyToNetProxyPac) {
+ crosapi::mojom::ProxyConfigPtr ptr = crosapi::mojom::ProxyConfig::New();
+ crosapi::mojom::ProxySettingsPtr proxy = crosapi::mojom::ProxySettings::New();
+ crosapi::mojom::ProxySettingsPacPtr pac =
+ crosapi::mojom::ProxySettingsPac::New();
+ pac->pac_url = GURL(kPacUrl);
+ pac->pac_mandatory = true;
+ proxy->set_pac(pac.Clone());
+ ptr->proxy_settings = proxy.Clone();
+ auto actual = CrosapiProxyToNetProxy(ptr.Clone());
+ EXPECT_FALSE(actual.value().auto_detect());
+ EXPECT_EQ(actual.value().pac_url(), GURL(kPacUrl));
+ EXPECT_TRUE(actual.value().pac_mandatory());
+
+ pac->pac_mandatory = false;
+ proxy->set_pac(std::move(pac));
+ ptr->proxy_settings = std::move(proxy);
+ actual = CrosapiProxyToNetProxy(std::move(ptr));
+ EXPECT_FALSE(actual.value().pac_mandatory());
+}
+
+TEST(NetworkSettingsTranslationTest, CrosapiProxyToNetProxyManual) {
+ crosapi::mojom::ProxyConfigPtr ptr = crosapi::mojom::ProxyConfig::New();
+ crosapi::mojom::ProxySettingsPtr proxy = crosapi::mojom::ProxySettings::New();
+ crosapi::mojom::ProxySettingsManualPtr manual =
+ crosapi::mojom::ProxySettingsManual::New();
+ crosapi::mojom::ProxyLocationPtr location =
+ crosapi::mojom::ProxyLocation::New();
+ location->host = "proxy";
+ location->port = 80;
+ manual->http_proxies.push_back(location.Clone());
+ location->host = "secure_proxy";
+ location->port = 81;
+ manual->secure_http_proxies.push_back(location.Clone());
+ location->host = "socks_proxy";
+ location->port = 82;
+ manual->socks_proxies.push_back(std::move(location));
+ manual->exclude_domains = {"localhost", "google.com"};
+ proxy->set_manual(std::move(manual));
+ ptr->proxy_settings = std::move(proxy);
+
+ auto actual = CrosapiProxyToNetProxy(std::move(ptr));
+
+ EXPECT_EQ(actual.value().proxy_rules().proxies_for_http.ToPacString(),
+ "PROXY proxy:80");
+ EXPECT_EQ(actual.value().proxy_rules().proxies_for_https.ToPacString(),
+ "HTTPS secure_proxy:81");
+ EXPECT_EQ(actual.value().proxy_rules().fallback_proxies.ToPacString(),
+ "SOCKS socks_proxy:82");
+ EXPECT_EQ(actual.value().proxy_rules().bypass_rules.ToString(),
+ "localhost;google.com;");
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/lacros/net/proxy_config_service_lacros.cc b/chrome/browser/lacros/net/proxy_config_service_lacros.cc
new file mode 100644
index 0000000..fc3b156
--- /dev/null
+++ b/chrome/browser/lacros/net/proxy_config_service_lacros.cc
@@ -0,0 +1,115 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/lacros/net/proxy_config_service_lacros.h"
+
+#include <memory>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/callback_helpers.h"
+#include "base/logging.h"
+#include "base/values.h"
+#include "chrome/browser/lacros/net/network_settings_translation.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/common/pref_names.h"
+#include "chromeos/lacros/lacros_service.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+#include "net/proxy_resolution/proxy_config.h"
+#include "net/proxy_resolution/proxy_config_with_annotation.h"
+
+namespace {
+
+net::ProxyConfigWithAnnotation GetConfigOrDirect(
+ const absl::optional<net::ProxyConfigWithAnnotation>& optional_config,
+ PrefService* pref_service) {
+ if (!optional_config || !pref_service ||
+ !pref_service->GetBoolean(prefs::kUseAshProxy)) {
+ net::ProxyConfigWithAnnotation config =
+ net::ProxyConfigWithAnnotation::CreateDirect();
+ return config;
+ }
+ return optional_config.value();
+}
+} // namespace
+
+namespace chromeos {
+
+ProxyConfigServiceLacros::ProxyConfigServiceLacros(Profile* profile) {
+ DCHECK(profile);
+ auto* lacros_service = chromeos::LacrosService::Get();
+ // crosapi is disabled in browser_tests.
+ if (!lacros_service->IsAvailable<crosapi::mojom::NetworkSettingsService>()) {
+ LOG(ERROR) << "The NetworkSettingsService service is not available";
+ return;
+ }
+ lacros_service->GetRemote<crosapi::mojom::NetworkSettingsService>()
+ ->AddNetworkSettingsObserver(receiver_.BindNewPipeAndPassRemote());
+
+ // `kUseAshProxy` is a user exposed setting whether to use the ash proxy (from
+ // the system) or whether to use profile specific proxy settings. This option
+ // is only given for secondary profiles. For the primary profile, the user has
+ // to use the system proxy settings, the value of kUseAshProxy is always true,
+ // and the setting is not exposed to the user.
+ // TODO(acostinas, b:192915915) Enable secondary profiles to configure
+ // `kUseAshProxy` from chrome://settings.
+ if (profile->IsMainProfile()) {
+ profile->GetPrefs()->SetBoolean(prefs::kUseAshProxy, true);
+ }
+
+ profile_prefs_ = profile->GetPrefs();
+ profile_pref_change_registrar_.Init(profile_prefs_);
+ profile_pref_change_registrar_.Add(
+ prefs::kUseAshProxy,
+ base::BindRepeating(&ProxyConfigServiceLacros::OnUseAshProxyPrefChanged,
+ base::Unretained(this)));
+}
+
+ProxyConfigServiceLacros::~ProxyConfigServiceLacros() = default;
+
+void ProxyConfigServiceLacros::OnProxyChanged(
+ crosapi::mojom::ProxyConfigPtr proxy_config) {
+ cached_config_ = CrosapiProxyToNetProxy(std::move(proxy_config));
+ NotifyObservers();
+}
+
+void ProxyConfigServiceLacros::OnUseAshProxyPrefChanged() {
+ NotifyObservers();
+}
+
+void ProxyConfigServiceLacros::NotifyObservers() {
+ for (auto& observer : observers_) {
+ observer.OnProxyConfigChanged(
+ GetConfigOrDirect(cached_config_, profile_prefs_),
+ ConfigAvailability::CONFIG_VALID);
+ }
+}
+
+void ProxyConfigServiceLacros::AddObserver(Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+void ProxyConfigServiceLacros::RemoveObserver(Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+// static
+void ProxyConfigServiceLacros::RegisterProfilePrefs(
+ PrefRegistrySimple* registry) {
+ registry->RegisterBooleanPref(prefs::kUseAshProxy, false);
+}
+
+net::ProxyConfigService::ConfigAvailability
+ProxyConfigServiceLacros::GetLatestProxyConfig(
+ net::ProxyConfigWithAnnotation* config) {
+ // Returns the last proxy configuration that the Ash
+ // NetworkSettingsService notified us, or the direct proxy if `cached_config_`
+ // is not set.
+ *config = GetConfigOrDirect(cached_config_, profile_prefs_);
+ return ConfigAvailability::CONFIG_VALID;
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/lacros/net/proxy_config_service_lacros.h b/chrome/browser/lacros/net/proxy_config_service_lacros.h
new file mode 100644
index 0000000..84697bc
--- /dev/null
+++ b/chrome/browser/lacros/net/proxy_config_service_lacros.h
@@ -0,0 +1,71 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_LACROS_NET_PROXY_CONFIG_SERVICE_LACROS_H_
+#define CHROME_BROWSER_LACROS_NET_PROXY_CONFIG_SERVICE_LACROS_H_
+
+#include "base/observer_list.h"
+#include "chromeos/crosapi/mojom/network_settings_service.mojom.h"
+#include "components/prefs/pref_change_registrar.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "net/proxy_resolution/proxy_config_service.h"
+#include "net/proxy_resolution/proxy_config_with_annotation.h"
+
+class PrefRegistrySimple;
+class PrefService;
+class Profile;
+
+namespace chromeos {
+
+// Implementation of ProxyConfigService that retrieves the system proxy
+// settings from Ash-Chrome via the mojo API. Unlike other
+// net::ProxyConfigService implementations used as base service, this class will
+// only forward the system proxy retrieved from Ash-Chrome if allowed by pref
+// kUseAshProxy.
+class ProxyConfigServiceLacros
+ : public net::ProxyConfigService,
+ public crosapi::mojom::NetworkSettingsObserver {
+ public:
+ explicit ProxyConfigServiceLacros(Profile* profile);
+
+ ProxyConfigServiceLacros(const ProxyConfigServiceLacros&) = delete;
+ ProxyConfigServiceLacros& operator=(const ProxyConfigServiceLacros&) = delete;
+ ~ProxyConfigServiceLacros() override;
+
+ // net::ProxyConfigService impl
+ void AddObserver(Observer* observer) override;
+ void RemoveObserver(Observer* observer) override;
+ ProxyConfigService::ConfigAvailability GetLatestProxyConfig(
+ net::ProxyConfigWithAnnotation* config) override;
+
+ static void RegisterProfilePrefs(PrefRegistrySimple* registry);
+
+ private:
+ // crosapi::mojom::NetworkSettingsObserver impl
+ void OnProxyChanged(crosapi::mojom::ProxyConfigPtr proxy_config) override;
+
+ void OnUseAshProxyPrefChanged();
+
+ void NotifyObservers();
+
+ // Owned by the Profile instance.
+ PrefService* profile_prefs_ = nullptr;
+
+ PrefChangeRegistrar profile_pref_change_registrar_;
+
+ // TODO(acostinas, b/200001678): Use checked observers.
+ base::ObserverList<net::ProxyConfigService::Observer>::Unchecked observers_;
+ // Receives mojo messages from Ash-Chrome.
+ mojo::Receiver<crosapi::mojom::NetworkSettingsObserver> receiver_{this};
+ // The latest proxy configuration sent by Ash-Chrome via mojo. This proxy is
+ // enforced in the browser only if the pref kUseAshProxy=true and the
+ // kProxy pref, which has precedence, is unset or set to mode=system.
+ absl::optional<net::ProxyConfigWithAnnotation> cached_config_;
+
+ base::WeakPtrFactory<ProxyConfigServiceLacros> weak_ptr_factory_{this};
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_LACROS_NET_PROXY_CONFIG_SERVICE_LACROS_H_
diff --git a/chrome/browser/lacros/net/proxy_config_service_lacros_browsertest.cc b/chrome/browser/lacros/net/proxy_config_service_lacros_browsertest.cc
new file mode 100644
index 0000000..1c55e15
--- /dev/null
+++ b/chrome/browser/lacros/net/proxy_config_service_lacros_browsertest.cc
@@ -0,0 +1,297 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/lacros/net/proxy_config_service_lacros.h"
+
+#include "base/time/time.h"
+#include "chrome/browser/lacros/net/network_settings_translation.h"
+#include "chrome/browser/net/proxy_service_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chromeos/crosapi/mojom/network_settings_service.mojom.h"
+#include "chromeos/lacros/lacros_service.h"
+#include "components/prefs/pref_service.h"
+#include "components/proxy_config/pref_proxy_config_tracker_impl.h"
+#include "components/proxy_config/proxy_config_dictionary.h"
+#include "components/proxy_config/proxy_config_pref_names.h"
+#include "components/proxy_config/proxy_prefs.h"
+#include "content/public/test/browser_test.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "net/proxy_resolution/proxy_config_service.h"
+
+namespace {
+
+constexpr char kPacUrl[] = "pac.pac";
+
+// Fakes the NetworkSettingsService in Ash-Chrome so we can send proxy updates
+// from the tests via the mojo API.
+class FakeNetworkSettingsService
+ : public crosapi::mojom::NetworkSettingsService {
+ public:
+ FakeNetworkSettingsService() = default;
+ FakeNetworkSettingsService(const FakeNetworkSettingsService&) = delete;
+ FakeNetworkSettingsService& operator=(const FakeNetworkSettingsService&) =
+ delete;
+ ~FakeNetworkSettingsService() override = default;
+
+ bool HasObserver() { return observer_.is_bound(); }
+
+ // crosapi::mojom::AshNetworService:
+ void AddNetworkSettingsObserver(
+ mojo::PendingRemote<crosapi::mojom::NetworkSettingsObserver> observer)
+ override {
+ observer_ = mojo::Remote<crosapi::mojom::NetworkSettingsObserver>(
+ std::move(observer));
+ if (quit_closure_) {
+ std::move(quit_closure_).Run();
+ }
+ }
+
+ void SetQuitClosure(base::OnceClosure quit_closure) {
+ quit_closure_ = std::move(quit_closure);
+ }
+
+ void SendProxyUpdate(crosapi::mojom::ProxyConfigPtr proxy_config) {
+ if (observer_) {
+ observer_->OnProxyChanged(std::move(proxy_config));
+ }
+ }
+
+ private:
+ mojo::Remote<crosapi::mojom::NetworkSettingsObserver> observer_;
+ base::OnceClosure quit_closure_;
+};
+
+// Fakes the ProxyConfigMonitor which is the class that sends the proxy updates
+// to the Browser's NetworkService process via mojo.
+class FakeProxyMonitor : public net::ProxyConfigService::Observer {
+ public:
+ FakeProxyMonitor() = default;
+ FakeProxyMonitor(const FakeProxyMonitor&) = delete;
+ FakeProxyMonitor& operator=(const FakeProxyMonitor&) = delete;
+ ~FakeProxyMonitor() override = default;
+
+ void OnProxyConfigChanged(
+ const net::ProxyConfigWithAnnotation& config,
+ net::ProxyConfigService::ConfigAvailability availability) override {
+ cached_proxy_config_ = std::move(config);
+ if (quit_closure_) {
+ std::move(quit_closure_).Run();
+ }
+ }
+
+ void SetQuitClosure(base::OnceClosure quit_closure) {
+ quit_closure_ = std::move(quit_closure);
+ }
+ net::ProxyConfigWithAnnotation cached_proxy_config_;
+
+ private:
+ base::OnceClosure quit_closure_;
+};
+
+} // namespace
+
+namespace chromeos {
+
+class ProxyConfigServiceLacrosTest : public InProcessBrowserTest {
+ protected:
+ ProxyConfigServiceLacrosTest() = default;
+
+ ProxyConfigServiceLacrosTest(const ProxyConfigServiceLacrosTest&) = delete;
+ ProxyConfigServiceLacrosTest& operator=(const ProxyConfigServiceLacrosTest&) =
+ delete;
+ ~ProxyConfigServiceLacrosTest() override = default;
+ mojo::Remote<crosapi::mojom::NetworkSettingsService>
+ network_settings_service_;
+
+ bool IsServiceAvailable() {
+ auto* lacros_service = chromeos::LacrosService::Get();
+ if (!lacros_service)
+ return false;
+ return lacros_service
+ ->IsAvailable<crosapi::mojom::NetworkSettingsService>();
+ }
+
+ void SetUpOnMainThread() override {
+ InProcessBrowserTest::SetUpOnMainThread();
+ // If the lacros service or the network settings service interface are not
+ // available on this version of ash-chrome, this test suite will no-op.
+ if (!IsServiceAvailable())
+ return;
+ // Replace the production network settings service with a fake for testing.
+ mojo::Remote<crosapi::mojom::NetworkSettingsService>& remote =
+ chromeos::LacrosService::Get()
+ ->GetRemote<crosapi::mojom::NetworkSettingsService>();
+ remote.reset();
+ receiver_.Bind(remote.BindNewPipeAndPassReceiver());
+
+ pref_proxy_config_tracker_ =
+ ProxyServiceFactory::CreatePrefProxyConfigTrackerOfProfile(
+ browser()->profile()->GetPrefs(), nullptr);
+
+ base::RunLoop run_loop;
+ service_.SetQuitClosure(run_loop.QuitClosure());
+ proxy_config_service_ = ProxyServiceFactory::CreateProxyConfigService(
+ pref_proxy_config_tracker_.get(), browser()->profile());
+ // Wait for the mojom::NetworkSettingsObserver created by
+ // `proxy_config_service_` in Lacros to be added as an observer to the
+ // AshNetworkSettingsService in Ash-Chrome.
+ run_loop.Run();
+
+ proxy_monitor_ = std::make_unique<FakeProxyMonitor>();
+ proxy_config_service_->AddObserver(proxy_monitor_.get());
+ }
+
+ void TearDownOnMainThread() override {
+ proxy_config_service_->RemoveObserver(proxy_monitor_.get());
+ pref_proxy_config_tracker_->DetachFromPrefService();
+ pref_proxy_config_tracker_.reset();
+ proxy_config_service_.reset();
+ proxy_monitor_.reset();
+ base::RunLoop().RunUntilIdle();
+ }
+
+ protected:
+ // Sends a proxy update via the AshNetworkSettingService in Ash-Chrome and
+ // waits for `proxy_monitor_` in Lacros-Chrome to receive the config.
+ void SendAshProxyUpdateAndWait(crosapi::mojom::ProxyConfigPtr proxy_config) {
+ base::RunLoop run_loop;
+ proxy_monitor_->SetQuitClosure(run_loop.QuitClosure());
+ service_.SendProxyUpdate(std::move(proxy_config));
+ run_loop.Run();
+ }
+
+ std::unique_ptr<net::ProxyConfigService> proxy_config_service_;
+ // Monitors global and profile prefs related to proxy configuration.
+ std::unique_ptr<PrefProxyConfigTracker> pref_proxy_config_tracker_;
+ // Fakes the ProxyConfigMonitor which directly updates the Browser's
+ // NetworkService process.
+ std::unique_ptr<FakeProxyMonitor> proxy_monitor_;
+ FakeNetworkSettingsService service_;
+ mojo::Receiver<crosapi::mojom::NetworkSettingsService> receiver_{&service_};
+};
+
+// Tests that the chromeos::ProxyConfigServiceLacros instance internally created
+// by `proxy_config_service_` is added to Ash-Chrome as an observer for network
+// changes.
+IN_PROC_BROWSER_TEST_F(ProxyConfigServiceLacrosTest, ObserverSet) {
+ if (!IsServiceAvailable())
+ return;
+ ASSERT_TRUE(service_.HasObserver());
+}
+
+// Tests that proxy updates from the AshNetworkService in Ash-Chrome are
+// correctly propagated to observers of the `proxy_config_service_` in
+// Lacros-Chrome.
+IN_PROC_BROWSER_TEST_F(ProxyConfigServiceLacrosTest, ProxyUpdates) {
+ if (!IsServiceAvailable())
+ return;
+
+ crosapi::mojom::ProxyConfigPtr proxy_config =
+ crosapi::mojom::ProxyConfig::New();
+ proxy_config->proxy_settings = crosapi::mojom::ProxySettings::New();
+
+ proxy_config->proxy_settings->set_direct(
+ crosapi::mojom::ProxySettingsDirect::New());
+ SendAshProxyUpdateAndWait(proxy_config.Clone());
+ EXPECT_EQ(proxy_monitor_->cached_proxy_config_.value().ToValue(),
+ net::ProxyConfig::CreateDirect().ToValue());
+
+ crosapi::mojom::ProxySettingsWpadPtr wpad =
+ crosapi::mojom::ProxySettingsWpad::New();
+ wpad->pac_url = GURL(kPacUrl);
+ proxy_config->proxy_settings->set_wpad(
+ crosapi::mojom::ProxySettingsWpad::New());
+ SendAshProxyUpdateAndWait(proxy_config.Clone());
+ EXPECT_EQ(proxy_monitor_->cached_proxy_config_.value().ToValue(),
+ CrosapiProxyToNetProxy(proxy_config.Clone()).value().ToValue());
+
+ crosapi::mojom::ProxySettingsManualPtr manual =
+ crosapi::mojom::ProxySettingsManual::New();
+ crosapi::mojom::ProxyLocationPtr location =
+ crosapi::mojom::ProxyLocation::New();
+ location->host = "proxy";
+ location->port = 80;
+ manual->secure_http_proxies.push_back(location.Clone());
+ manual->socks_proxies.push_back(location.Clone());
+ proxy_config->proxy_settings->set_manual(std::move(manual));
+ SendAshProxyUpdateAndWait(proxy_config.Clone());
+ EXPECT_EQ(proxy_monitor_->cached_proxy_config_.value().ToValue(),
+ CrosapiProxyToNetProxy(std::move(proxy_config)).value().ToValue());
+}
+
+// Tests that proxies set via the user pref `kProxy` have precedence over system
+// proxies coming from Ash-Chrome.
+IN_PROC_BROWSER_TEST_F(ProxyConfigServiceLacrosTest, UserPrefPrecedence) {
+ if (!IsServiceAvailable())
+ return;
+ // Set a proxy via pref.
+ base::RunLoop run_loop;
+ proxy_monitor_->SetQuitClosure(run_loop.QuitClosure());
+ base::Value proxy_config_wpad(base::Value::Type::DICTIONARY);
+ proxy_config_wpad.SetKey("mode",
+ base::Value(ProxyPrefs::kAutoDetectProxyModeName));
+ browser()->profile()->GetPrefs()->Set(proxy_config::prefs::kProxy,
+ proxy_config_wpad);
+ run_loop.Run();
+ // Verify that the pref proxy is applied.
+ EXPECT_EQ(proxy_monitor_->cached_proxy_config_.value().ToValue(),
+ net::ProxyConfig::CreateAutoDetect().ToValue());
+
+ // Set a system proxy via the AshNetworkSettingsService.
+ crosapi::mojom::ProxyConfigPtr proxy_config =
+ crosapi::mojom::ProxyConfig::New();
+ proxy_config->proxy_settings = crosapi::mojom::ProxySettings::New();
+ crosapi::mojom::ProxySettingsPacPtr pac =
+ crosapi::mojom::ProxySettingsPac::New();
+ pac->pac_url = GURL(kPacUrl);
+ proxy_config->proxy_settings->set_pac(std::move(pac));
+ service_.SendProxyUpdate(std::move(proxy_config));
+ base::RunLoop().RunUntilIdle();
+
+ // Verify that the pref proxy is still applied.
+ EXPECT_EQ(proxy_monitor_->cached_proxy_config_.value().ToValue(),
+ net::ProxyConfig::CreateAutoDetect().ToValue());
+
+ // Remove the pref and verify that the system proxy is applied.
+ browser()->profile()->GetPrefs()->ClearPref(proxy_config::prefs::kProxy);
+ EXPECT_EQ(proxy_monitor_->cached_proxy_config_.value().ToValue(),
+ CrosapiProxyToNetProxy(std::move(proxy_config)).value().ToValue());
+}
+
+// Test that verifies that the system proxy sent from Ash-Chrome is only applied
+// if the pref `kUseAshProxy` is true.
+IN_PROC_BROWSER_TEST_F(ProxyConfigServiceLacrosTest, UseAshProxyPref) {
+ if (!IsServiceAvailable())
+ return;
+ browser()->profile()->GetPrefs()->SetBoolean(prefs::kUseAshProxy, false);
+ crosapi::mojom::ProxyConfigPtr proxy_config =
+ crosapi::mojom::ProxyConfig::New();
+ proxy_config->proxy_settings = crosapi::mojom::ProxySettings::New();
+ crosapi::mojom::ProxySettingsWpadPtr wpad =
+ crosapi::mojom::ProxySettingsWpad::New();
+ wpad->pac_url = GURL(kPacUrl);
+ proxy_config->proxy_settings->set_wpad(
+ crosapi::mojom::ProxySettingsWpad::New());
+ service_.SendProxyUpdate(proxy_config.Clone());
+ base::RunLoop().RunUntilIdle();
+ // Verify that the system proxy is not applied.
+ EXPECT_EQ(proxy_monitor_->cached_proxy_config_.value().ToValue(),
+ net::ProxyConfig::CreateDirect().ToValue());
+
+ browser()->profile()->GetPrefs()->SetBoolean(prefs::kUseAshProxy, true);
+ // Verify that the system proxy is applied.
+ EXPECT_EQ(proxy_monitor_->cached_proxy_config_.value().ToValue(),
+ CrosapiProxyToNetProxy(proxy_config.Clone()).value().ToValue());
+
+ // Verify that the system proxy is not applied.
+ browser()->profile()->GetPrefs()->SetBoolean(prefs::kUseAshProxy, false);
+ EXPECT_EQ(proxy_monitor_->cached_proxy_config_.value().ToValue(),
+ net::ProxyConfig::CreateDirect().ToValue());
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/net/proxy_config_monitor.cc b/chrome/browser/net/proxy_config_monitor.cc
index 55cc762b..583ae4a 100644
--- a/chrome/browser/net/proxy_config_monitor.cc
+++ b/chrome/browser/net/proxy_config_monitor.cc
@@ -52,7 +52,7 @@
}
proxy_config_service_ = ProxyServiceFactory::CreateProxyConfigService(
- pref_proxy_config_tracker_.get());
+ pref_proxy_config_tracker_.get(), profile);
proxy_config_service_->AddObserver(this);
}
@@ -66,8 +66,7 @@
local_state);
proxy_config_service_ = ProxyServiceFactory::CreateProxyConfigService(
- pref_proxy_config_tracker_.get());
-
+ pref_proxy_config_tracker_.get(), nullptr);
proxy_config_service_->AddObserver(this);
}
diff --git a/chrome/browser/net/proxy_service_factory.cc b/chrome/browser/net/proxy_service_factory.cc
index 9f6edc5..e340c32e 100644
--- a/chrome/browser/net/proxy_service_factory.cc
+++ b/chrome/browser/net/proxy_service_factory.cc
@@ -20,11 +20,16 @@
#include "chromeos/network/proxy/proxy_config_service_impl.h"
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+#include "chrome/browser/lacros/net/proxy_config_service_lacros.h"
+#endif // BUILDFLAG(IS_CHROMEOS_LACROS)
+
using content::BrowserThread;
// static
std::unique_ptr<net::ProxyConfigService>
-ProxyServiceFactory::CreateProxyConfigService(PrefProxyConfigTracker* tracker) {
+ProxyServiceFactory::CreateProxyConfigService(PrefProxyConfigTracker* tracker,
+ Profile* profile) {
// The linux gsettings-based proxy settings getter relies on being initialized
// from the UI thread. The system proxy config service could also get created
// without full browser process by launching service manager alone.
@@ -33,8 +38,17 @@
std::unique_ptr<net::ProxyConfigService> base_service;
-#if !BUILDFLAG(IS_CHROMEOS_ASH)
- // On ChromeOS, base service is NULL; chromeos::ProxyConfigServiceImpl
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ // The base service for Lacros observes proxy updates coming from Ash-Chrome
+ // via Mojo. Only created for `tracker` instances associated to a profile;
+ // for`tracker` instances associated to local_state the base_service is
+ // nullptr.
+ if (profile) {
+ base_service =
+ std::make_unique<chromeos::ProxyConfigServiceLacros>(profile);
+ }
+#elif !BUILDFLAG(IS_CHROMEOS_ASH)
+ // On Ash-Chrome, base service is NULL; chromeos::ProxyConfigServiceImpl
// determines the effective proxy config to take effect in the network layer,
// be it from prefs or system (which is network shill on chromeos).
diff --git a/chrome/browser/net/proxy_service_factory.h b/chrome/browser/net/proxy_service_factory.h
index 5f35c19e..82b26f2 100644
--- a/chrome/browser/net/proxy_service_factory.h
+++ b/chrome/browser/net/proxy_service_factory.h
@@ -11,6 +11,7 @@
class PrefProxyConfigTracker;
class PrefService;
+class Profile;
namespace net {
class ProxyConfigService;
@@ -19,9 +20,10 @@
class ProxyServiceFactory {
public:
// Creates a ProxyConfigService that delivers the system preferences
- // (or the respective ChromeOS equivalent).
+ // (or the respective Ash-Chrome equivalent).
static std::unique_ptr<net::ProxyConfigService> CreateProxyConfigService(
- PrefProxyConfigTracker* tracker);
+ PrefProxyConfigTracker* tracker,
+ Profile* profile);
// Creates a PrefProxyConfigTracker that tracks preferences of a
// profile. On ChromeOS it additionaly tracks local state for shared proxy
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 4293ff1..a0e78ab 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -418,6 +418,7 @@
#if BUILDFLAG(IS_CHROMEOS_LACROS)
#include "chrome/browser/lacros/lacros_prefs.h"
+#include "chrome/browser/lacros/net/proxy_config_service_lacros.h"
#endif
#if !defined(OS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH)
@@ -1356,6 +1357,7 @@
#if BUILDFLAG(IS_CHROMEOS_LACROS)
lacros_prefs::RegisterProfilePrefs(registry);
+ chromeos::ProxyConfigServiceLacros::RegisterProfilePrefs(registry);
#endif
#if defined(OS_WIN)