summaryrefslogtreecommitdiffstats
path: root/chrome/browser/chromeos
diff options
context:
space:
mode:
authorsatorux@chromium.org <satorux@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-17 05:10:30 +0000
committersatorux@chromium.org <satorux@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-17 05:10:30 +0000
commit83aa77e873d1dfde716c0083f6f5704999c93748 (patch)
tree0523199cb0032c5b48e2ca82aa243d1b65ce1fc9 /chrome/browser/chromeos
parentaf3b0898b4adf7961c5af8c6e1ef4909672c8488 (diff)
downloadchromium_src-83aa77e873d1dfde716c0083f6f5704999c93748.zip
chromium_src-83aa77e873d1dfde716c0083f6f5704999c93748.tar.gz
chromium_src-83aa77e873d1dfde716c0083f6f5704999c93748.tar.bz2
Rework LibcrosService using our D-Bus library.
Also introduce DBusThreadManager, that manages the D-Bus thread, and D-Bus clients using the thread. cros_dbus_service.cc and proxy_resolution_service_provider.cc are based on libcros_service_library.cc. The basic logic is kept as before. The major changes are: - Get rid of all libcros function calls (ex. StartLibCrosService). - Export "ResolveProxy" D-Bus method from Chrome, instead of libcros. - CrosDBusService is now managed by DBusThreadManager, instead of CrosLibrary. - Reduce use of nested class per the C++ style guide. - Now unit tested: libcros_service_unittest.cc BUG=chromium-os:18904 TEST=on the device, change the proxy config to use http://proxyconfig.corp.google.com/wpad.dat, run /opt/google/chrome/chromeos/libcros_service_tester (installed by USE=install_tests gmerge libcros), and confirm the libcros service works as before. Review URL: http://codereview.chromium.org/7819012 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@101640 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/chromeos')
-rw-r--r--chrome/browser/chromeos/chrome_browser_main_chromeos.cc8
-rw-r--r--chrome/browser/chromeos/cros/cros_library.cc3
-rw-r--r--chrome/browser/chromeos/cros/cros_library.h4
-rw-r--r--chrome/browser/chromeos/cros/libcros_service_library.cc322
-rw-r--r--chrome/browser/chromeos/cros/libcros_service_library.h29
-rw-r--r--chrome/browser/chromeos/dbus/OWNERS4
-rw-r--r--chrome/browser/chromeos/dbus/cros_dbus_service.cc70
-rw-r--r--chrome/browser/chromeos/dbus/cros_dbus_service.h94
-rw-r--r--chrome/browser/chromeos/dbus/cros_dbus_service_unittest.cc92
-rw-r--r--chrome/browser/chromeos/dbus/dbus_thread_manager.cc71
-rw-r--r--chrome/browser/chromeos/dbus/dbus_thread_manager.h71
-rw-r--r--chrome/browser/chromeos/dbus/proxy_resolution_service_provider.cc265
-rw-r--r--chrome/browser/chromeos/dbus/proxy_resolution_service_provider.h117
-rw-r--r--chrome/browser/chromeos/dbus/proxy_resolution_service_provider_unittest.cc311
14 files changed, 1103 insertions, 358 deletions
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index dfabefc..0f0a530 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -11,6 +11,7 @@
#include "base/message_loop.h"
#include "chrome/browser/chromeos/boot_times_loader.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
+#include "chrome/browser/chromeos/dbus/dbus_thread_manager.h"
#include "chrome/browser/chromeos/net/cros_network_change_notifier_factory.h"
#include "chrome/browser/chromeos/sensors_source_chromeos.h"
#include "chrome/browser/defaults.h"
@@ -67,7 +68,10 @@ ChromeBrowserMainPartsChromeos::ChromeBrowserMainPartsChromeos(
const MainFunctionParams& parameters)
: ChromeBrowserMainPartsGtk(parameters) {
}
+
ChromeBrowserMainPartsChromeos::~ChromeBrowserMainPartsChromeos() {
+ chromeos::DBusThreadManager::Shutdown();
+
if (!parameters().ui_task && chromeos::CrosLibrary::Get())
chromeos::CrosLibrary::Shutdown();
@@ -116,4 +120,8 @@ void ChromeBrowserMainPartsChromeos::PostMainMessageLoopStart() {
message_loop->PostTask(FROM_HERE,
base::Bind(&DoDeferredSensorsInit, sensors_source_));
}
+
+ // Initialize DBusThreadManager for the browser. This must be done after
+ // the main message loop is started, as it uses the message loop.
+ chromeos::DBusThreadManager::Initialize();
}
diff --git a/chrome/browser/chromeos/cros/cros_library.cc b/chrome/browser/chromeos/cros/cros_library.cc
index e3dc355..a3a748d 100644
--- a/chrome/browser/chromeos/cros/cros_library.cc
+++ b/chrome/browser/chromeos/cros/cros_library.cc
@@ -8,7 +8,6 @@
#include "chrome/browser/chromeos/cros/burn_library.h"
#include "chrome/browser/chromeos/cros/cert_library.h"
#include "chrome/browser/chromeos/cros/cryptohome_library.h"
-#include "chrome/browser/chromeos/cros/libcros_service_library.h"
#include "chrome/browser/chromeos/cros/library_loader.h"
#include "chrome/browser/chromeos/cros/login_library.h"
#include "chrome/browser/chromeos/cros/mount_library.h"
@@ -82,7 +81,6 @@ DEFINE_GET_LIBRARY_METHOD(Brightness, brightness);
DEFINE_GET_LIBRARY_METHOD(Burn, burn);
DEFINE_GET_LIBRARY_METHOD(Cert, cert);
DEFINE_GET_LIBRARY_METHOD(Cryptohome, crypto);
-DEFINE_GET_LIBRARY_METHOD(LibCrosService, libcros_service);
DEFINE_GET_LIBRARY_METHOD(Login, login);
DEFINE_GET_LIBRARY_METHOD(Mount, mount);
DEFINE_GET_LIBRARY_METHOD(Network, network);
@@ -132,7 +130,6 @@ DEFINE_SET_LIBRARY_METHOD(Brightness, brightness);
DEFINE_SET_LIBRARY_METHOD(Cert, cert);
DEFINE_SET_LIBRARY_METHOD(Burn, burn);
DEFINE_SET_LIBRARY_METHOD(Cryptohome, crypto);
-DEFINE_SET_LIBRARY_METHOD(LibCrosService, libcros_service);
DEFINE_SET_LIBRARY_METHOD(Login, login);
DEFINE_SET_LIBRARY_METHOD(Mount, mount);
DEFINE_SET_LIBRARY_METHOD(Network, network);
diff --git a/chrome/browser/chromeos/cros/cros_library.h b/chrome/browser/chromeos/cros/cros_library.h
index 5683e5e1..bc16426 100644
--- a/chrome/browser/chromeos/cros/cros_library.h
+++ b/chrome/browser/chromeos/cros/cros_library.h
@@ -20,7 +20,6 @@ class BrightnessLibrary;
class BurnLibrary;
class CertLibrary;
class CryptohomeLibrary;
-class LibCrosServiceLibrary;
class LibraryLoader;
class LoginLibrary;
class MountLibrary;
@@ -52,7 +51,6 @@ class CrosLibrary {
void SetCertLibrary(CertLibrary* library, bool own);
void SetBurnLibrary(BurnLibrary* library, bool own);
void SetCryptohomeLibrary(CryptohomeLibrary* library, bool own);
- void SetLibCrosServiceLibrary(LibCrosServiceLibrary* library, bool own);
void SetLoginLibrary(LoginLibrary* library, bool own);
void SetMountLibrary(MountLibrary* library, bool own);
void SetNetworkLibrary(NetworkLibrary* library, bool own);
@@ -82,7 +80,6 @@ class CrosLibrary {
BurnLibrary* GetBurnLibrary();
CertLibrary* GetCertLibrary();
CryptohomeLibrary* GetCryptohomeLibrary();
- LibCrosServiceLibrary* GetLibCrosServiceLibrary();
LoginLibrary* GetLoginLibrary();
MountLibrary* GetMountLibrary();
NetworkLibrary* GetNetworkLibrary();
@@ -157,7 +154,6 @@ class CrosLibrary {
Library<BurnLibrary> burn_lib_;
Library<CertLibrary> cert_lib_;
Library<CryptohomeLibrary> crypto_lib_;
- Library<LibCrosServiceLibrary> libcros_service_lib_;
Library<LoginLibrary> login_lib_;
Library<MountLibrary> mount_lib_;
Library<NetworkLibrary> network_lib_;
diff --git a/chrome/browser/chromeos/cros/libcros_service_library.cc b/chrome/browser/chromeos/cros/libcros_service_library.cc
deleted file mode 100644
index cd4d578d..0000000
--- a/chrome/browser/chromeos/cros/libcros_service_library.cc
+++ /dev/null
@@ -1,322 +0,0 @@
-// Copyright (c) 2011 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/chromeos/cros/libcros_service_library.h"
-
-#include "base/synchronization/lock.h"
-#include "chrome/browser/chromeos/cros/cros_library.h"
-#include "chrome/browser/profiles/profile_manager.h"
-#include "content/browser/browser_thread.h"
-#include "cros/chromeos_libcros_service.h"
-#include "net/base/net_errors.h"
-#include "net/proxy/proxy_service.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_context_getter.h"
-
-namespace chromeos {
-
-class LibCrosServiceLibraryImpl : public LibCrosServiceLibrary {
- public:
- // Base class for all services of LibCrosService.
- // Each subclass should declare DISABLE_RUNNABLE_METHOD_REFCOUNT to disable
- // refcounting, which is okay since the subclass's object will exist as a
- // scoped_ptr in Singleton LibCrosServiceLibraryImpl, guaranteeing that its
- // lifetime is longer than that of any message loop.
- class ServicingLibrary {
- public:
- explicit ServicingLibrary(LibCrosServiceConnection service_connection);
- virtual ~ServicingLibrary();
-
- // Clears service_connection_ (which is stored as weak pointer) so that it
- // can't be used anymore.
- virtual void ClearServiceConnection();
-
- protected:
- LibCrosServiceConnection service_connection_; // Weak pointer.
- // Lock for data members to synchronize access on multiple threads.
- base::Lock data_lock_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ServicingLibrary);
- };
-
- // Library that provides network proxy service for LibCrosService.
- // For now, it only processes proxy resolution requests for ChromeOS clients.
- class NetworkProxyLibrary : public ServicingLibrary {
- public:
- explicit NetworkProxyLibrary(LibCrosServiceConnection connection);
- virtual ~NetworkProxyLibrary();
-
- private:
- // Data being used in one proxy resolution.
- class Request {
- public:
- explicit Request(const std::string& source_url);
- virtual ~Request() {}
-
- // Callback on IO thread for when net::ProxyService::ResolveProxy
- // completes, synchronously or asynchronously.
- void OnCompletion(int result);
- net::CompletionCallbackImpl<Request> completion_callback_;
-
- std::string source_url_; // URL being resolved.
- int result_; // Result of proxy resolution.
- net::ProxyInfo proxy_info_; // ProxyInfo resolved for source_url_.
- std::string error_; // Error from proxy resolution.
- Task* notify_task_; // Task to notify of resolution result.
-
- private:
- DISALLOW_COPY_AND_ASSIGN(Request);
- };
-
- // Static callback passed to LibCrosService to be invoked when ChromeOS
- // clients send network proxy resolution requests to the service running in
- // chrome executable. Called on UI thread from dbus request.
- static void ResolveProxyHandler(void* object, const char* source_url);
-
- void ResolveProxy(const std::string& source_url,
- scoped_refptr<net::URLRequestContextGetter> getter);
-
- // Wrapper on UI thread to call LibCrosService::NotifyNetworkProxyResolved.
- void NotifyProxyResolved(Request* request);
-
- std::vector<Request*> all_requests_;
-
- DISALLOW_COPY_AND_ASSIGN(NetworkProxyLibrary);
- };
-
- LibCrosServiceLibraryImpl();
- virtual ~LibCrosServiceLibraryImpl();
-
- // LibCrosServiceLibrary implementation.
-
- // Starts LibCrosService running on dbus if not already started.
- virtual void StartService();
-
- private:
- // Connection to LibCrosService.
- LibCrosServiceConnection service_connection_;
-
- // Libraries that form LibCrosService.
- scoped_ptr<NetworkProxyLibrary> network_proxy_lib_;
-
- DISALLOW_COPY_AND_ASSIGN(LibCrosServiceLibraryImpl);
-};
-
-//---------------- LibCrosServiceLibraryImpl: public ---------------------------
-
-LibCrosServiceLibraryImpl::LibCrosServiceLibraryImpl()
- : service_connection_(NULL) {
- if (!CrosLibrary::Get()->EnsureLoaded()) {
- LOG(ERROR) << "Cros library has not been loaded.";
- }
-}
-
-LibCrosServiceLibraryImpl::~LibCrosServiceLibraryImpl() {
- if (service_connection_) {
- // Clear service connections in servicing libraries which held the former
- // as weak pointers.
- if (network_proxy_lib_.get())
- network_proxy_lib_->ClearServiceConnection();
-
- StopLibCrosService(service_connection_);
- VLOG(1) << "LibCrosService stopped.";
- service_connection_ = NULL;
- }
-}
-
-// Called on UI thread to start service for LibCrosService.
-void LibCrosServiceLibraryImpl::StartService() {
- // Make sure we're running on UI thread.
- if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(this,
- &LibCrosServiceLibraryImpl::StartService));
- return;
- }
- if (service_connection_) // Service has already been started.
- return;
- // Starts LibCrosService; the returned connection is used for future
- // interactions with the service.
- service_connection_ = StartLibCrosService();
- if (!service_connection_) {
- LOG(WARNING) << "Error starting LibCrosService";
- return;
- }
- network_proxy_lib_.reset(new NetworkProxyLibrary(service_connection_));
- VLOG(1) << "LibCrosService started.";
-}
-
-//------------- LibCrosServiceLibraryImpl::ServicingLibrary: public ------------
-
-LibCrosServiceLibraryImpl::ServicingLibrary::ServicingLibrary(
- LibCrosServiceConnection connection)
- : service_connection_(connection) {
-}
-
-LibCrosServiceLibraryImpl::ServicingLibrary::~ServicingLibrary() {
- ClearServiceConnection();
-}
-
-void LibCrosServiceLibraryImpl::ServicingLibrary::ClearServiceConnection() {
- base::AutoLock lock(data_lock_);
- service_connection_ = NULL;
-}
-
-//----------- LibCrosServiceLibraryImpl::NetworkProxyLibrary: public -----------
-
-LibCrosServiceLibraryImpl::NetworkProxyLibrary::NetworkProxyLibrary(
- LibCrosServiceConnection connection)
- : ServicingLibrary(connection) {
- // Register callback for LibCrosService::ResolveNetworkProxy.
- SetNetworkProxyResolver(&ResolveProxyHandler, this, service_connection_);
-}
-
-LibCrosServiceLibraryImpl::NetworkProxyLibrary::~NetworkProxyLibrary() {
- base::AutoLock lock(data_lock_);
- while (!all_requests_.empty()) {
- LOG(WARNING) << "Pending request for " << all_requests_.back()->source_url_;
- delete all_requests_.back();
- all_requests_.pop_back();
- }
-}
-
-//----------- LibCrosServiceLibraryImpl::NetworkProxyLibrary: private ----------
-
-// Static, called on UI thread from LibCrosService::ResolveProxy via dbus.
-void LibCrosServiceLibraryImpl::NetworkProxyLibrary::ResolveProxyHandler(
- void* object, const char* source_url) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- NetworkProxyLibrary* lib = static_cast<NetworkProxyLibrary*>(object);
- // parameters of RunnbaleMethod will be freed when this function returns, so
- // make a copy of them.
- std::string url(source_url);
- scoped_refptr<net::URLRequestContextGetter> getter =
- ProfileManager::GetDefaultProfile()->GetRequestContext();
- BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(lib, &NetworkProxyLibrary::ResolveProxy, url, getter));
-}
-
-// Called on IO thread as task posted from ResolveProxyHandler on UI thread.
-void LibCrosServiceLibraryImpl::NetworkProxyLibrary::ResolveProxy(
- const std::string& source_url,
- scoped_refptr<net::URLRequestContextGetter> getter) {
- // Make sure we're running on IO thread.
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
- // Create a request slot for this proxy resolution request.
- Request* request = new Request(source_url);
- request->notify_task_ = NewRunnableMethod(this,
- &NetworkProxyLibrary::NotifyProxyResolved, request);
- {
- base::AutoLock lock(data_lock_);
- // Queue request slot.
- all_requests_.push_back(request);
- if (!service_connection_) // Make sure |service_connection_| is valid.
- request->error_ = "LibCrosService not started";
- }
-
- // Retrieve ProxyService from profile's request context.
- net::ProxyService* proxy_service = NULL;
- if (request->error_.empty()) { // No error yet, proceed.
- if (getter)
- proxy_service = getter->GetURLRequestContext()->proxy_service();
- if (!proxy_service) // Make sure proxy_service is valid.
- request->error_ = "No proxy service in chrome";
- }
-
- if (!request->error_.empty()) { // Error string was just set.
- LOG(ERROR) << request->error_;
- request->result_ = net::OK; // Set to OK since error string is set.
- } else {
- VLOG(1) << "Starting networy proxy resolution for " << request->source_url_;
- request->result_ = proxy_service->ResolveProxy(
- GURL(request->source_url_), &request->proxy_info_,
- &request->completion_callback_, NULL, net::BoundNetLog());
- }
- if (request->result_ != net::ERR_IO_PENDING) {
- VLOG(1) << "Network proxy resolution completed synchronously.";
- request->OnCompletion(request->result_);
- }
-}
-
-// Called on UI thread as task posted from Request::OnCompletion on IO thread.
-void LibCrosServiceLibraryImpl::NetworkProxyLibrary::NotifyProxyResolved(
- Request* request) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- base::AutoLock lock(data_lock_);
- if (service_connection_) {
- if (!NotifyNetworkProxyResolved(request->source_url_.c_str(),
- request->proxy_info_.ToPacString().c_str(),
- request->error_.c_str(),
- service_connection_)) {
- LOG(ERROR) << "LibCrosService has error with NotifyNetworkProxyResolved";
- } else {
- VLOG(1) << "LibCrosService has notified proxy resoloution for "
- << request->source_url_;
- }
- }
- std::vector<Request*>::iterator iter =
- std::find(all_requests_.begin(), all_requests_.end(), request);
- if (iter == all_requests_.end()) {
- LOG(ERROR) << "can't find request slot(" << request->source_url_
- << ") in proxy-resolution queue";
- } else {
- all_requests_.erase(iter);
- }
- delete request;
-}
-
-//---------- LibCrosServiceLibraryImpl::NetworkProxyLibrary::Request -----------
-
-LibCrosServiceLibraryImpl::NetworkProxyLibrary::Request::Request(
- const std::string& source_url)
- : ALLOW_THIS_IN_INITIALIZER_LIST(
- completion_callback_(this, &Request::OnCompletion)),
- source_url_(source_url),
- result_(net::ERR_FAILED),
- notify_task_(NULL) {
-}
-
-// Called on IO thread when net::ProxyService::ResolveProxy has completed.
-void LibCrosServiceLibraryImpl::NetworkProxyLibrary::Request::OnCompletion(
- int result) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- result_ = result;
- if (result_ != net::OK)
- error_ = net::ErrorToString(result_);
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, notify_task_);
- notify_task_ = NULL;
-}
-
-//--------------------- LibCrosServiceLibraryStubImpl --------------------------
-
-class LibCrosServiceLibraryStubImpl : public LibCrosServiceLibrary {
- public:
- LibCrosServiceLibraryStubImpl() {}
- virtual ~LibCrosServiceLibraryStubImpl() {}
-
- // LibCrosServiceLibrary overrides.
- virtual void StartService() {}
-
- DISALLOW_COPY_AND_ASSIGN(LibCrosServiceLibraryStubImpl);
-};
-
-//--------------------------- LibCrosServiceLibrary ----------------------------
-
-// Static.
-LibCrosServiceLibrary* LibCrosServiceLibrary::GetImpl(bool stub) {
- if (stub)
- return new LibCrosServiceLibraryStubImpl();
- return new LibCrosServiceLibraryImpl();
-}
-
-} // namespace chromeos
-
-// Allows InvokeLater without adding refcounting. This class is a Singleton and
-// won't be deleted until it's last InvokeLater is run, so are all its
-// scoped_ptred class members.
-DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::LibCrosServiceLibraryImpl);
-DISABLE_RUNNABLE_METHOD_REFCOUNT(
- chromeos::LibCrosServiceLibraryImpl::NetworkProxyLibrary);
diff --git a/chrome/browser/chromeos/cros/libcros_service_library.h b/chrome/browser/chromeos/cros/libcros_service_library.h
deleted file mode 100644
index b409f29..0000000
--- a/chrome/browser/chromeos/cros/libcros_service_library.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (c) 2010 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_CHROMEOS_CROS_LIBCROS_SERVICE_LIBRARY_H_
-#define CHROME_BROWSER_CHROMEOS_CROS_LIBCROS_SERVICE_LIBRARY_H_
-#pragma once
-
-namespace net{
-class ProxyService;
-};
-
-namespace chromeos {
-
-class LibCrosServiceLibrary {
- public:
- virtual ~LibCrosServiceLibrary() {}
-
- // Starts dbus service for LibCrosService.
- virtual void StartService() = 0;
-
- // Factory function, creates a new instance and returns ownership.
- // For normal usage, access the singleton via CrosLibrary::Get().
- static LibCrosServiceLibrary* GetImpl(bool stub);
-};
-
-} // namespace chromeos
-
-#endif // CHROME_BROWSER_CHROMEOS_CROS_LIBCROS_SERVICE_LIBRARY_H_
diff --git a/chrome/browser/chromeos/dbus/OWNERS b/chrome/browser/chromeos/dbus/OWNERS
new file mode 100644
index 0000000..453c641
--- /dev/null
+++ b/chrome/browser/chromeos/dbus/OWNERS
@@ -0,0 +1,4 @@
+set noparent
+satorux@chromium.org
+stevenjb@chromium.org
+
diff --git a/chrome/browser/chromeos/dbus/cros_dbus_service.cc b/chrome/browser/chromeos/dbus/cros_dbus_service.cc
new file mode 100644
index 0000000..52cfec4
--- /dev/null
+++ b/chrome/browser/chromeos/dbus/cros_dbus_service.cc
@@ -0,0 +1,70 @@
+// Copyright (c) 2011 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/chromeos/dbus/cros_dbus_service.h"
+
+#include "base/stl_util.h"
+#include "base/threading/platform_thread.h"
+#include "chrome/browser/chromeos/dbus/proxy_resolution_service_provider.h"
+#include "content/browser/browser_thread.h"
+#include "dbus/bus.h"
+#include "dbus/exported_object.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
+
+namespace chromeos {
+
+CrosDBusService::CrosDBusService(dbus::Bus* bus)
+ : service_started_(false),
+ origin_thread_id_(base::PlatformThread::CurrentId()),
+ bus_(bus) {
+}
+
+CrosDBusService::~CrosDBusService() {
+}
+
+void CrosDBusService::Start() {
+ // Make sure we're running on the origin thread (i.e. the UI thread in
+ // production).
+ DCHECK(OnOriginThread());
+
+ // Return if the service has been already started.
+ if (service_started_)
+ return;
+
+ exported_object_ = bus_->GetExportedObject(
+ kLibCrosServiceName,
+ kLibCrosServicePath);
+
+ for (size_t i = 0; i < service_providers_.size(); ++i)
+ service_providers_[i]->Start(exported_object_);
+
+ service_started_ = true;
+
+ VLOG(1) << "CrosDBusService started.";
+}
+
+CrosDBusService* CrosDBusService::Get(dbus::Bus* bus) {
+ CrosDBusService* service = new CrosDBusService(bus);
+ service->RegisterServiceProvider(ProxyResolutionServiceProvider::Get());
+ return service;
+}
+
+CrosDBusService* CrosDBusService::GetForTesting(
+ dbus::Bus* bus,
+ ServiceProviderInterface* proxy_resolution_service) {
+ CrosDBusService* service = new CrosDBusService(bus);
+ service->RegisterServiceProvider(proxy_resolution_service);
+ return service;
+}
+
+void CrosDBusService::RegisterServiceProvider(
+ ServiceProviderInterface* provider) {
+ service_providers_.push_back(provider);
+}
+
+bool CrosDBusService::OnOriginThread() {
+ return base::PlatformThread::CurrentId() == origin_thread_id_;
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/dbus/cros_dbus_service.h b/chrome/browser/chromeos/dbus/cros_dbus_service.h
new file mode 100644
index 0000000..4ab24c5
--- /dev/null
+++ b/chrome/browser/chromeos/dbus/cros_dbus_service.h
@@ -0,0 +1,94 @@
+// Copyright (c) 2011 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_CHROMEOS_DBUS_CROS_DBUS_SERVICE_H_
+#define CHROME_BROWSER_CHROMEOS_DBUS_CROS_DBUS_SERVICE_H_
+#pragma once
+
+#include <vector>
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/threading/platform_thread.h"
+
+namespace dbus {
+class Bus;
+class ExportedObject;
+}
+
+namespace chromeos {
+
+// CrosDBusService is used to run a D-Bus service inside Chrome for Chrome
+// OS. The service will be registered as follows:
+//
+// Service name: org.chromium.LibCrosService (kLibCrosServiceName)
+// Object path: chromium/LibCrosService (kLibCrosServicePath)
+//
+// For historical reasons, the rather irrelevant name "LibCrosService" is
+// used in the D-Bus constants such as the service name.
+//
+// CrosDBusService exports D-Bus methods through service provider classes
+// that implement CrosDBusService::ServiceProviderInterface.
+//
+class ProxyResolutionService;
+
+class CrosDBusService {
+ public:
+ // CrosDBusService consists of service providers that implement this
+ // interface.
+ //
+ // ServiceProviderInterface is a ref counted object, to ensure that
+ // |this| of the object is alive when callbacks referencing |this| are
+ // called.
+ class ServiceProviderInterface
+ : public base::RefCountedThreadSafe<ServiceProviderInterface> {
+ public:
+ virtual ~ServiceProviderInterface() {}
+
+ // Starts the service provider. |exported_object| is used to export
+ // D-Bus methods.
+ virtual void Start(
+ scoped_refptr<dbus::ExportedObject> exported_object) = 0;
+
+ private:
+ friend class base::RefCountedThreadSafe<ServiceProviderInterface>;
+ };
+
+ virtual ~CrosDBusService();
+
+ // Starts the D-Bus service.
+ virtual void Start();
+
+ // Gets the instance.
+ static CrosDBusService* Get(dbus::Bus* bus);
+
+ private:
+ explicit CrosDBusService(dbus::Bus* bus);
+
+ // Gets the instance for testing. Takes the ownership of
+ // |proxy_resolution_service|.
+ friend class CrosDBusServiceTest;
+ static CrosDBusService* GetForTesting(
+ dbus::Bus* bus,
+ ServiceProviderInterface* proxy_resolution_service);
+
+ // Registers a service provider. This must be done before Start().
+ // |provider| will be owned by CrosDBusService.
+ void RegisterServiceProvider(ServiceProviderInterface* provider);
+
+ // Returns true if the current thread is on the origin thread.
+ bool OnOriginThread();
+
+ bool service_started_;
+ base::PlatformThreadId origin_thread_id_;
+ dbus::Bus* bus_;
+ scoped_refptr<dbus::ExportedObject> exported_object_;
+
+ // Service providers that form CrosDBusService.
+ std::vector<scoped_refptr<ServiceProviderInterface> > service_providers_;
+};
+
+} // namespace
+
+#endif // CHROME_BROWSER_CHROMEOS_DBUS_CROS_DBUS_SERVICE_H_
diff --git a/chrome/browser/chromeos/dbus/cros_dbus_service_unittest.cc b/chrome/browser/chromeos/dbus/cros_dbus_service_unittest.cc
new file mode 100644
index 0000000..70e2ece
--- /dev/null
+++ b/chrome/browser/chromeos/dbus/cros_dbus_service_unittest.cc
@@ -0,0 +1,92 @@
+// Copyright (c) 2011 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/chromeos/dbus/cros_dbus_service.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "dbus/message.h"
+#include "dbus/mock_bus.h"
+#include "dbus/mock_exported_object.h"
+#include "dbus/mock_object_proxy.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
+
+using ::testing::Eq;
+using ::testing::Invoke;
+using ::testing::Return;
+
+namespace chromeos {
+
+class MockProxyResolutionService
+ : public CrosDBusService::ServiceProviderInterface {
+ public:
+ MOCK_METHOD1(Start, void(scoped_refptr<dbus::ExportedObject>
+ exported_object));
+};
+
+class CrosDBusServiceTest : public testing::Test {
+ public:
+ CrosDBusServiceTest() {
+ }
+
+ // Creates an instance of CrosDBusService with mocks injected.
+ virtual void SetUp() {
+ // Create a mock bus.
+ dbus::Bus::Options options;
+ options.bus_type = dbus::Bus::SYSTEM;
+ mock_bus_ = new dbus::MockBus(options);
+
+ // ShutdownAndBlock() will be called in TearDown().
+ EXPECT_CALL(*mock_bus_, ShutdownAndBlock()).WillOnce(Return());
+
+ // Create a mock exported object that behaves as
+ // org.chromium.CrosDBusService.
+ mock_exported_object_ =
+ new dbus::MockExportedObject(mock_bus_.get(),
+ kLibCrosServiceName,
+ kLibCrosServicePath);
+
+ // |mock_bus_|'s GetExportedObject() will return mock_exported_object_|
+ // for the given service name and the object path.
+ EXPECT_CALL(*mock_bus_, GetExportedObject(
+ kLibCrosServiceName, kLibCrosServicePath))
+ .WillOnce(Return(mock_exported_object_.get()));
+
+ // Create a mock proxy resolution service.
+ MockProxyResolutionService* mock_proxy_resolution_service_provider =
+ new MockProxyResolutionService;
+
+ // Start() will be called with |mock_exported_object_|.
+ EXPECT_CALL(*mock_proxy_resolution_service_provider,
+ Start(Eq(mock_exported_object_))).WillOnce(Return());
+
+ // Create the cros service with the mocks injected.
+ cros_dbus_service_.reset(
+ CrosDBusService::GetForTesting(
+ mock_bus_,
+ mock_proxy_resolution_service_provider));
+ }
+
+ virtual void TearDown() {
+ // Shutdown the bus.
+ mock_bus_->ShutdownAndBlock();
+ }
+
+ protected:
+ scoped_refptr<dbus::MockBus> mock_bus_;
+ scoped_refptr<dbus::MockExportedObject> mock_exported_object_;
+ scoped_ptr<CrosDBusService> cros_dbus_service_;
+};
+
+TEST_F(CrosDBusServiceTest, Start) {
+ // Simply start the service and see if mock expectations are met:
+ // - The service object is exported by GetExportedObject()
+ // - The proxy resolution service is started.
+ cros_dbus_service_->Start();
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/dbus/dbus_thread_manager.cc b/chrome/browser/chromeos/dbus/dbus_thread_manager.cc
new file mode 100644
index 0000000..5f4232c
--- /dev/null
+++ b/chrome/browser/chromeos/dbus/dbus_thread_manager.cc
@@ -0,0 +1,71 @@
+// Copyright (c) 2011 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/chromeos/dbus/dbus_thread_manager.h"
+
+#include "base/threading/thread.h"
+#include "chrome/browser/chromeos/dbus/cros_dbus_service.h"
+#include "dbus/bus.h"
+
+namespace chromeos {
+
+static DBusThreadManager* g_dbus_thread_manager = NULL;
+
+DBusThreadManager::DBusThreadManager() {
+ // Create the D-Bus thread.
+ base::Thread::Options thread_options;
+ thread_options.message_loop_type = MessageLoop::TYPE_IO;
+ dbus_thread_.reset(new base::Thread("D-Bus thread"));
+ dbus_thread_->StartWithOptions(thread_options);
+
+ // Create the connection to the system bus.
+ dbus::Bus::Options system_bus_options;
+ system_bus_options.bus_type = dbus::Bus::SYSTEM;
+ system_bus_options.connection_type = dbus::Bus::PRIVATE;
+ system_bus_options.dbus_thread_message_loop_proxy =
+ dbus_thread_->message_loop_proxy();
+ system_bus_ = new dbus::Bus(system_bus_options);
+
+ // Create and start the cros D-Bus service.
+ cros_dbus_service_ = CrosDBusService::Get(system_bus_.get());
+ cros_dbus_service_->Start();
+}
+
+DBusThreadManager::~DBusThreadManager() {
+ // Shut down the bus. During the browser shutdown, it's ok to shut down
+ // the bus synchronously.
+ system_bus_->ShutdownOnDBusThreadAndBlock();
+
+ // Stop the D-Bus thread.
+ dbus_thread_->Stop();
+
+ // D-Bus clients should be deleted after the D-Bus thread is stopped.
+ // See "CALLBACKS IN D-BUS CLIENTS" in the header file for why.
+ delete cros_dbus_service_;
+}
+
+void DBusThreadManager::Initialize() {
+ CHECK(!g_dbus_thread_manager);
+ g_dbus_thread_manager = new DBusThreadManager;
+ VLOG(1) << "DBusThreadManager initialized";
+}
+
+void DBusThreadManager::Shutdown() {
+ if (!g_dbus_thread_manager) {
+ // This can happen in tests.
+ LOG(WARNING) << "DBusThreadManager::Shutdown() called with NULL manager";
+ return;
+ }
+ delete g_dbus_thread_manager;
+ g_dbus_thread_manager = NULL;
+ VLOG(1) << "DBusThreadManager Shutdown completed";
+}
+
+DBusThreadManager* DBusThreadManager::Get() {
+ CHECK(g_dbus_thread_manager)
+ << "DBusThreadManager::Get() called before Initialize()";
+ return g_dbus_thread_manager;
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/dbus/dbus_thread_manager.h b/chrome/browser/chromeos/dbus/dbus_thread_manager.h
new file mode 100644
index 0000000..c4da3b6
--- /dev/null
+++ b/chrome/browser/chromeos/dbus/dbus_thread_manager.h
@@ -0,0 +1,71 @@
+// Copyright (c) 2011 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_CHROMEOS_DBUS_DBUS_THREAD_MANAGER_H_
+#define CHROME_BROWSER_CHROMEOS_DBUS_DBUS_THREAD_MANAGER_H_
+#pragma once
+
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/ref_counted.h"
+
+namespace base {
+class Thread;
+};
+
+namespace dbus {
+class Bus;
+};
+
+namespace chromeos {
+
+class CrosDBusService;
+
+// DBusThreadManager manages the D-Bus thread, the thread dedicated to
+// handling asynchronous D-Bus operations.
+//
+// This class also manages D-Bus connections and D-Bus clients, which
+// depend on the D-Bus thread to ensure the right order of shutdowns for
+// the D-Bus thread, the D-Bus connections, and the D-Bus clients.
+//
+// CALLBACKS IN D-BUS CLIENTS:
+//
+// D-Bus clients managed by DBusThreadManager are guaranteed to be deleted
+// after the D-Bus thread so the clients don't need to worry if new
+// incoming messages arrive from the D-Bus thread during shutdown of the
+// clients. However, the UI message loop may still be running during the
+// shutdown, hence the D-Bus clients should inherit
+// base::RefCountedThreadSafe if they export methods or call methods, to
+// ensure that callbacks can reference |this| safely on the UI thread
+// during the shutdown.
+//
+class DBusThreadManager {
+ public:
+ // Sets the global instance. Must be called before any calls to Get().
+ // We explicitly initialize and shut down the global object, rather than
+ // making it a Singleton, to ensure clean startup and shutdown.
+ static void Initialize();
+
+ // Destroys the global instance.
+ static void Shutdown();
+
+ // Gets the global instance. Initialize() must be called first.
+ static DBusThreadManager* Get();
+
+ // Returns the connection to the system bus.
+ dbus::Bus* system_bus() { return system_bus_.get(); }
+
+ private:
+ DBusThreadManager();
+ virtual ~DBusThreadManager();
+
+ scoped_ptr<base::Thread> dbus_thread_;
+ scoped_refptr<dbus::Bus> system_bus_;
+ CrosDBusService* cros_dbus_service_;
+
+ DISALLOW_COPY_AND_ASSIGN(DBusThreadManager);
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_DBUS_DBUS_THREAD_MANAGER_H_
diff --git a/chrome/browser/chromeos/dbus/proxy_resolution_service_provider.cc b/chrome/browser/chromeos/dbus/proxy_resolution_service_provider.cc
new file mode 100644
index 0000000..bf0f31b
--- /dev/null
+++ b/chrome/browser/chromeos/dbus/proxy_resolution_service_provider.cc
@@ -0,0 +1,265 @@
+// Copyright (c) 2011 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/chromeos/dbus/proxy_resolution_service_provider.h"
+
+#include "base/bind.h"
+#include "base/threading/platform_thread.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "dbus/bus.h"
+#include "dbus/message.h"
+#include "dbus/exported_object.h"
+#include "net/base/net_errors.h"
+#include "net/proxy/proxy_service.h"
+#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_context_getter.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
+
+namespace chromeos {
+
+// The ProxyResolverInterface implementation used in production.
+class ProxyResolverImpl : public ProxyResolverInterface {
+ public:
+ // Data being used in one proxy resolution.
+ class Request {
+ public:
+ explicit Request(const std::string& source_url)
+ : ALLOW_THIS_IN_INITIALIZER_LIST(
+ completion_callback_(this, &Request::OnCompletion)),
+ source_url_(source_url),
+ result_(net::ERR_FAILED) {
+ }
+
+ virtual ~Request() {}
+
+ // Callback on IO thread for when net::ProxyService::ResolveProxy
+ // completes, synchronously or asynchronously.
+ void OnCompletion(int result) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ result_ = result;
+ // Generate the error message if the error message is not yet set,
+ // and there was an error.
+ if (error_.empty() && result_ != net::OK)
+ error_ = net::ErrorToString(result_);
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, notify_task_);
+ }
+
+ net::CompletionCallbackImpl<Request> completion_callback_;
+
+ std::string source_url_; // URL being resolved.
+ int result_; // Result of proxy resolution.
+ net::ProxyInfo proxy_info_; // ProxyInfo resolved for source_url_.
+ std::string error_; // Error from proxy resolution.
+ base::Closure notify_task_; // Task to notify of resolution result.
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Request);
+ };
+
+ ProxyResolverImpl()
+ : origin_thread_id_(base::PlatformThread::CurrentId()) {
+ }
+
+ virtual ~ProxyResolverImpl() {
+ base::AutoLock lock(data_lock_);
+ while (!all_requests_.empty()) {
+ LOG(WARNING) << "Pending request for "
+ << all_requests_.back()->source_url_;
+ delete all_requests_.back();
+ all_requests_.pop_back();
+ }
+ }
+
+ // ProxyResolverInterface override.
+ virtual void ResolveProxy(
+ const std::string& source_url,
+ const std::string& signal_interface,
+ const std::string& signal_name,
+ scoped_refptr<dbus::ExportedObject> exported_object) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&ProxyResolverImpl::ResolveProxyInternal,
+ this,
+ source_url,
+ signal_interface,
+ signal_name,
+ exported_object));
+ }
+
+ private:
+ // Helper function for ResolveProxy().
+ void ResolveProxyInternal(
+ const std::string& source_url,
+ const std::string& signal_interface,
+ const std::string& signal_name,
+ scoped_refptr<dbus::ExportedObject> exported_object) {
+ // Make sure we're running on IO thread.
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ // Create a request slot for this proxy resolution request.
+ Request* request = new Request(source_url);
+ request->notify_task_ = base::Bind(
+ &ProxyResolverImpl::NotifyProxyResolved,
+ this,
+ signal_interface,
+ signal_name,
+ exported_object,
+ request);
+ // Queue request slot.
+ {
+ base::AutoLock lock(data_lock_);
+ all_requests_.push_back(request);
+ }
+
+ // Check if we have the URLRequestContextGetter.
+ scoped_refptr<net::URLRequestContextGetter> getter =
+ ProfileManager::GetDefaultProfile()->GetRequestContext();
+ if (!getter) {
+ request->error_ = "No URLRequestContextGetter";
+ request->OnCompletion(net::ERR_UNEXPECTED);
+ return;
+ }
+
+ // Retrieve ProxyService from profile's request context.
+ net::ProxyService* proxy_service =
+ getter->GetURLRequestContext()->proxy_service();
+ if (!proxy_service) {
+ request->error_ = "No proxy service in chrome";
+ request->OnCompletion(net::ERR_UNEXPECTED);
+ return;
+ }
+
+ VLOG(1) << "Starting network proxy resolution for "
+ << request->source_url_;
+ request->result_ = proxy_service->ResolveProxy(
+ GURL(request->source_url_), &request->proxy_info_,
+ &request->completion_callback_, NULL, net::BoundNetLog());
+ if (request->result_ != net::ERR_IO_PENDING) {
+ VLOG(1) << "Network proxy resolution completed synchronously.";
+ request->OnCompletion(request->result_);
+ }
+ }
+
+ // Called on UI thread as task posted from Request::OnCompletion on IO
+ // thread.
+ void NotifyProxyResolved(
+ const std::string& signal_interface,
+ const std::string& signal_name,
+ scoped_refptr<dbus::ExportedObject> exported_object,
+ Request* request) {
+ DCHECK(OnOriginThread());
+
+ // Send a signal to the client.
+ dbus::Signal signal(signal_interface, signal_name);
+ dbus::MessageWriter writer(&signal);
+ writer.AppendString(request->source_url_);
+ writer.AppendString(request->proxy_info_.ToPacString());
+ writer.AppendString(request->error_);
+ exported_object->SendSignal(&signal);
+ VLOG(1) << "Sending signal: " << signal.ToString();
+
+ base::AutoLock lock(data_lock_);
+ std::vector<Request*>::iterator iter =
+ std::find(all_requests_.begin(), all_requests_.end(), request);
+ if (iter == all_requests_.end()) {
+ LOG(ERROR) << "can't find request slot(" << request->source_url_
+ << ") in proxy-resolution queue";
+ } else {
+ all_requests_.erase(iter);
+ }
+ delete request;
+ }
+
+ // Returns true if the current thread is on the origin thread.
+ bool OnOriginThread() {
+ return base::PlatformThread::CurrentId() == origin_thread_id_;
+ }
+
+ base::PlatformThreadId origin_thread_id_;
+ // Lock for data members to synchronize access on multiple threads.
+ base::Lock data_lock_;
+ std::vector<Request*> all_requests_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProxyResolverImpl);
+};
+
+ProxyResolutionServiceProvider::ProxyResolutionServiceProvider(
+ ProxyResolverInterface* resolver)
+ : resolver_(resolver),
+ origin_thread_id_(base::PlatformThread::CurrentId()) {
+}
+
+ProxyResolutionServiceProvider::~ProxyResolutionServiceProvider() {
+}
+
+void ProxyResolutionServiceProvider::Start(
+ scoped_refptr<dbus::ExportedObject> exported_object) {
+ DCHECK(OnOriginThread());
+ exported_object_ = exported_object;
+ VLOG(1) << "ProxyResolutionServiceProvider started";
+ exported_object_->ExportMethod(
+ kLibCrosServiceInterface,
+ kResolveNetworkProxy,
+ base::Bind(&ProxyResolutionServiceProvider::ResolveProxyHandler,
+ this),
+ base::Bind(&ProxyResolutionServiceProvider::OnExported,
+ this));
+}
+
+void ProxyResolutionServiceProvider::OnExported(
+ const std::string& interface_name,
+ const std::string& method_name,
+ bool success) {
+ if (!success) {
+ LOG(ERROR) << "Failed to export " << interface_name << "."
+ << method_name;
+ }
+ VLOG(1) << "Method exported: " << interface_name << "." << method_name;
+}
+
+bool ProxyResolutionServiceProvider::OnOriginThread() {
+ return base::PlatformThread::CurrentId() == origin_thread_id_;
+}
+
+dbus::Response* ProxyResolutionServiceProvider::ResolveProxyHandler(
+ dbus::MethodCall* method_call) {
+ DCHECK(OnOriginThread());
+ VLOG(1) << "Handing method call: " << method_call->ToString();
+ // The method call should contain the three string parameters.
+ dbus::MessageReader reader(method_call);
+ std::string source_url;
+ std::string signal_interface;
+ std::string signal_name;
+ if (!reader.PopString(&source_url) ||
+ !reader.PopString(&signal_interface) ||
+ !reader.PopString(&signal_name)) {
+ LOG(ERROR) << "Unexpected method call: " << method_call->ToString();
+ return NULL;
+ }
+
+ resolver_->ResolveProxy(source_url,
+ signal_interface,
+ signal_name,
+ exported_object_);
+
+ // Return an empty response for now. We'll send a signal once the
+ // network proxy resolution is completed.
+ dbus::Response* response = dbus::Response::FromMethodCall(method_call);
+ return response;
+}
+
+ProxyResolutionServiceProvider* ProxyResolutionServiceProvider::Get() {
+ return new ProxyResolutionServiceProvider(new ProxyResolverImpl);
+}
+
+ProxyResolutionServiceProvider* ProxyResolutionServiceProvider::GetForTesting(
+ ProxyResolverInterface* resolver) {
+ return new ProxyResolutionServiceProvider(resolver);
+}
+
+ProxyResolverInterface::~ProxyResolverInterface() {
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/dbus/proxy_resolution_service_provider.h b/chrome/browser/chromeos/dbus/proxy_resolution_service_provider.h
new file mode 100644
index 0000000..2bb644e
--- /dev/null
+++ b/chrome/browser/chromeos/dbus/proxy_resolution_service_provider.h
@@ -0,0 +1,117 @@
+// Copyright (c) 2011 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_CHROMEOS_DBUS_PROXY_RESOLUTION_SERVICE_PROVIDER_H_
+#define CHROME_BROWSER_CHROMEOS_DBUS_PROXY_RESOLUTION_SERVICE_PROVIDER_H_
+#pragma once
+
+#include <string>
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/platform_thread.h"
+#include "chrome/browser/chromeos/dbus/cros_dbus_service.h"
+
+namespace dbus {
+class ExportedObject;
+class MethodCall;
+class Response;
+}
+
+namespace chromeos {
+
+class ProxyResolverInterface;
+
+// This class provides proxy resolution service for CrosDBusService.
+// It processes proxy resolution requests for ChromeOS clients.
+//
+// The following methods are exported.
+//
+// Interface: org.chromium.LibCrosServiceInterface (kLibCrosServiceInterface)
+// Method: ResolveNetworkProxy (kResolveNetworkProxy)
+// Parameters: string:source_url
+// string:signal_interface
+// string:signal_name
+//
+// Resolves the proxy for |source_url|. Returns the result
+// as a D-Bus signal sent to |signal_interface| and |signal_name|.
+//
+// The returned signal will contain the three values:
+// - string:source_url - requested source URL.
+// - string:proxy_info - proxy info for the source URL in PAC format
+// like "PROXY cache.example.com:12345"
+// - string:error_message - error message. Empty if successful.
+//
+class ProxyResolutionServiceProvider
+ : public CrosDBusService::ServiceProviderInterface {
+ public:
+ virtual ~ProxyResolutionServiceProvider();
+
+ // CrosDBusService::ServiceProviderInterface override.
+ virtual void Start(scoped_refptr<dbus::ExportedObject> exported_object);
+
+ // Gets the instance.
+ static ProxyResolutionServiceProvider* Get();
+
+ private:
+ explicit ProxyResolutionServiceProvider(ProxyResolverInterface *resovler);
+
+ // Gets the instance for testing. Takes the ownership of |resovler|
+ friend class ProxyResolutionServiceProviderTest;
+ static ProxyResolutionServiceProvider* GetForTesting(
+ ProxyResolverInterface* resolver);
+
+ // Called from ExportedObject, when ResolveProxyHandler() is exported as
+ // a D-Bus method, or failed to be exported.
+ void OnExported(const std::string& interface_name,
+ const std::string& method_name,
+ bool success);
+
+ // Callback to be invoked when ChromeOS clients send network proxy
+ // resolution requests to the service running in chrome executable.
+ // Called on UI thread from dbus request.
+ dbus::Response* ResolveProxyHandler(dbus::MethodCall* method_call);
+
+ // Returns true if the current thread is on the origin thread.
+ bool OnOriginThread();
+
+ scoped_refptr<dbus::ExportedObject> exported_object_;
+ scoped_refptr<ProxyResolverInterface> resolver_;
+ base::PlatformThreadId origin_thread_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProxyResolutionServiceProvider);
+};
+
+// The interface is defined so we can mock out the proxy resolver
+// implementation.
+//
+// ProxyResolverInterface is a ref counted object, to ensure that |this|
+// of the object is alive when callbacks referencing |this| are called.
+class ProxyResolverInterface
+ : public base::RefCountedThreadSafe<ProxyResolverInterface> {
+ public:
+ virtual ~ProxyResolverInterface();
+
+ // Resolves the proxy for the given URL. Returns the result as a
+ // signal sent to |signal_interface| and
+ // |signal_name|. |exported_object| will be used to send the
+ // signal. The signal contains the three string members:
+ //
+ // - source url: the requested source URL.
+ // - proxy info: proxy info for the source URL in PAC format.
+ // - error message: empty if the proxy resolution was successful.
+ virtual void ResolveProxy(
+ const std::string& source_url,
+ const std::string& signal_interface,
+ const std::string& signal_name,
+ scoped_refptr<dbus::ExportedObject> exported_object) = 0;
+
+ private:
+ friend class base::RefCountedThreadSafe<ProxyResolverInterface>;
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_DBUS_PROXY_RESOLUTION_SERVICE_PROVIDER_H_
diff --git a/chrome/browser/chromeos/dbus/proxy_resolution_service_provider_unittest.cc b/chrome/browser/chromeos/dbus/proxy_resolution_service_provider_unittest.cc
new file mode 100644
index 0000000..50978a1
--- /dev/null
+++ b/chrome/browser/chromeos/dbus/proxy_resolution_service_provider_unittest.cc
@@ -0,0 +1,311 @@
+// Copyright (c) 2011 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.
+//
+// This test is relatively complicated. Here's the summary of what it does:
+//
+// - Set up mock D-Bus related objects to mock out D-Bus calls.
+// - Set up a mock proxy resolver to mock out the proxy resolution.
+// - Create ProxyResolutionServiceProvider by injecting the mocks
+// - Start the service provider.
+// - Request ProxyResolutionServiceProvider to resolve proxy for kSourceURL.
+// - ProxyResolutionServiceProvider will return the result as a signal.
+// - Confirm that we receive the signal and check the contents of the signal.
+
+#include "chrome/browser/chromeos/dbus/proxy_resolution_service_provider.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "dbus/message.h"
+#include "dbus/mock_bus.h"
+#include "dbus/mock_exported_object.h"
+#include "dbus/mock_object_proxy.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
+
+using ::testing::_;
+using ::testing::Invoke;
+using ::testing::Return;
+using ::testing::Unused;
+
+namespace chromeos {
+
+// We want to know about the proxy info for the URL.
+const char kSourceURL[] = "http://www.gmail.com/";
+
+// ProxyResolutionServiceProvider will return the proxy info as a D-Bus
+// signal, to the following signal interface and the signal name.
+const char kReturnSignalInterface[] = "org.chromium.TestInterface";
+const char kReturnSignalName[] = "TestSignal";
+
+// The returned proxy info.
+const char kReturnProxyInfo[] = "PROXY cache.example.com:12345";
+
+// The error message is empty if proxy resolution is successful.
+const char kReturnEmptyErrorMessage[] = "";
+
+// Mock for ProxyResolverInterface. We'll inject this to
+// ProxyResolutionServiceProvider to mock out the proxy resolution.
+class MockProxyResolver : public ProxyResolverInterface {
+ public:
+ MOCK_METHOD4(ResolveProxy,
+ void(const std::string& source_url,
+ const std::string& signal_interface,
+ const std::string& signal_name,
+ scoped_refptr<dbus::ExportedObject> exported_object));
+};
+
+class ProxyResolutionServiceProviderTest : public testing::Test {
+ public:
+ ProxyResolutionServiceProviderTest()
+ : signal_received_successfully_(false),
+ mock_resolver_(NULL) {
+ }
+
+ virtual void SetUp() {
+ // Create a mock bus.
+ dbus::Bus::Options options;
+ options.bus_type = dbus::Bus::SYSTEM;
+ mock_bus_ = new dbus::MockBus(options);
+
+ // ShutdownAndBlock() will be called in TearDown().
+ EXPECT_CALL(*mock_bus_, ShutdownAndBlock()).WillOnce(Return());
+
+ // Create a mock exported object that behaves as
+ // org.chromium.CrosDBusService.
+ mock_exported_object_ =
+ new dbus::MockExportedObject(mock_bus_.get(),
+ kLibCrosServiceName,
+ kLibCrosServicePath);
+
+ // |mock_exported_object_|'s ExportMethod() will use
+ // |MockExportedObject().
+ EXPECT_CALL(
+ *mock_exported_object_,
+ ExportMethod(_, _, _, _)).WillOnce(
+ Invoke(this,
+ &ProxyResolutionServiceProviderTest::MockExportMethod));
+ // |mock_exported_object_|'s SendSignal() will use
+ // |MockSendSignal().
+ EXPECT_CALL(
+ *mock_exported_object_,
+ SendSignal(_)).WillOnce(
+ Invoke(this,
+ &ProxyResolutionServiceProviderTest::MockSendSignal));
+
+ // Create a mock object proxy, with which we call a method of
+ // |mock_exported_object_|.
+ mock_object_proxy_ =
+ new dbus::MockObjectProxy(mock_bus_.get(),
+ kLibCrosServiceName,
+ kLibCrosServicePath);
+ // |mock_object_proxy_|'s CallMethodAndBlock() will use
+ // CreateResponse() to return responses.
+ EXPECT_CALL(*mock_object_proxy_,
+ CallMethodAndBlock(_, _))
+ .WillOnce(Invoke(
+ this,
+ &ProxyResolutionServiceProviderTest::CreateResponse));
+ // |mock_object_proxy_|'s ConnectToSignal will use
+ // MockConnectToSignal().
+ EXPECT_CALL(*mock_object_proxy_,
+ ConnectToSignal(kReturnSignalInterface,
+ kReturnSignalName,
+ _, _))
+ .WillOnce(Invoke(
+ this,
+ &ProxyResolutionServiceProviderTest::MockConnectToSignal));
+
+ // Create a mock proxy resolver. Will be owned by
+ // |proxy_resolution_service|.
+ mock_resolver_ = new MockProxyResolver;
+ // |mock_resolver_|'s ResolveProxy() will use MockResolveProxy().
+ EXPECT_CALL(*mock_resolver_, ResolveProxy(kSourceURL,
+ kReturnSignalInterface,
+ kReturnSignalName,
+ _))
+ .WillOnce(Invoke(
+ this,
+ &ProxyResolutionServiceProviderTest::MockResolveProxy));
+
+ // Create the proxy resolution service with the mock bus and the mock
+ // resolver injected.
+ proxy_resolution_service_ =
+ ProxyResolutionServiceProvider::GetForTesting(mock_resolver_);
+
+ // Finally, start the service.
+ proxy_resolution_service_->Start(mock_exported_object_);
+ }
+
+ virtual void TearDown() {
+ mock_bus_->ShutdownAndBlock();
+ }
+
+ // Called when a signal is received.
+ void OnSignalReceived(dbus::Signal* signal) {
+ ASSERT_EQ(kReturnSignalInterface, signal->GetInterface());
+ ASSERT_EQ(kReturnSignalName, signal->GetMember());
+
+ std::string source_url;
+ std::string proxy_info;
+ std::string error_message;
+
+ // The signal should contain three strings.
+ dbus::MessageReader reader(signal);
+ ASSERT_TRUE(reader.PopString(&source_url));
+ ASSERT_TRUE(reader.PopString(&proxy_info));
+ ASSERT_TRUE(reader.PopString(&error_message));
+
+ // Check the signal conetnts.
+ EXPECT_EQ(kSourceURL, source_url);
+ EXPECT_EQ(kReturnProxyInfo, proxy_info);
+ EXPECT_EQ(kReturnEmptyErrorMessage, error_message);
+
+ // Mark that the signal is received successfully.
+ signal_received_successfully_ = true;
+ }
+
+ // Called when connected to a signal.
+ void OnConnectedToSignal(const std::string& signal_interface,
+ const std::string& signal_name,
+ bool success){
+ ASSERT_EQ(kReturnSignalInterface, signal_interface);
+ ASSERT_EQ(kReturnSignalName, signal_name);
+ ASSERT_TRUE(success);
+ }
+
+ protected:
+ bool signal_received_successfully_;
+ MockProxyResolver* mock_resolver_;
+ scoped_refptr<dbus::MockBus> mock_bus_;
+ scoped_refptr<dbus::MockExportedObject> mock_exported_object_;
+ scoped_refptr<dbus::MockObjectProxy> mock_object_proxy_;
+ scoped_refptr<ProxyResolutionServiceProvider> proxy_resolution_service_;
+ dbus::ExportedObject::MethodCallCallback resolve_network_proxy_;
+ dbus::ObjectProxy::SignalCallback on_signal_callback_;
+
+ private:
+ // Behaves as |mock_exported_object_|'s ExportMethod().
+ void MockExportMethod(
+ const std::string& interface_name,
+ const std::string& method_name,
+ dbus::ExportedObject::MethodCallCallback method_callback,
+ dbus::ExportedObject::OnExportedCallback on_exported_callback) {
+ if (interface_name == kLibCrosServiceInterface,
+ method_name == kResolveNetworkProxy) {
+ // Tell the call back that the method is exported successfully.
+ on_exported_callback.Run(interface_name, method_name, true);
+ // Capture the callback, so we can run this at a later time.
+ resolve_network_proxy_ = method_callback;
+ return;
+ }
+
+ LOG(ERROR) << "Unexpected method exported: " << interface_name
+ << method_name;
+ }
+
+ // Behaves as |mock_exported_object_|'s SendSignal().
+ void MockSendSignal(dbus::Signal* signal) {
+ ASSERT_EQ(kReturnSignalInterface, signal->GetInterface());
+ ASSERT_EQ(kReturnSignalName, signal->GetMember());
+
+ // Run the callback captured in MockConnectToSignal(). This will call
+ // OnSignalReceived().
+ on_signal_callback_.Run(signal);
+ }
+
+ // Behaves as |mock_resolver_|'s ResolveProxy().
+ void MockResolveProxy(const std::string& source_url,
+ const std::string& signal_interface,
+ const std::string& signal_name,
+ scoped_refptr<dbus::ExportedObject> exported_object) {
+ if (source_url == kSourceURL) {
+ dbus::Signal signal(signal_interface,
+ signal_name);
+ dbus::MessageWriter writer(&signal);
+ writer.AppendString(kSourceURL);
+ writer.AppendString(kReturnProxyInfo);
+ writer.AppendString(kReturnEmptyErrorMessage);
+ // Send the signal back to the requested signal interface and the
+ // signal name.
+ exported_object->SendSignal(&signal);
+ return;
+ }
+
+ LOG(ERROR) << "Unexpected source URL: " << source_url;
+ }
+
+ // Creates a response for |mock_object_proxy_|.
+ dbus::Response* CreateResponse(
+ dbus::MethodCall* method_call,
+ Unused) {
+ if (method_call->GetInterface() ==
+ kLibCrosServiceInterface &&
+ method_call->GetMember() == kResolveNetworkProxy) {
+ // Set the serial number to non-zero, so
+ // dbus_message_new_method_return() won't emit a warning.
+ method_call->SetSerial(1);
+ // Run the callback captured in MockExportMethod(). This will send
+ // a signal, which will be received by |on_signal_callback_|.
+ dbus::Response* response = resolve_network_proxy_.Run(method_call);
+ return response;
+ }
+
+ LOG(ERROR) << "Unexpected method call: " << method_call->ToString();
+ return NULL;
+ }
+
+ // Behaves as |mock_object_proxy_|'s ConnectToSignal().
+ void MockConnectToSignal(
+ const std::string& interface_name,
+ const std::string& signal_name,
+ dbus::ObjectProxy::SignalCallback signal_callback,
+ dbus::ObjectProxy::OnConnectedCallback connected_callback) {
+ // Tell the callback that the object proxy is connected to the signal.
+ connected_callback.Run(interface_name, signal_name, true);
+ // Capture the callback, so we can run this at a later time.
+ on_signal_callback_ = signal_callback;
+ }
+};
+
+TEST_F(ProxyResolutionServiceProviderTest, ResolveProxy) {
+ // Connect to the signal that will be sent to kReturnSignalInterface and
+ // kReturnSignalName. ResolveNetworkProxy() will send the result as a
+ // signal. OnSignalReceived() will be called upon the delivery.
+ mock_object_proxy_->ConnectToSignal(
+ kReturnSignalInterface,
+ kReturnSignalName,
+ base::Bind(&ProxyResolutionServiceProviderTest::OnSignalReceived,
+ base::Unretained(this)),
+ base::Bind(&ProxyResolutionServiceProviderTest::OnConnectedToSignal,
+ base::Unretained(this)));
+ // The signal is not yet received.
+ ASSERT_FALSE(signal_received_successfully_);
+
+ // Create a method call to resolve proxy config for kSourceURL.
+ dbus::MethodCall method_call(kLibCrosServiceInterface,
+ kResolveNetworkProxy);
+ dbus::MessageWriter writer(&method_call);
+ writer.AppendString(kSourceURL);
+ writer.AppendString(kReturnSignalInterface);
+ writer.AppendString(kReturnSignalName);
+
+ // Call the ResolveNetworkProxy method.
+ scoped_ptr<dbus::Response> response(
+ mock_object_proxy_->CallMethodAndBlock(
+ &method_call,
+ dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
+
+ // An empty response should be returned.
+ ASSERT_TRUE(response.get());
+ dbus::MessageReader reader(response.get());
+ ASSERT_FALSE(reader.HasMoreData());
+
+ // Confirm that the signal is received successfully.
+ // The contents of the signal are checked in OnSignalReceived().
+ ASSERT_TRUE(signal_received_successfully_);
+}
+
+} // namespace chromeos