diff --git a/chrome/browser/policy/device_management_backend_impl.cc b/chrome/browser/policy/device_management_backend_impl.cc
new file mode 100644
index 0000000000000000000000000000000000000000..c0e9b0722c28a3d36b50e25cb370772b3846cf70
--- /dev/null
+++ b/chrome/browser/policy/device_management_backend_impl.cc
@@ -0,0 +1,415 @@
+// 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.
+
+#include "chrome/browser/policy/device_management_backend_impl.h"
+
+#include <utility>
+#include <vector>
+
+#include "base/stl_util-inl.h"
+#include "base/stringprintf.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/common/net/url_request_context_getter.h"
+#include "net/base/cookie_monster.h"
+#include "net/base/escape.h"
+#include "net/base/host_resolver.h"
+#include "net/base/ssl_config_service_defaults.h"
+#include "net/http/http_auth_handler_factory.h"
+#include "net/http/http_network_layer.h"
+#include "net/proxy/proxy_service.h"
+#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_status.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/io_thread.h"
+#include "chrome/browser/net/chrome_net_log.h"
+#include "chrome/common/chrome_version_info.h"
+
+namespace policy {
+
+namespace {
+
+// Name constants for URL query parameters.
+const char kServiceParamRequest[] = "request";
+const char kServiceParamDeviceType[] = "devicetype";
+const char kServiceParamDeviceID[] = "deviceid";
+const char kServiceParamAgent[] = "agent";
+
+// String constants for the device type and agent we report to the service.
+const char kServiceValueDeviceType[] = "Chrome";
+const char kServiceValueAgent[] =
+    "%s enterprise management client version %s (%s)";
+
+const char kServiceTokenAuthHeader[] = "Authorization: GoogleLogin auth=";
+const char kDMTokenAuthHeader[] = "Authorization: GoogleDMToken token=";
+
+}  // namespace
+
+// Custom request context implementation that allows to override the user agent,
+// amongst others. Using the default request context is not an option since this
+// service may be constructed before the default request context is created
+// (i.e. before the profile has been loaded).
+class DeviceManagementBackendRequestContext : public URLRequestContext {
+ public:
+  explicit DeviceManagementBackendRequestContext(IOThread::Globals* io_globals);
+  virtual ~DeviceManagementBackendRequestContext();
+
+ private:
+  virtual const std::string& GetUserAgent(const GURL& url) const;
+
+  std::string user_agent_;
+};
+
+DeviceManagementBackendRequestContext::DeviceManagementBackendRequestContext(
+    IOThread::Globals* io_globals) {
+  net_log_ = io_globals->net_log.get();
+  host_resolver_ = io_globals->host_resolver.get();
+  proxy_service_ = net::ProxyService::CreateDirect();
+  ssl_config_service_ = net::SSLConfigService::CreateSystemSSLConfigService();
+  http_auth_handler_factory_ =
+      net::HttpAuthHandlerFactory::CreateDefault(host_resolver_);
+  http_transaction_factory_ =
+      net::HttpNetworkLayer::CreateFactory(host_resolver_,
+                                           io_globals->dnsrr_resolver.get(),
+                                           NULL /* ssl_host_info_factory */,
+                                           proxy_service_,
+                                           ssl_config_service_,
+                                           http_auth_handler_factory_,
+                                           NULL /* network_delegate */,
+                                           net_log_);
+  cookie_store_ = new net::CookieMonster(NULL, NULL);
+  user_agent_ = DeviceManagementBackendImpl::GetAgentString();
+  accept_language_ = "*";
+  accept_charset_ = "*";
+}
+
+DeviceManagementBackendRequestContext
+    ::~DeviceManagementBackendRequestContext() {
+  delete http_transaction_factory_;
+  delete http_auth_handler_factory_;
+}
+
+const std::string&
+DeviceManagementBackendRequestContext::GetUserAgent(const GURL& url) const {
+  return user_agent_;
+}
+
+// Request context holder.
+class DeviceManagementBackendRequestContextGetter
+    : public URLRequestContextGetter {
+ public:
+  DeviceManagementBackendRequestContextGetter()
+      : io_thread_(g_browser_process->io_thread()) {}
+
+  // URLRequestContextGetter overrides.
+  virtual URLRequestContext* GetURLRequestContext();
+  virtual scoped_refptr<base::MessageLoopProxy> GetIOMessageLoopProxy() const;
+
+ private:
+  scoped_refptr<URLRequestContext> context_;
+  IOThread* io_thread_;
+};
+
+
+URLRequestContext*
+DeviceManagementBackendRequestContextGetter::GetURLRequestContext() {
+  if (!context_)
+    context_ = new DeviceManagementBackendRequestContext(io_thread_->globals());
+
+  return context_.get();
+}
+
+scoped_refptr<base::MessageLoopProxy>
+DeviceManagementBackendRequestContextGetter::GetIOMessageLoopProxy() const {
+  return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
+}
+
+// Helper class for URL query parameter encoding/decoding.
+class URLQueryParameters {
+ public:
+  URLQueryParameters() {}
+
+  // Add a query parameter.
+  void Put(const std::string& name, const std::string& value);
+
+  // Produce the query string, taking care of properly encoding and assembling
+  // the names and values.
+  std::string Encode();
+
+ private:
+  typedef std::vector<std::pair<std::string, std::string> > ParameterMap;
+  ParameterMap params_;
+
+  DISALLOW_COPY_AND_ASSIGN(URLQueryParameters);
+};
+
+void URLQueryParameters::Put(const std::string& name,
+                             const std::string& value) {
+  params_.push_back(std::make_pair(name, value));
+}
+
+std::string URLQueryParameters::Encode() {
+  std::string result;
+  for (ParameterMap::const_iterator entry(params_.begin());
+       entry != params_.end();
+       ++entry) {
+    if (entry != params_.begin())
+      result += '&';
+    result += EscapeUrlEncodedData(entry->first);
+    result += '=';
+    result += EscapeUrlEncodedData(entry->second);
+  }
+  return result;
+}
+
+// Wraps common response parsing and handling functionality.
+class ResponseHandler {
+ public:
+  ResponseHandler() {}
+  virtual ~ResponseHandler() {}
+
+  // Handles the URL request response.
+  void HandleResponse(const URLRequestStatus& status,
+                      int response_code,
+                      const ResponseCookies& cookies,
+                      const std::string& data);
+
+  // Forwards the given error to the delegate.
+  virtual void OnError(DeviceManagementBackend::ErrorCode error) = 0;
+
+ private:
+  // Implemented by subclasses to handle the decoded response.
+  virtual void ProcessResponse(
+      const em::DeviceManagementResponse& response) = 0;
+};
+
+void ResponseHandler::HandleResponse(const URLRequestStatus& status,
+                                     int response_code,
+                                     const ResponseCookies& cookies,
+                                     const std::string& data) {
+  if (status.status() != URLRequestStatus::SUCCESS) {
+    OnError(DeviceManagementBackend::kErrorRequestFailed);
+    return;
+  }
+
+  if (response_code != 200) {
+    OnError(DeviceManagementBackend::kErrorHttpStatus);
+    return;
+  }
+
+  em::DeviceManagementResponse response;
+  if (!response.ParseFromString(data)) {
+    OnError(DeviceManagementBackend::kErrorResponseDecoding);
+    return;
+  }
+
+  // Check service error code.
+  switch (response.error()) {
+    case em::DeviceManagementResponse::SUCCESS:
+      break;
+    case em::DeviceManagementResponse::DEVICE_MANAGEMENT_NOT_SUPPORTED:
+      OnError(DeviceManagementBackend::kErrorServiceManagementNotSupported);
+      return;
+    case em::DeviceManagementResponse::DEVICE_NOT_FOUND:
+      OnError(DeviceManagementBackend::kErrorServiceDeviceNotFound);
+      return;
+    case em::DeviceManagementResponse::DEVICE_MANAGEMENT_TOKEN_INVALID:
+      OnError(DeviceManagementBackend::kErrorServiceManagementTokenInvalid);
+      return;
+    case em::DeviceManagementResponse::ACTIVATION_PENDING:
+      OnError(DeviceManagementBackend::kErrorServiceActivationPending);
+      return;
+    default:
+      // This should be caught by the protobuf decoder.
+      NOTREACHED();
+      OnError(DeviceManagementBackend::kErrorResponseDecoding);
+      return;
+  }
+
+  ProcessResponse(response);
+}
+
+// Handles device registration responses.
+class RegisterResponseHandler : public ResponseHandler {
+ public:
+  RegisterResponseHandler(
+      DeviceManagementBackend::DeviceRegisterResponseDelegate* delegate)
+      : delegate_(delegate) {}
+
+ private:
+  // ResponseHandler overrides.
+  virtual void OnError(DeviceManagementBackend::ErrorCode error) {
+    delegate_->OnError(error);
+  }
+  virtual void ProcessResponse(const em::DeviceManagementResponse& response) {
+    delegate_->HandleRegisterResponse(response.register_response());
+  }
+
+  DeviceManagementBackend::DeviceRegisterResponseDelegate* delegate_;
+};
+
+// Handles device unregister responses.
+class UnregisterResponseHandler : public ResponseHandler {
+ public:
+  UnregisterResponseHandler(
+      DeviceManagementBackend::DeviceUnregisterResponseDelegate* delegate)
+      : delegate_(delegate) {}
+
+ private:
+  // ResponseHandler overrides.
+  virtual void OnError(DeviceManagementBackend::ErrorCode error) {
+    delegate_->OnError(error);
+  }
+  virtual void ProcessResponse(const em::DeviceManagementResponse& response) {
+    delegate_->HandleUnregisterResponse(response.unregister_response());
+  }
+
+  DeviceManagementBackend::DeviceUnregisterResponseDelegate* delegate_;
+};
+
+// Handles device policy responses.
+class PolicyResponseHandler : public ResponseHandler {
+ public:
+  PolicyResponseHandler(
+      DeviceManagementBackend::DevicePolicyResponseDelegate* delegate)
+      : delegate_(delegate) {}
+
+ private:
+  // ResponseHandler overrides.
+  virtual void OnError(DeviceManagementBackend::ErrorCode error) {
+    delegate_->OnError(error);
+  }
+  virtual void ProcessResponse(const em::DeviceManagementResponse& response) {
+    delegate_->HandlePolicyResponse(response.policy_response());
+  }
+
+  DeviceManagementBackend::DevicePolicyResponseDelegate* delegate_;
+};
+
+DeviceManagementBackendImpl::DeviceManagementBackendImpl(
+    const std::string& server_url)
+    : server_url_(server_url),
+      request_context_getter_(
+          new DeviceManagementBackendRequestContextGetter()) {
+}
+
+DeviceManagementBackendImpl::~DeviceManagementBackendImpl() {
+  // Cancel all pending requests.
+  STLDeleteContainerPairPointers(response_handlers_.begin(),
+                                 response_handlers_.end());
+}
+
+void DeviceManagementBackendImpl::ProcessRegisterRequest(
+    const std::string& auth_token,
+    const std::string& device_id,
+    const em::DeviceRegisterRequest& request,
+    DeviceRegisterResponseDelegate* delegate) {
+  em::DeviceManagementRequest request_wrapper;
+  request_wrapper.mutable_register_request()->CopyFrom(request);
+
+  URLQueryParameters params;
+  PutCommonQueryParameters(&params);
+  params.Put(kServiceParamRequest, "register");
+  params.Put(kServiceParamDeviceID, device_id);
+
+  CreateFetcher(request_wrapper,
+                new RegisterResponseHandler(delegate),
+                params.Encode(),
+                kServiceTokenAuthHeader + auth_token);
+}
+
+void DeviceManagementBackendImpl::ProcessUnregisterRequest(
+    const std::string& device_management_token,
+    const em::DeviceUnregisterRequest& request,
+    DeviceUnregisterResponseDelegate* delegate) {
+  em::DeviceManagementRequest request_wrapper;
+  request_wrapper.mutable_unregister_request()->CopyFrom(request);
+
+  URLQueryParameters params;
+  PutCommonQueryParameters(&params);
+  params.Put(kServiceParamRequest, "unregister");
+
+  CreateFetcher(request_wrapper,
+                new UnregisterResponseHandler(delegate),
+                params.Encode(),
+                kDMTokenAuthHeader + device_management_token);
+}
+
+void DeviceManagementBackendImpl::ProcessPolicyRequest(
+    const std::string& device_management_token,
+    const em::DevicePolicyRequest& request,
+    DevicePolicyResponseDelegate* delegate) {
+  em::DeviceManagementRequest request_wrapper;
+  request_wrapper.mutable_policy_request()->CopyFrom(request);
+
+  URLQueryParameters params;
+  PutCommonQueryParameters(&params);
+  params.Put(kServiceParamRequest, "policy");
+
+  CreateFetcher(request_wrapper,
+                new PolicyResponseHandler(delegate),
+                params.Encode(),
+                kDMTokenAuthHeader + device_management_token);
+}
+
+// static
+std::string DeviceManagementBackendImpl::GetAgentString() {
+  chrome::VersionInfo version_info;
+  return base::StringPrintf(kServiceValueAgent,
+                            version_info.Name().c_str(),
+                            version_info.Version().c_str(),
+                            version_info.LastChange().c_str());
+}
+
+void DeviceManagementBackendImpl::OnURLFetchComplete(
+    const URLFetcher* source,
+    const GURL& url,
+    const URLRequestStatus& status,
+    int response_code,
+    const ResponseCookies& cookies,
+    const std::string& data) {
+  ResponseHandlerMap::iterator entry(response_handlers_.find(source));
+  if (entry != response_handlers_.end()) {
+    ResponseHandler* handler = entry->second;
+    handler->HandleResponse(status, response_code, cookies, data);
+    response_handlers_.erase(entry);
+    delete handler;
+  } else {
+    NOTREACHED() << "Callback from foreign URL fetcher";
+  }
+  delete source;
+}
+
+void DeviceManagementBackendImpl::CreateFetcher(
+    const em::DeviceManagementRequest& request,
+    ResponseHandler* handler,
+    const std::string& query_params,
+    const std::string& extra_headers) {
+  scoped_ptr<ResponseHandler> handler_ptr(handler);
+
+  // Construct the payload.
+  std::string payload;
+  if (!request.SerializeToString(&payload)) {
+    handler->OnError(DeviceManagementBackend::kErrorRequestInvalid);
+    return;
+  }
+
+  // Instantiate the fetcher.
+  GURL url(server_url_ + '?' + query_params);
+  URLFetcher* fetcher = URLFetcher::Create(0, url, URLFetcher::POST, this);
+  fetcher->set_request_context(request_context_getter_.get());
+  fetcher->set_upload_data("application/octet-stream", payload);
+  fetcher->set_extra_request_headers(extra_headers);
+  response_handlers_[fetcher] = handler_ptr.release();
+
+  // Start the request. The fetcher will call OnURLFetchComplete when done.
+  fetcher->Start();
+}
+
+void DeviceManagementBackendImpl::PutCommonQueryParameters(
+    URLQueryParameters* params) {
+  params->Put(kServiceParamDeviceType, kServiceValueDeviceType);
+  params->Put(kServiceParamAgent, GetAgentString());
+}
+
+}  // namespace policy
diff --git a/chrome/browser/policy/device_management_backend_impl.h b/chrome/browser/policy/device_management_backend_impl.h
new file mode 100644
index 0000000000000000000000000000000000000000..648ca5512df2d02d8efc254d2bd1f0fa947929e6
--- /dev/null
+++ b/chrome/browser/policy/device_management_backend_impl.h
@@ -0,0 +1,84 @@
+// 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_POLICY_DEVICE_MANAGEMENT_BACKEND_IMPL_H_
+#define CHROME_BROWSER_POLICY_DEVICE_MANAGEMENT_BACKEND_IMPL_H_
+#pragma once
+
+#include <map>
+#include <string>
+
+#include "chrome/browser/policy/device_management_backend.h"
+#include "chrome/common/net/url_fetcher.h"
+#include "googleurl/src/gurl.h"
+
+class URLRequestContextGetter;
+
+namespace policy {
+
+class ResponseHandler;
+class URLQueryParameters;
+
+// Device management backend implementation. This implementation makes HTTP
+// requests to the policy server through the net layer.
+class DeviceManagementBackendImpl : public DeviceManagementBackend,
+                                    public URLFetcher::Delegate {
+ public:
+  explicit DeviceManagementBackendImpl(const std::string& server_url);
+  virtual ~DeviceManagementBackendImpl();
+
+  // GoogleAppsPolicyService overrides:
+  virtual void ProcessRegisterRequest(
+      const std::string& auth_token,
+      const std::string& device_id,
+      const em::DeviceRegisterRequest& request,
+      DeviceRegisterResponseDelegate* response_delegate);
+  virtual void ProcessUnregisterRequest(
+      const std::string& device_management_token,
+      const em::DeviceUnregisterRequest& request,
+      DeviceUnregisterResponseDelegate* response_delegate);
+  virtual void ProcessPolicyRequest(
+      const std::string& device_management_token,
+      const em::DevicePolicyRequest& request,
+      DevicePolicyResponseDelegate* response_delegate);
+
+  // Get the agent string (used for HTTP user agent and as agent passed to the
+  // server).
+  static std::string GetAgentString();
+
+ private:
+  typedef std::map<const URLFetcher*, ResponseHandler*> ResponseHandlerMap;
+
+  // URLFetcher::Delegate override.
+  virtual void OnURLFetchComplete(const URLFetcher* source,
+                                  const GURL& url,
+                                  const URLRequestStatus& status,
+                                  int response_code,
+                                  const ResponseCookies& cookies,
+                                  const std::string& data);
+
+  // Create a URLFetcher for a given request message and response handler.
+  void CreateFetcher(const em::DeviceManagementRequest& request,
+                     ResponseHandler* handler,
+                     const std::string& query_params,
+                     const std::string& extra_headers);
+
+  // Fill in the common query parameters.
+  void PutCommonQueryParameters(URLQueryParameters* params);
+
+  // Server at which to contact the service.
+  const std::string server_url_;
+
+  // The request context we use.
+  scoped_refptr<URLRequestContextGetter> request_context_getter_;
+
+  // Keeps track of all in-flight requests an their response handlers.
+  ResponseHandlerMap response_handlers_;
+
+  DISALLOW_COPY_AND_ASSIGN(DeviceManagementBackendImpl);
+};
+
+}  // namespace policy
+
+#endif  // CHROME_BROWSER_POLICY_DEVICE_MANAGEMENT_BACKEND_IMPL_H_
diff --git a/chrome/browser/policy/device_management_backend_impl_browsertest.cc b/chrome/browser/policy/device_management_backend_impl_browsertest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..43df7be90d8e67201f0bf0a648eb92260a71b9ad
--- /dev/null
+++ b/chrome/browser/policy/device_management_backend_impl_browsertest.cc
@@ -0,0 +1,141 @@
+// 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.
+
+#include "chrome/browser/policy/device_management_backend_impl.h"
+
+#include "base/message_loop.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/policy/device_management_backend_mock.h"
+#include "chrome/test/in_process_browser_test.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_test_job.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using testing::_;
+using testing::DoAll;
+using testing::Invoke;
+using testing::InvokeWithoutArgs;
+
+namespace policy {
+
+namespace {
+
+const char kServiceUrl[] = "http://example.com/service";
+
+// Binary representation of successful register response containing a token.
+const char kServiceResponseRegister[] =
+    "\x08\x00\x1a\x22\x0a\x20\x64\x64\x32\x63\x38\x63\x33\x65\x64\x61"
+    "\x63\x63\x34\x61\x33\x32\x38\x31\x66\x33\x38\x62\x36\x35\x31\x31"
+    "\x36\x64\x61\x62\x66\x63";
+// Contains a single policy setting, namely HomepageIsNewTabPage: false.
+const char kServiceResponsePolicy[] =
+    "\x08\x00\x2a\x2a\x0a\x28\x0a\x06\x70\x6f\x6c\x69\x63\x79\x12\x1e"
+    "\x0a\x1c\x0a\x14\x48\x6f\x6d\x65\x70\x61\x67\x65\x49\x73\x4e\x65"
+    "\x77\x54\x61\x62\x50\x61\x67\x65\x12\x04\x08\x01\x10\x00";
+// Successful unregister response.
+const char kServiceResponseUnregister[] =
+    "\x08\x00\x22\x00";
+
+#define PROTO_STRING(name) (std::string(name, arraysize(name) - 1))
+
+}  // namespace
+
+// Interceptor implementation that returns test data back to the service.
+class CannedResponseInterceptor : public URLRequest::Interceptor {
+ public:
+  CannedResponseInterceptor(const GURL& service_url,
+                            const std::string& response_data)
+      : service_url_(service_url),
+        response_data_(response_data) {
+    URLRequest::RegisterRequestInterceptor(this);
+  }
+
+  virtual ~CannedResponseInterceptor() {
+    URLRequest::UnregisterRequestInterceptor(this);
+  }
+
+ private:
+  // URLRequest::Interceptor overrides.
+  virtual URLRequestJob* MaybeIntercept(URLRequest* request) {
+    if (request->url().GetOrigin() == service_url_.GetOrigin() &&
+        request->url().path() == service_url_.path()) {
+      return new URLRequestTestJob(request,
+                                   URLRequestTestJob::test_headers(),
+                                   response_data_,
+                                   true);
+    }
+
+    return NULL;
+  }
+
+  const GURL service_url_;
+  const std::string response_data_;
+};
+
+class DeviceManagementBackendImplIntegrationTest : public InProcessBrowserTest {
+ public:
+  void CaptureToken(const em::DeviceRegisterResponse& response) {
+    token_ = response.device_management_token();
+  }
+
+ protected:
+  DeviceManagementBackendImplIntegrationTest() {
+    URLFetcher::enable_interception_for_tests(true);
+  }
+
+  std::string token_;
+};
+
+static void QuitMessageLoop() {
+  MessageLoop::current()->Quit();
+}
+
+IN_PROC_BROWSER_TEST_F(DeviceManagementBackendImplIntegrationTest,
+                       RegisterAndFetchPolicy) {
+  DeviceManagementBackendImpl service(kServiceUrl);
+
+  {
+    CannedResponseInterceptor interceptor(
+        GURL(kServiceUrl), PROTO_STRING(kServiceResponseRegister));
+    DeviceRegisterResponseDelegateMock delegate;
+    EXPECT_CALL(delegate, HandleRegisterResponse(_))
+        .WillOnce(DoAll(Invoke(this, &DeviceManagementBackendImplIntegrationTest
+                                          ::CaptureToken),
+                        InvokeWithoutArgs(QuitMessageLoop)));
+    em::DeviceRegisterRequest request;
+    service.ProcessRegisterRequest("token", "device id", request, &delegate);
+    MessageLoop::current()->Run();
+  }
+
+  {
+    CannedResponseInterceptor interceptor(
+        GURL(kServiceUrl), PROTO_STRING(kServiceResponsePolicy));
+    DevicePolicyResponseDelegateMock delegate;
+    EXPECT_CALL(delegate, HandlePolicyResponse(_))
+        .WillOnce(InvokeWithoutArgs(QuitMessageLoop));
+    em::DevicePolicyRequest request;
+    request.set_policy_scope("chrome");
+    em::DevicePolicySettingRequest* setting_request =
+        request.add_setting_request();
+    setting_request->set_key("policy");
+    service.ProcessPolicyRequest(token_, request, &delegate);
+
+    MessageLoop::current()->Run();
+  }
+
+  {
+    CannedResponseInterceptor interceptor(
+        GURL(kServiceUrl), PROTO_STRING(kServiceResponseUnregister));
+    DeviceUnregisterResponseDelegateMock delegate;
+    EXPECT_CALL(delegate, HandleUnregisterResponse(_))
+        .WillOnce(InvokeWithoutArgs(QuitMessageLoop));
+    em::DeviceUnregisterRequest request;
+    service.ProcessUnregisterRequest(token_, request, &delegate);
+
+    MessageLoop::current()->Run();
+  }
+}
+
+}  // namespace policy
diff --git a/chrome/browser/policy/device_management_backend_impl_unittest.cc b/chrome/browser/policy/device_management_backend_impl_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..1e93f3a6ef6e6356d7ee025fd5055b84f54a8319
--- /dev/null
+++ b/chrome/browser/policy/device_management_backend_impl_unittest.cc
@@ -0,0 +1,375 @@
+// 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.
+
+#include "chrome/browser/policy/device_management_backend_impl.h"
+
+#include "base/message_loop.h"
+#include "base/string_split.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/policy/device_management_backend_mock.h"
+#include "chrome/common/net/test_url_fetcher_factory.h"
+#include "net/base/escape.h"
+#include "net/url_request/url_request_status.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using testing::_;
+
+namespace policy {
+
+namespace {
+
+const char kServiceURL[] = "https://example.com/management_service";
+
+// Encoded error response messages for testing the error code paths.
+const char kResponseEmpty[] = "\x08\x00";
+const char kResponseErrorManagementNotSupported[] = "\x08\x01";
+const char kResponseErrorDeviceNotFound[] = "\x08\x02";
+const char kResponseErrorManagementTokenInvalid[] = "\x08\x03";
+const char kResponseErrorActivationPending[] = "\x08\x04";
+
+#define PROTO_STRING(name) (std::string(name, arraysize(name) - 1))
+
+}  // namespace
+
+// Unit tests for the google apps policy backend. The pattern here is each test
+// case triggeres a request and installs a mock delegate. The test will run and
+// the default action installed on the test delegate will quit the loop.
+template<typename TESTBASE>
+class DeviceManagementBackendImplTestBase : public TESTBASE {
+ protected:
+  DeviceManagementBackendImplTestBase()
+      : io_thread_(BrowserThread::IO, &loop_),
+        service_(kServiceURL) {}
+
+  virtual void SetUp() {
+    URLFetcher::set_factory(&factory_);
+  }
+
+  virtual void TearDown() {
+    URLFetcher::set_factory(NULL);
+    loop_.RunAllPending();
+  }
+
+  MessageLoopForUI loop_;
+  BrowserThread io_thread_;
+  TestURLFetcherFactory factory_;
+  DeviceManagementBackendImpl service_;
+};
+
+struct FailedRequestParams {
+  FailedRequestParams(DeviceManagementBackend::ErrorCode expected_error,
+                      URLRequestStatus::Status request_status,
+                      int http_status,
+                      const std::string& response)
+      : expected_error_(expected_error),
+        request_status_(request_status, 0),
+        http_status_(http_status),
+        response_(response) {}
+
+  DeviceManagementBackend::ErrorCode expected_error_;
+  URLRequestStatus request_status_;
+  int http_status_;
+  std::string response_;
+};
+
+// A parameterized test case for erroneous response situations, they're mostly
+// the same for all kinds of requests.
+class DeviceManagementBackendImplFailedRequestTest
+    : public DeviceManagementBackendImplTestBase<
+          testing::TestWithParam<FailedRequestParams> > {
+};
+
+TEST_P(DeviceManagementBackendImplFailedRequestTest, RegisterRequest) {
+  DeviceRegisterResponseDelegateMock mock;
+  EXPECT_CALL(mock, OnError(GetParam().expected_error_));
+  em::DeviceRegisterRequest request;
+  service_.ProcessRegisterRequest("token", "device id", request, &mock);
+  TestURLFetcher* fetcher = factory_.GetFetcherByID(0);
+  ASSERT_TRUE(fetcher);
+
+  fetcher->delegate()->OnURLFetchComplete(fetcher,
+                                          GURL(kServiceURL),
+                                          GetParam().request_status_,
+                                          GetParam().http_status_,
+                                          ResponseCookies(),
+                                          GetParam().response_);
+}
+
+TEST_P(DeviceManagementBackendImplFailedRequestTest, UnregisterRequest) {
+  DeviceUnregisterResponseDelegateMock mock;
+  EXPECT_CALL(mock, OnError(GetParam().expected_error_));
+  em::DeviceUnregisterRequest request;
+  service_.ProcessUnregisterRequest("token", request, &mock);
+  TestURLFetcher* fetcher = factory_.GetFetcherByID(0);
+  ASSERT_TRUE(fetcher);
+
+  fetcher->delegate()->OnURLFetchComplete(fetcher,
+                                          GURL(kServiceURL),
+                                          GetParam().request_status_,
+                                          GetParam().http_status_,
+                                          ResponseCookies(),
+                                          GetParam().response_);
+}
+
+TEST_P(DeviceManagementBackendImplFailedRequestTest, PolicyRequest) {
+  DevicePolicyResponseDelegateMock mock;
+  EXPECT_CALL(mock, OnError(GetParam().expected_error_));
+  em::DevicePolicyRequest request;
+  request.set_policy_scope("Chrome");
+  em::DevicePolicySettingRequest* setting_request =
+      request.add_setting_request();
+  setting_request->set_key("policy");
+  service_.ProcessPolicyRequest("token", request, &mock);
+  TestURLFetcher* fetcher = factory_.GetFetcherByID(0);
+  ASSERT_TRUE(fetcher);
+
+  fetcher->delegate()->OnURLFetchComplete(fetcher,
+                                          GURL(kServiceURL),
+                                          GetParam().request_status_,
+                                          GetParam().http_status_,
+                                          ResponseCookies(),
+                                          GetParam().response_);
+}
+
+INSTANTIATE_TEST_CASE_P(
+    DeviceManagementBackendImplFailedRequestTestInstance,
+    DeviceManagementBackendImplFailedRequestTest,
+    testing::Values(
+        FailedRequestParams(
+            DeviceManagementBackend::kErrorRequestFailed,
+            URLRequestStatus::FAILED,
+            200,
+            PROTO_STRING(kResponseEmpty)),
+        FailedRequestParams(
+            DeviceManagementBackend::kErrorHttpStatus,
+            URLRequestStatus::SUCCESS,
+            500,
+            PROTO_STRING(kResponseEmpty)),
+        FailedRequestParams(
+            DeviceManagementBackend::kErrorResponseDecoding,
+            URLRequestStatus::SUCCESS,
+            200,
+            PROTO_STRING("Not a protobuf.")),
+        FailedRequestParams(
+            DeviceManagementBackend::kErrorServiceManagementNotSupported,
+            URLRequestStatus::SUCCESS,
+            200,
+            PROTO_STRING(kResponseErrorManagementNotSupported)),
+        FailedRequestParams(
+            DeviceManagementBackend::kErrorServiceDeviceNotFound,
+            URLRequestStatus::SUCCESS,
+            200,
+            PROTO_STRING(kResponseErrorDeviceNotFound)),
+        FailedRequestParams(
+            DeviceManagementBackend::kErrorServiceManagementTokenInvalid,
+            URLRequestStatus::SUCCESS,
+            200,
+            PROTO_STRING(kResponseErrorManagementTokenInvalid)),
+        FailedRequestParams(
+            DeviceManagementBackend::kErrorServiceActivationPending,
+            URLRequestStatus::SUCCESS,
+            200,
+            PROTO_STRING(kResponseErrorActivationPending))));
+
+class DeviceManagementBackendImplTest
+    : public DeviceManagementBackendImplTestBase<testing::Test> {
+};
+
+MATCHER_P(MessageEquals, reference, "") {
+  std::string reference_data;
+  std::string arg_data;
+  return arg.SerializeToString(&arg_data) &&
+         reference.SerializeToString(&reference_data) &&
+         arg_data == reference_data;
+}
+
+// Simple query parameter parser for testing.
+class QueryParams {
+ public:
+  explicit QueryParams(const std::string& query) {
+    base::SplitStringIntoKeyValuePairs(query, '=', '&', &params_);
+  }
+
+  bool Check(const std::string& name, const std::string& expected_value) {
+    bool found = false;
+    for (ParamMap::const_iterator i(params_.begin()); i != params_.end(); ++i) {
+      std::string unescaped_name(
+          UnescapeURLComponent(i->first,
+                               UnescapeRule::NORMAL |
+                               UnescapeRule::SPACES |
+                               UnescapeRule::URL_SPECIAL_CHARS |
+                               UnescapeRule::CONTROL_CHARS |
+                               UnescapeRule::REPLACE_PLUS_WITH_SPACE));
+      if (unescaped_name == name) {
+        if (found)
+          return false;
+        found = true;
+        std::string unescaped_value(
+            UnescapeURLComponent(i->second,
+                                 UnescapeRule::NORMAL |
+                                 UnescapeRule::SPACES |
+                                 UnescapeRule::URL_SPECIAL_CHARS |
+                                 UnescapeRule::CONTROL_CHARS |
+                                 UnescapeRule::REPLACE_PLUS_WITH_SPACE));
+        if (unescaped_value != expected_value)
+          return false;
+      }
+    }
+    return found;
+  }
+
+ private:
+  typedef std::vector<std::pair<std::string, std::string> > ParamMap;
+  ParamMap params_;
+};
+
+TEST_F(DeviceManagementBackendImplTest, RegisterRequest) {
+  DeviceRegisterResponseDelegateMock mock;
+  em::DeviceRegisterResponse expected_response;
+  expected_response.set_device_management_token("mtoken");
+  EXPECT_CALL(mock, HandleRegisterResponse(MessageEquals(expected_response)));
+  em::DeviceRegisterRequest request;
+  service_.ProcessRegisterRequest("token", "device id", request, &mock);
+  TestURLFetcher* fetcher = factory_.GetFetcherByID(0);
+  ASSERT_TRUE(fetcher);
+
+  // Check the data the fetcher received.
+  const GURL& request_url(fetcher->original_url());
+  const GURL service_url(kServiceURL);
+  EXPECT_EQ(service_url.scheme(), request_url.scheme());
+  EXPECT_EQ(service_url.host(), request_url.host());
+  EXPECT_EQ(service_url.port(), request_url.port());
+  EXPECT_EQ(service_url.path(), request_url.path());
+
+  QueryParams query_params(request_url.query());
+  EXPECT_TRUE(query_params.Check("request", "register"));
+
+  em::DeviceManagementRequest expected_request_wrapper;
+  expected_request_wrapper.mutable_register_request()->CopyFrom(request);
+  std::string expected_request_data;
+  ASSERT_TRUE(expected_request_wrapper.SerializeToString(
+      &expected_request_data));
+  EXPECT_EQ(expected_request_data, fetcher->upload_data());
+
+  // Generate the response.
+  std::string response_data;
+  em::DeviceManagementResponse response_wrapper;
+  response_wrapper.set_error(em::DeviceManagementResponse::SUCCESS);
+  response_wrapper.mutable_register_response()->CopyFrom(expected_response);
+  ASSERT_TRUE(response_wrapper.SerializeToString(&response_data));
+  URLRequestStatus status(URLRequestStatus::SUCCESS, 0);
+  fetcher->delegate()->OnURLFetchComplete(fetcher,
+                                          GURL(kServiceURL),
+                                          status,
+                                          200,
+                                          ResponseCookies(),
+                                          response_data);
+}
+
+TEST_F(DeviceManagementBackendImplTest, UnregisterRequest) {
+  DeviceUnregisterResponseDelegateMock mock;
+  em::DeviceUnregisterResponse expected_response;
+  EXPECT_CALL(mock, HandleUnregisterResponse(MessageEquals(expected_response)));
+  em::DeviceUnregisterRequest request;
+  service_.ProcessUnregisterRequest("dmtokenvalue", request, &mock);
+  TestURLFetcher* fetcher = factory_.GetFetcherByID(0);
+  ASSERT_TRUE(fetcher);
+
+  // Check the data the fetcher received.
+  const GURL& request_url(fetcher->original_url());
+  const GURL service_url(kServiceURL);
+  EXPECT_EQ(service_url.scheme(), request_url.scheme());
+  EXPECT_EQ(service_url.host(), request_url.host());
+  EXPECT_EQ(service_url.port(), request_url.port());
+  EXPECT_EQ(service_url.path(), request_url.path());
+
+  QueryParams query_params(request_url.query());
+  EXPECT_TRUE(query_params.Check("request", "unregister"));
+
+  em::DeviceManagementRequest expected_request_wrapper;
+  expected_request_wrapper.mutable_unregister_request()->CopyFrom(request);
+  std::string expected_request_data;
+  ASSERT_TRUE(expected_request_wrapper.SerializeToString(
+      &expected_request_data));
+  EXPECT_EQ(expected_request_data, fetcher->upload_data());
+
+  // Generate the response.
+  std::string response_data;
+  em::DeviceManagementResponse response_wrapper;
+  response_wrapper.set_error(em::DeviceManagementResponse::SUCCESS);
+  response_wrapper.mutable_unregister_response()->CopyFrom(expected_response);
+  ASSERT_TRUE(response_wrapper.SerializeToString(&response_data));
+  URLRequestStatus status(URLRequestStatus::SUCCESS, 0);
+  fetcher->delegate()->OnURLFetchComplete(fetcher,
+                                          GURL(kServiceURL),
+                                          status,
+                                          200,
+                                          ResponseCookies(),
+                                          response_data);
+}
+
+TEST_F(DeviceManagementBackendImplTest, PolicyRequest) {
+  DevicePolicyResponseDelegateMock mock;
+  em::DevicePolicyResponse expected_response;
+  em::DevicePolicySetting* policy_setting = expected_response.add_setting();
+  policy_setting->set_policy_key("policy");
+  policy_setting->set_watermark("fresh");
+  em::GenericSetting* policy_value = policy_setting->mutable_policy_value();
+  em::GenericNamedValue* named_value = policy_value->add_named_value();
+  named_value->set_name("HomepageLocation");
+  named_value->mutable_value()->set_value_type(
+      em::GenericValue::VALUE_TYPE_STRING);
+  named_value->mutable_value()->set_string_value("http://www.chromium.org");
+  named_value = policy_value->add_named_value();
+  named_value->set_name("HomepageIsNewTabPage");
+  named_value->mutable_value()->set_value_type(
+      em::GenericValue::VALUE_TYPE_BOOL);
+  named_value->mutable_value()->set_bool_value(false);
+  EXPECT_CALL(mock, HandlePolicyResponse(MessageEquals(expected_response)));
+
+  em::DevicePolicyRequest request;
+  request.set_policy_scope("chromium");
+  em::DevicePolicySettingRequest* setting_request =
+      request.add_setting_request();
+  setting_request->set_key("policy");
+  setting_request->set_watermark("stale");
+  service_.ProcessPolicyRequest("dmtokenvalue", request, &mock);
+  TestURLFetcher* fetcher = factory_.GetFetcherByID(0);
+  ASSERT_TRUE(fetcher);
+
+  // Check the data the fetcher received.
+  const GURL& request_url(fetcher->original_url());
+  const GURL service_url(kServiceURL);
+  EXPECT_EQ(service_url.scheme(), request_url.scheme());
+  EXPECT_EQ(service_url.host(), request_url.host());
+  EXPECT_EQ(service_url.port(), request_url.port());
+  EXPECT_EQ(service_url.path(), request_url.path());
+
+  QueryParams query_params(request_url.query());
+  EXPECT_TRUE(query_params.Check("request", "policy"));
+
+  em::DeviceManagementRequest expected_request_wrapper;
+  expected_request_wrapper.mutable_policy_request()->CopyFrom(request);
+  std::string expected_request_data;
+  ASSERT_TRUE(expected_request_wrapper.SerializeToString(
+      &expected_request_data));
+  EXPECT_EQ(expected_request_data, fetcher->upload_data());
+
+  // Generate the response.
+  std::string response_data;
+  em::DeviceManagementResponse response_wrapper;
+  response_wrapper.set_error(em::DeviceManagementResponse::SUCCESS);
+  response_wrapper.mutable_policy_response()->CopyFrom(expected_response);
+  ASSERT_TRUE(response_wrapper.SerializeToString(&response_data));
+  URLRequestStatus status(URLRequestStatus::SUCCESS, 0);
+  fetcher->delegate()->OnURLFetchComplete(fetcher,
+                                          GURL(kServiceURL),
+                                          status,
+                                          200,
+                                          ResponseCookies(),
+                                          response_data);
+}
+
+}  // namespace policy
diff --git a/chrome/browser/policy/device_management_backend_mock.h b/chrome/browser/policy/device_management_backend_mock.h
new file mode 100644
index 0000000000000000000000000000000000000000..170fe3a945e144bdda2a54dd07bb35a9ca08d3b2
--- /dev/null
+++ b/chrome/browser/policy/device_management_backend_mock.h
@@ -0,0 +1,38 @@
+// 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_POLICY_DEVICE_MANAGEMENT_BACKEND_MOCK_H_
+#define CHROME_BROWSER_POLICY_DEVICE_MANAGEMENT_BACKEND_MOCK_H_
+
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace policy {
+
+// Mock classes for the various DeviceManagementBackend delegates that allow to
+// capture callbacks using gmock.
+class DeviceRegisterResponseDelegateMock
+    : public DeviceManagementBackend::DeviceRegisterResponseDelegate {
+ public:
+  MOCK_METHOD1(HandleRegisterResponse, void(const em::DeviceRegisterResponse&));
+  MOCK_METHOD1(OnError, void(DeviceManagementBackend::ErrorCode error));
+};
+
+class DeviceUnregisterResponseDelegateMock
+    : public DeviceManagementBackend::DeviceUnregisterResponseDelegate {
+ public:
+  MOCK_METHOD1(HandleUnregisterResponse,
+               void(const em::DeviceUnregisterResponse&));
+  MOCK_METHOD1(OnError, void(DeviceManagementBackend::ErrorCode error));
+};
+
+class DevicePolicyResponseDelegateMock
+    : public DeviceManagementBackend::DevicePolicyResponseDelegate {
+ public:
+  MOCK_METHOD1(HandlePolicyResponse, void(const em::DevicePolicyResponse&));
+  MOCK_METHOD1(OnError, void(DeviceManagementBackend::ErrorCode error));
+};
+
+}  // namespace policy
+
+#endif  // CHROME_BROWSER_POLICY_DEVICE_MANAGEMENT_BACKEND_MOCK_H_
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 15614873c3c6d4dfabb9008ce9a30eb6298c51f1..98afc2d8f2843f888ac688c85f69f9ca629c02be 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -2400,6 +2400,8 @@
         'browser/policy/configuration_policy_provider_win.h',
         'browser/policy/configuration_policy_store_interface.h',
         'browser/policy/device_management_backend.h',
+        'browser/policy/device_management_backend_impl.cc',
+        'browser/policy/device_management_backend_impl.h',
         'browser/policy/device_token_fetcher.cc',
         'browser/policy/device_token_fetcher.h',
         'browser/policy/dummy_configuration_policy_provider.h',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index e8fd4c7cd04395c1f1b2046085e6ca16596d40c3..6b2c4e9da2e53acc8cb1865bbda284677ac2ef71 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1386,6 +1386,8 @@
         'browser/policy/configuration_policy_provider_win_unittest.cc',
         'browser/policy/device_token_fetcher_unittest.cc',
         'browser/policy/file_based_policy_provider_unittest.cc',
+        'browser/policy/device_management_backend_impl_mock.h',
+        'browser/policy/device_management_backend_impl_unittest.cc',
         'browser/policy/managed_prefs_banner_base_unittest.cc',
         'browser/policy/mock_configuration_policy_provider.cc',
         'browser/policy/mock_configuration_policy_provider.h',
@@ -2008,6 +2010,8 @@
         'browser/in_process_webkit/indexed_db_browsertest.cc',
         'browser/net/cookie_policy_browsertest.cc',
         'browser/net/ftp_browsertest.cc',
+        'browser/policy/device_management_backend_impl_mock.h',
+        'browser/policy/device_management_backend_impl_browsertest.cc',
         'browser/popup_blocker_browsertest.cc',
         'browser/printing/print_dialog_cloud_uitest.cc',
         'browser/renderer_host/test/render_process_host_browsertest.cc',